solve merge issues
This commit is contained in:
		
						commit
						61f6e2ac25
					
				
					 26 changed files with 364 additions and 154 deletions
				
			
		
							
								
								
									
										1
									
								
								.idea/misc.xml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/misc.xml
									
										
									
										generated
									
									
									
								
							|  | @ -1,4 +1,3 @@ | ||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project version="4"> | <project version="4"> | ||||||
|   <component name="ExternalStorageConfigurationManager" enabled="true" /> |   <component name="ExternalStorageConfigurationManager" enabled="true" /> | ||||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> |   <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> | ||||||
|  |  | ||||||
|  | @ -123,9 +123,6 @@ dependencies { | ||||||
|     implementation 'com.google.firebase:firebase-firestore-ktx' |     implementation 'com.google.firebase:firebase-firestore-ktx' | ||||||
|     implementation 'com.google.firebase:firebase-perf-ktx' |     implementation 'com.google.firebase:firebase-perf-ktx' | ||||||
|     implementation 'com.google.firebase:firebase-config-ktx' |     implementation 'com.google.firebase:firebase-config-ktx' | ||||||
| 
 |  | ||||||
|     // Colorpicker |  | ||||||
|     implementation 'com.github.skydoves:colorpicker-compose:1.0.2' |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Allow references to generate code | // Allow references to generate code | ||||||
|  |  | ||||||
|  | @ -2,7 +2,6 @@ package be.ugent.sel.studeez.common.composable | ||||||
| 
 | 
 | ||||||
| import androidx.compose.animation.core.animateFloat | import androidx.compose.animation.core.animateFloat | ||||||
| import androidx.compose.animation.core.updateTransition | import androidx.compose.animation.core.updateTransition | ||||||
| import androidx.compose.foundation.border |  | ||||||
| import androidx.compose.foundation.layout.* | import androidx.compose.foundation.layout.* | ||||||
| import androidx.compose.material.FloatingActionButton | import androidx.compose.material.FloatingActionButton | ||||||
| import androidx.compose.material.Icon | import androidx.compose.material.Icon | ||||||
|  |  | ||||||
|  | @ -0,0 +1,22 @@ | ||||||
|  | package be.ugent.sel.studeez.common.composable | ||||||
|  | 
 | ||||||
|  | import androidx.compose.foundation.layout.Box | ||||||
|  | import androidx.compose.foundation.rememberScrollState | ||||||
|  | import androidx.compose.foundation.verticalScroll | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun FormComposable( | ||||||
|  |     title: String, | ||||||
|  |     popUp: () -> Unit, | ||||||
|  |     content: @Composable () -> Unit, | ||||||
|  | ) { | ||||||
|  |     SecondaryScreenTemplate(title = title, popUp = popUp) { | ||||||
|  |         Box( | ||||||
|  |             modifier = Modifier.verticalScroll(rememberScrollState()), | ||||||
|  |         ) { | ||||||
|  |             content() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,39 @@ | ||||||
|  | package be.ugent.sel.studeez.common.composable | ||||||
|  | 
 | ||||||
|  | import androidx.compose.foundation.Image | ||||||
|  | import androidx.compose.foundation.border | ||||||
|  | import androidx.compose.foundation.clickable | ||||||
|  | import androidx.compose.foundation.shape.RoundedCornerShape | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.graphics.Color | ||||||
|  | import androidx.compose.ui.graphics.painter.Painter | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | 
 | ||||||
|  | @Composable | ||||||
|  | fun ImageBackgroundButton( | ||||||
|  |     paint: Painter, | ||||||
|  |     str: String, | ||||||
|  |     background2: Color, | ||||||
|  |     setBackground1: (Color) -> Unit, | ||||||
|  |     setBackground2: (Color) -> Unit | ||||||
|  | ) { | ||||||
|  |     Image( | ||||||
|  |         painter = paint, | ||||||
|  |         str, | ||||||
|  |         modifier = Modifier | ||||||
|  |             .clickable { | ||||||
|  |                 if (background2 == Color.Transparent) { | ||||||
|  |                     setBackground1(Color.LightGray) | ||||||
|  |                     setBackground2(Color.Transparent) | ||||||
|  |                 } else { | ||||||
|  |                     setBackground2(Color.Transparent) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             .border( | ||||||
|  |                 width = 2.dp, | ||||||
|  |                 color = background2, | ||||||
|  |                 shape = RoundedCornerShape(16.dp) | ||||||
|  |             ) | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | @ -31,9 +31,13 @@ import be.ugent.sel.studeez.R.string as AppText | ||||||
| fun SubjectEntry( | fun SubjectEntry( | ||||||
|     subject: Subject, |     subject: Subject, | ||||||
|     onViewSubject: () -> Unit, |     onViewSubject: () -> Unit, | ||||||
|  |     getTaskCount: () -> Flow<Int>, | ||||||
|  |     getCompletedTaskCount: () -> Flow<Int>, | ||||||
|     getStudyTime: () -> Flow<Int>, |     getStudyTime: () -> Flow<Int>, | ||||||
| ) { | ) { | ||||||
|     val studytime by getStudyTime().collectAsState(initial = 0) |     val studytime by getStudyTime().collectAsState(initial = 0) | ||||||
|  |     val taskCount by getTaskCount().collectAsState(initial = 0) | ||||||
|  |     val completedTaskCount by getCompletedTaskCount().collectAsState(initial = 0) | ||||||
|     Card( |     Card( | ||||||
|         modifier = Modifier |         modifier = Modifier | ||||||
|             .fillMaxWidth() |             .fillMaxWidth() | ||||||
|  | @ -80,7 +84,7 @@ fun SubjectEntry( | ||||||
|                                 imageVector = Icons.Default.List, |                                 imageVector = Icons.Default.List, | ||||||
|                                 contentDescription = stringResource(id = AppText.tasks) |                                 contentDescription = stringResource(id = AppText.tasks) | ||||||
|                             ) |                             ) | ||||||
|                             Text(text = "${subject.taskCompletedCount}/${subject.taskCount}") |                             Text(text = "${completedTaskCount}/${taskCount}") | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -104,11 +108,11 @@ fun SubjectEntryPreview() { | ||||||
|         subject = Subject( |         subject = Subject( | ||||||
|             name = "Test Subject", |             name = "Test Subject", | ||||||
|             argb_color = 0xFFFFD200, |             argb_color = 0xFFFFD200, | ||||||
|             taskCount = 5, |  | ||||||
|             taskCompletedCount = 2, |  | ||||||
|         ), |         ), | ||||||
|         onViewSubject = {}, |         onViewSubject = {}, | ||||||
|         getStudyTime = { flowOf() } |         getTaskCount = { flowOf() }, | ||||||
|  |         getCompletedTaskCount = { flowOf() }, | ||||||
|  |         getStudyTime = { flowOf() }, | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -121,6 +125,8 @@ fun OverflowSubjectEntryPreview() { | ||||||
|             argb_color = 0xFFFFD200, |             argb_color = 0xFFFFD200, | ||||||
|         ), |         ), | ||||||
|         onViewSubject = {}, |         onViewSubject = {}, | ||||||
|         getStudyTime = { flowOf() } |         getTaskCount = { flowOf() }, | ||||||
|  |         getCompletedTaskCount = { flowOf() }, | ||||||
|  |         getStudyTime = { flowOf() }, | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  | @ -0,0 +1,10 @@ | ||||||
|  | package be.ugent.sel.studeez.common.ext | ||||||
|  | 
 | ||||||
|  | import androidx.compose.ui.graphics.Color | ||||||
|  | import kotlin.random.Random | ||||||
|  | 
 | ||||||
|  | fun Color.Companion.generateRandomArgb(): Long { | ||||||
|  |     val random = Random | ||||||
|  |     val mask: Long = (0x000000FFL shl random.nextInt(0, 3)).inv() | ||||||
|  |     return random.nextLong(0xFF000000L, 0xFFFFFFFFL) and mask | ||||||
|  | } | ||||||
|  | @ -8,10 +8,6 @@ data class Subject( | ||||||
|     val name: String = "", |     val name: String = "", | ||||||
|     val argb_color: Long = 0, |     val argb_color: Long = 0, | ||||||
|     var archived: Boolean = false, |     var archived: Boolean = false, | ||||||
|     @get:Exclude @set:Exclude |  | ||||||
|     var taskCount: Int = 0, |  | ||||||
|     @get:Exclude @set:Exclude |  | ||||||
|     var taskCompletedCount: Int = 0, |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| object SubjectDocument { | object SubjectDocument { | ||||||
|  |  | ||||||
|  | @ -6,14 +6,13 @@ class FunctionalPomodoroTimer( | ||||||
|     val repeats: Int |     val repeats: Int | ||||||
| ) : FunctionalTimer(studyTime) { | ) : FunctionalTimer(studyTime) { | ||||||
| 
 | 
 | ||||||
|     var breaksRemaining = repeats |     var breaksRemaining = repeats - 1 | ||||||
|     var isInBreak = false |     var isInBreak = false | ||||||
| 
 | 
 | ||||||
|     override fun tick() { |     override fun tick() { | ||||||
|         if (hasEnded()) { |         if (hasEnded()) { | ||||||
|             return |             return | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         if (hasCurrentCountdownEnded()) { |         if (hasCurrentCountdownEnded()) { | ||||||
|             if (isInBreak) { |             if (isInBreak) { | ||||||
|                 breaksRemaining-- |                 breaksRemaining-- | ||||||
|  |  | ||||||
|  | @ -13,8 +13,10 @@ interface SubjectDAO { | ||||||
| 
 | 
 | ||||||
|     fun updateSubject(newSubject: Subject) |     fun updateSubject(newSubject: Subject) | ||||||
| 
 | 
 | ||||||
|     suspend fun getTaskCount(subject: Subject): Int |     suspend fun archiveSubject(subject: Subject) | ||||||
|     suspend fun getCompletedTaskCount(subject: Subject): Int | 
 | ||||||
|  |     fun getTaskCount(subject: Subject): Flow<Int> | ||||||
|  |     fun getCompletedTaskCount(subject: Subject): Flow<Int> | ||||||
|     fun getStudyTime(subject: Subject): Flow<Int> |     fun getStudyTime(subject: Subject): Flow<Int> | ||||||
| 
 | 
 | ||||||
|     suspend fun getSubject(subjectId: String): Subject? |     suspend fun getSubject(subjectId: String): Subject? | ||||||
|  |  | ||||||
|  | @ -1,11 +1,13 @@ | ||||||
| package be.ugent.sel.studeez.domain.implementation | package be.ugent.sel.studeez.domain.implementation | ||||||
| 
 | 
 | ||||||
|  | import android.util.Log | ||||||
| import be.ugent.sel.studeez.data.local.models.task.Subject | import be.ugent.sel.studeez.data.local.models.task.Subject | ||||||
| import be.ugent.sel.studeez.data.local.models.task.SubjectDocument | import be.ugent.sel.studeez.data.local.models.task.SubjectDocument | ||||||
|  | import be.ugent.sel.studeez.data.local.models.task.Task | ||||||
|  | import be.ugent.sel.studeez.data.local.models.task.TaskDocument | ||||||
| import be.ugent.sel.studeez.domain.AccountDAO | import be.ugent.sel.studeez.domain.AccountDAO | ||||||
| import be.ugent.sel.studeez.domain.SubjectDAO | import be.ugent.sel.studeez.domain.SubjectDAO | ||||||
| import be.ugent.sel.studeez.domain.TaskDAO | import be.ugent.sel.studeez.domain.TaskDAO | ||||||
| import com.google.firebase.firestore.AggregateSource |  | ||||||
| import com.google.firebase.firestore.CollectionReference | import com.google.firebase.firestore.CollectionReference | ||||||
| import com.google.firebase.firestore.FirebaseFirestore | import com.google.firebase.firestore.FirebaseFirestore | ||||||
| import com.google.firebase.firestore.Query | import com.google.firebase.firestore.Query | ||||||
|  | @ -15,6 +17,7 @@ import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.coroutines.flow.map | import kotlinx.coroutines.flow.map | ||||||
| import kotlinx.coroutines.tasks.await | import kotlinx.coroutines.tasks.await | ||||||
| import javax.inject.Inject | import javax.inject.Inject | ||||||
|  | import kotlin.collections.count | ||||||
| 
 | 
 | ||||||
| class FireBaseSubjectDAO @Inject constructor( | class FireBaseSubjectDAO @Inject constructor( | ||||||
|     private val firestore: FirebaseFirestore, |     private val firestore: FirebaseFirestore, | ||||||
|  | @ -26,13 +29,6 @@ class FireBaseSubjectDAO @Inject constructor( | ||||||
|             .subjectNotArchived() |             .subjectNotArchived() | ||||||
|             .snapshots() |             .snapshots() | ||||||
|             .map { it.toObjects(Subject::class.java) } |             .map { it.toObjects(Subject::class.java) } | ||||||
|             .map { subjects -> |  | ||||||
|                 subjects.map { subject -> |  | ||||||
|                     subject.taskCount = getTaskCount(subject) |  | ||||||
|                     subject.taskCompletedCount = getCompletedTaskCount(subject) |  | ||||||
|                     subject |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override suspend fun getSubject(subjectId: String): Subject? { |     override suspend fun getSubject(subjectId: String): Subject? { | ||||||
|  | @ -51,23 +47,26 @@ class FireBaseSubjectDAO @Inject constructor( | ||||||
|         currentUserSubjectsCollection().document(newSubject.id).set(newSubject) |         currentUserSubjectsCollection().document(newSubject.id).set(newSubject) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override suspend fun getTaskCount(subject: Subject): Int { |     override suspend fun archiveSubject(subject: Subject) { | ||||||
|         return subjectTasksCollection(subject) |         currentUserSubjectsCollection().document(subject.id).update(SubjectDocument.archived, true) | ||||||
|  |         currentUserSubjectsCollection().document(subject.id) | ||||||
|  |             .collection(FireBaseCollections.TASK_COLLECTION) | ||||||
|             .taskNotArchived() |             .taskNotArchived() | ||||||
|             .count() |             .get().await() | ||||||
|             .get(AggregateSource.SERVER) |             .documents | ||||||
|             .await() |             .forEach { | ||||||
|             .count.toInt() |                 it.reference.update(TaskDocument.archived, true) | ||||||
|  |             } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override suspend fun getCompletedTaskCount(subject: Subject): Int { |     override fun getTaskCount(subject: Subject): Flow<Int> { | ||||||
|         return subjectTasksCollection(subject) |         return taskDAO.getTasks(subject) | ||||||
|             .taskNotArchived() |             .map(List<Task>::count) | ||||||
|             .taskNotCompleted() |     } | ||||||
|             .count() | 
 | ||||||
|             .get(AggregateSource.SERVER) |     override fun getCompletedTaskCount(subject: Subject): Flow<Int> { | ||||||
|             .await() |         return taskDAO.getTasks(subject) | ||||||
|             .count.toInt() |             .map { tasks -> tasks.count { it.completed && !it.archived } } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun getStudyTime(subject: Subject): Flow<Int> { |     override fun getStudyTime(subject: Subject): Flow<Int> { | ||||||
|  |  | ||||||
|  | @ -25,9 +25,9 @@ import be.ugent.sel.studeez.screens.settings.SettingsRoute | ||||||
| import be.ugent.sel.studeez.screens.sign_up.SignUpRoute | import be.ugent.sel.studeez.screens.sign_up.SignUpRoute | ||||||
| import be.ugent.sel.studeez.screens.splash.SplashRoute | import be.ugent.sel.studeez.screens.splash.SplashRoute | ||||||
| import be.ugent.sel.studeez.screens.subjects.SubjectRoute | import be.ugent.sel.studeez.screens.subjects.SubjectRoute | ||||||
| import be.ugent.sel.studeez.screens.tasks.TaskRoute |  | ||||||
| import be.ugent.sel.studeez.screens.subjects.form.SubjectCreateRoute | import be.ugent.sel.studeez.screens.subjects.form.SubjectCreateRoute | ||||||
| import be.ugent.sel.studeez.screens.subjects.form.SubjectEditRoute | import be.ugent.sel.studeez.screens.subjects.form.SubjectEditRoute | ||||||
|  | import be.ugent.sel.studeez.screens.tasks.TaskRoute | ||||||
| import be.ugent.sel.studeez.screens.tasks.form.TaskCreateRoute | import be.ugent.sel.studeez.screens.tasks.form.TaskCreateRoute | ||||||
| import be.ugent.sel.studeez.screens.tasks.form.TaskEditRoute | import be.ugent.sel.studeez.screens.tasks.form.TaskEditRoute | ||||||
| import be.ugent.sel.studeez.screens.timer_form.TimerAddRoute | import be.ugent.sel.studeez.screens.timer_form.TimerAddRoute | ||||||
|  | @ -51,6 +51,7 @@ fun StudeezNavGraph( | ||||||
|     val open: (String) -> Unit = { appState.navigate(it) } |     val open: (String) -> Unit = { appState.navigate(it) } | ||||||
|     val openAndPopUp: (String, String) -> Unit = |     val openAndPopUp: (String, String) -> Unit = | ||||||
|         { route, popUp -> appState.navigateAndPopUp(route, popUp) } |         { route, popUp -> appState.navigateAndPopUp(route, popUp) } | ||||||
|  |     val clearAndNavigate: (route: String) -> Unit = { route -> appState.clearAndNavigate(route) } | ||||||
| 
 | 
 | ||||||
|     val drawerActions: DrawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp) |     val drawerActions: DrawerActions = getDrawerActions(drawerViewModel, open, openAndPopUp) | ||||||
|     val navigationBarActions: NavigationBarActions = |     val navigationBarActions: NavigationBarActions = | ||||||
|  | @ -200,7 +201,7 @@ fun StudeezNavGraph( | ||||||
| 
 | 
 | ||||||
|         composable(StudeezDestinations.SESSION_RECAP) { |         composable(StudeezDestinations.SESSION_RECAP) { | ||||||
|             SessionRecapRoute( |             SessionRecapRoute( | ||||||
|                 openAndPopUp = openAndPopUp, |                 clearAndNavigate = clearAndNavigate, | ||||||
|                 viewModel = hiltViewModel() |                 viewModel = hiltViewModel() | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -4,18 +4,13 @@ import android.media.MediaPlayer | ||||||
| import androidx.compose.foundation.background | import androidx.compose.foundation.background | ||||||
| import androidx.compose.foundation.layout.* | import androidx.compose.foundation.layout.* | ||||||
| import androidx.compose.foundation.shape.CircleShape | import androidx.compose.foundation.shape.CircleShape | ||||||
| import androidx.compose.material.Text |  | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.ui.Alignment | import androidx.compose.ui.Alignment | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.compose.ui.draw.clip | import androidx.compose.ui.draw.clip | ||||||
| import androidx.compose.ui.graphics.Color | import androidx.compose.ui.graphics.Color | ||||||
| import androidx.compose.ui.text.font.FontWeight |  | ||||||
| import androidx.compose.ui.text.style.TextAlign |  | ||||||
| import androidx.compose.ui.tooling.preview.Preview | import androidx.compose.ui.tooling.preview.Preview | ||||||
| import androidx.compose.ui.unit.dp | import androidx.compose.ui.unit.dp | ||||||
| import androidx.compose.ui.unit.sp |  | ||||||
| import be.ugent.sel.studeez.R |  | ||||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer | import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
| import be.ugent.sel.studeez.R.string as AppText | import be.ugent.sel.studeez.R.string as AppText | ||||||
|  | @ -37,23 +32,31 @@ class BreakSessionScreen( | ||||||
|             verticalAlignment = Alignment.CenterVertically, |             verticalAlignment = Alignment.CenterVertically, | ||||||
|             horizontalArrangement = Arrangement.Center, |             horizontalArrangement = Arrangement.Center, | ||||||
|         ) { |         ) { | ||||||
|             repeat(funPomoDoroTimer.repeats - funPomoDoroTimer.breaksRemaining) { |             if (funPomoDoroTimer.hasEnded()) { | ||||||
|  |                 repeat(funPomoDoroTimer.repeats) { | ||||||
|  |                     Dot(Color.Green) | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 repeat(funPomoDoroTimer.repeats - funPomoDoroTimer.breaksRemaining - 1) { | ||||||
|                     Dot(color = Color.DarkGray) |                     Dot(color = Color.DarkGray) | ||||||
|                 } |                 } | ||||||
|                 if (!funPomoDoroTimer.isInBreak) Dot(Color.Green) else Dot(Color.DarkGray) |                 if (!funPomoDoroTimer.isInBreak) Dot(Color.Green) else Dot(Color.DarkGray) | ||||||
|             repeat(funPomoDoroTimer.breaksRemaining - 1) { |                 repeat(funPomoDoroTimer.breaksRemaining) { | ||||||
|                     Dot(color = Color.Gray) |                     Dot(color = Color.Gray) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     @Composable |     @Composable | ||||||
|     private fun Dot(color: Color) { |     private fun Dot(color: Color) { | ||||||
|         Box(modifier = Modifier |         Box( | ||||||
|  |             modifier = Modifier | ||||||
|                 .padding(5.dp) |                 .padding(5.dp) | ||||||
|                 .size(10.dp) |                 .size(10.dp) | ||||||
|                 .clip(CircleShape) |                 .clip(CircleShape) | ||||||
|             .background(color)) |                 .background(color) | ||||||
|  |         ) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Composable |     @Composable | ||||||
|  |  | ||||||
|  | @ -1,13 +1,24 @@ | ||||||
| package be.ugent.sel.studeez.screens.session_recap | package be.ugent.sel.studeez.screens.session_recap | ||||||
| 
 | 
 | ||||||
| import androidx.compose.foundation.layout.Column | import androidx.compose.foundation.layout.* | ||||||
| import androidx.compose.material.ButtonDefaults | import androidx.compose.material.ButtonDefaults | ||||||
| import androidx.compose.material.Text | import androidx.compose.material.Text | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.mutableStateOf | ||||||
|  | import androidx.compose.runtime.remember | ||||||
|  | import androidx.compose.ui.Alignment | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.compose.ui.graphics.Color | import androidx.compose.ui.graphics.Color | ||||||
|  | import androidx.compose.ui.res.painterResource | ||||||
|  | import androidx.compose.ui.res.stringResource | ||||||
|  | import androidx.compose.ui.text.font.FontWeight | ||||||
|  | import androidx.compose.ui.text.style.TextAlign | ||||||
|  | import androidx.compose.ui.tooling.preview.Preview | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import androidx.compose.ui.unit.sp | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
| import be.ugent.sel.studeez.common.composable.BasicButton | import be.ugent.sel.studeez.common.composable.BasicButton | ||||||
|  | import be.ugent.sel.studeez.common.composable.ImageBackgroundButton | ||||||
| import be.ugent.sel.studeez.common.ext.basicButton | import be.ugent.sel.studeez.common.ext.basicButton | ||||||
| import be.ugent.sel.studeez.data.local.models.SessionReport | import be.ugent.sel.studeez.data.local.models.SessionReport | ||||||
| import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds | import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds | ||||||
|  | @ -21,24 +32,24 @@ data class SessionRecapActions( | ||||||
| 
 | 
 | ||||||
| fun getSessionRecapActions( | fun getSessionRecapActions( | ||||||
|     viewModel: SessionRecapViewModel, |     viewModel: SessionRecapViewModel, | ||||||
|     openAndPopUp: (String, String) -> Unit, |     clearAndNavigate: (String) -> Unit, | ||||||
| ): SessionRecapActions { | ): SessionRecapActions { | ||||||
|     return SessionRecapActions( |     return SessionRecapActions( | ||||||
|         viewModel::getSessionReport, |         viewModel::getSessionReport, | ||||||
|         {viewModel.saveSession(openAndPopUp)}, |         { viewModel.saveSession(clearAndNavigate) }, | ||||||
|         {viewModel.discardSession(openAndPopUp)} |         { viewModel.discardSession(clearAndNavigate) } | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun SessionRecapRoute( | fun SessionRecapRoute( | ||||||
|     openAndPopUp: (String, String) -> Unit, |     clearAndNavigate: (String) -> Unit, | ||||||
|     modifier: Modifier = Modifier, |     modifier: Modifier = Modifier, | ||||||
|     viewModel: SessionRecapViewModel, |     viewModel: SessionRecapViewModel, | ||||||
| ) { | ) { | ||||||
|     SessionRecapScreen( |     SessionRecapScreen( | ||||||
|         modifier = modifier, |         modifier = modifier, | ||||||
|         getSessionRecapActions(viewModel, openAndPopUp) |         getSessionRecapActions(viewModel, clearAndNavigate) | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -47,11 +58,62 @@ fun SessionRecapScreen(modifier: Modifier, sessionRecapActions: SessionRecapActi | ||||||
|     val sessionReport: SessionReport = sessionRecapActions.getSessionReport() |     val sessionReport: SessionReport = sessionRecapActions.getSessionReport() | ||||||
|     val studyTime: Int = sessionReport.studyTime |     val studyTime: Int = sessionReport.studyTime | ||||||
|     val hms: HoursMinutesSeconds = Time(studyTime).getAsHMS() |     val hms: HoursMinutesSeconds = Time(studyTime).getAsHMS() | ||||||
|  |     val (background1, setBackground1) = remember { mutableStateOf(Color.Transparent) } | ||||||
|  |     val (background2, setBackground2) = remember { mutableStateOf(Color.Transparent) } | ||||||
|     Column( |     Column( | ||||||
|         modifier = modifier |         modifier = modifier | ||||||
|  |             .fillMaxWidth() | ||||||
|  |             .fillMaxHeight() | ||||||
|  |             .padding(16.dp), | ||||||
|  |         horizontalAlignment = Alignment.CenterHorizontally, | ||||||
|  |         verticalArrangement = Arrangement.SpaceBetween | ||||||
|     ) { |     ) { | ||||||
|         Text(text = "You studied: $hms") |         Text( | ||||||
|  |             text = stringResource(R.string.congrats, hms), | ||||||
|  |             modifier = Modifier | ||||||
|  |                 .fillMaxWidth(), | ||||||
|  |             textAlign = TextAlign.Center, | ||||||
|  |             fontWeight = FontWeight.Light, | ||||||
|  |             fontSize = 30.sp, | ||||||
| 
 | 
 | ||||||
|  |             ) | ||||||
|  | 
 | ||||||
|  |         Column( | ||||||
|  |             modifier = Modifier.fillMaxWidth() | ||||||
|  |         ) { | ||||||
|  |             Text( | ||||||
|  |                 text = stringResource(R.string.how_did_it_go), | ||||||
|  |                 modifier = Modifier.fillMaxWidth(), | ||||||
|  |                 textAlign = TextAlign.Center, | ||||||
|  |                 fontWeight = FontWeight.Light, | ||||||
|  |                 fontSize = 30.sp | ||||||
|  |             ) | ||||||
|  | 
 | ||||||
|  |             Row( | ||||||
|  |                 horizontalArrangement = Arrangement.Center, | ||||||
|  |                 modifier = Modifier | ||||||
|  |                     .fillMaxWidth() | ||||||
|  |                     .align(Alignment.CenterHorizontally) | ||||||
|  |             ) { | ||||||
|  |                 ImageBackgroundButton( | ||||||
|  |                     paint = painterResource(id = R.drawable.mood_1), | ||||||
|  |                     str = stringResource(id = R.string.good), | ||||||
|  |                     background2 = background2, | ||||||
|  |                     setBackground1 = setBackground2, | ||||||
|  |                     setBackground2 = setBackground1 | ||||||
|  |                 ) | ||||||
|  | 
 | ||||||
|  |                 ImageBackgroundButton( | ||||||
|  |                     paint = painterResource(id = R.drawable.mood_2), | ||||||
|  |                     str = stringResource(id = R.string.bad), | ||||||
|  |                     background2 = background1, | ||||||
|  |                     setBackground1 = setBackground1, | ||||||
|  |                     setBackground2 = setBackground2 | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Column { | ||||||
|             BasicButton( |             BasicButton( | ||||||
|                 R.string.save, Modifier.basicButton() |                 R.string.save, Modifier.basicButton() | ||||||
|             ) { |             ) { | ||||||
|  | @ -65,3 +127,19 @@ fun SessionRecapScreen(modifier: Modifier, sessionRecapActions: SessionRecapActi | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @Preview | ||||||
|  | @Composable | ||||||
|  | fun SessionRecapScreenPreview() { | ||||||
|  |     SessionRecapScreen( | ||||||
|  |         modifier = Modifier, | ||||||
|  |         sessionRecapActions = SessionRecapActions( | ||||||
|  |             { SessionReport( | ||||||
|  |                 studyTime = 100, | ||||||
|  |             ) }, | ||||||
|  |             {}, | ||||||
|  |             {}, | ||||||
|  |         ) | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -24,15 +24,15 @@ class SessionRecapViewModel @Inject constructor( | ||||||
|         return selectedSessionReport() |         return selectedSessionReport() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun saveSession(open: (String, String) -> Unit) { |     fun saveSession(open: (String) -> Unit) { | ||||||
|         sessionDAO.saveSession(getSessionReport()) |         sessionDAO.saveSession(getSessionReport()) | ||||||
|         val newTask = |         val newTask = | ||||||
|             selectedTask().copy(time = selectedTask().time + selectedSessionReport().studyTime) |             selectedTask().copy(time = selectedTask().time + selectedSessionReport().studyTime) | ||||||
|         taskDAO.updateTask(newTask) |         taskDAO.updateTask(newTask) | ||||||
|         open(StudeezDestinations.HOME_SCREEN, StudeezDestinations.SESSION_RECAP) |         open(StudeezDestinations.HOME_SCREEN) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun discardSession(open: (String, String) -> Unit) { |     fun discardSession(open: (String) -> Unit) { | ||||||
|         open(StudeezDestinations.HOME_SCREEN, StudeezDestinations.SESSION_RECAP) |         open(StudeezDestinations.HOME_SCREEN) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -36,6 +36,8 @@ fun SubjectRoute( | ||||||
|         navigationBarActions = navigationBarActions, |         navigationBarActions = navigationBarActions, | ||||||
|         onAddSubject = { viewModel.onAddSubject(open) }, |         onAddSubject = { viewModel.onAddSubject(open) }, | ||||||
|         onViewSubject = { viewModel.onViewSubject(it, open) }, |         onViewSubject = { viewModel.onViewSubject(it, open) }, | ||||||
|  |         getTaskCount = viewModel::getTaskCount, | ||||||
|  |         getCompletedTaskCount = viewModel::getCompletedTaskCount, | ||||||
|         getStudyTime = viewModel::getStudyTime, |         getStudyTime = viewModel::getStudyTime, | ||||||
|         uiState, |         uiState, | ||||||
|     ) |     ) | ||||||
|  | @ -47,6 +49,8 @@ fun SubjectScreen( | ||||||
|     navigationBarActions: NavigationBarActions, |     navigationBarActions: NavigationBarActions, | ||||||
|     onAddSubject: () -> Unit, |     onAddSubject: () -> Unit, | ||||||
|     onViewSubject: (Subject) -> Unit, |     onViewSubject: (Subject) -> Unit, | ||||||
|  |     getTaskCount: (Subject) -> Flow<Int>, | ||||||
|  |     getCompletedTaskCount: (Subject) -> Flow<Int>, | ||||||
|     getStudyTime: (Subject) -> Flow<Int>, |     getStudyTime: (Subject) -> Flow<Int>, | ||||||
|     uiState: SubjectUiState, |     uiState: SubjectUiState, | ||||||
| ) { | ) { | ||||||
|  | @ -76,6 +80,8 @@ fun SubjectScreen( | ||||||
|                             SubjectEntry( |                             SubjectEntry( | ||||||
|                                 subject = it, |                                 subject = it, | ||||||
|                                 onViewSubject = { onViewSubject(it) }, |                                 onViewSubject = { onViewSubject(it) }, | ||||||
|  |                                 getTaskCount = { getTaskCount(it) }, | ||||||
|  |                                 getCompletedTaskCount = { getCompletedTaskCount(it) }, | ||||||
|                                 getStudyTime = { getStudyTime(it) }, |                                 getStudyTime = { getStudyTime(it) }, | ||||||
|                             ) |                             ) | ||||||
|                         } |                         } | ||||||
|  | @ -94,13 +100,14 @@ fun SubjectScreenPreview() { | ||||||
|         navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}), |         navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}), | ||||||
|         onAddSubject = {}, |         onAddSubject = {}, | ||||||
|         onViewSubject = {}, |         onViewSubject = {}, | ||||||
|  |         getTaskCount = { flowOf() }, | ||||||
|  |         getCompletedTaskCount = { flowOf() }, | ||||||
|         getStudyTime = { flowOf() }, |         getStudyTime = { flowOf() }, | ||||||
|         uiState = SubjectUiState.Succes( |         uiState = SubjectUiState.Succes( | ||||||
|             listOf( |             listOf( | ||||||
|                 Subject( |                 Subject( | ||||||
|                     name = "Test Subject", |                     name = "Test Subject", | ||||||
|                     argb_color = 0xFFFFD200, |                     argb_color = 0xFFFFD200, | ||||||
|                     taskCount = 5, taskCompletedCount = 2, |  | ||||||
|                 ) |                 ) | ||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
|  | @ -115,7 +122,9 @@ fun SubjectScreenLoadingPreview() { | ||||||
|         navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}), |         navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}), | ||||||
|         onAddSubject = {}, |         onAddSubject = {}, | ||||||
|         onViewSubject = {}, |         onViewSubject = {}, | ||||||
|  |         getTaskCount = { flowOf() }, | ||||||
|  |         getCompletedTaskCount = { flowOf() }, | ||||||
|         getStudyTime = { flowOf() }, |         getStudyTime = { flowOf() }, | ||||||
|         uiState = SubjectUiState.Loading |         uiState = SubjectUiState.Loading, | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  | @ -30,6 +30,14 @@ class SubjectViewModel @Inject constructor( | ||||||
|         open(StudeezDestinations.ADD_SUBJECT_FORM) |         open(StudeezDestinations.ADD_SUBJECT_FORM) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     fun getTaskCount(subject: Subject): Flow<Int> { | ||||||
|  |         return subjectDAO.getTaskCount(subject) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun getCompletedTaskCount(subject: Subject): Flow<Int> { | ||||||
|  |         return subjectDAO.getCompletedTaskCount(subject) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fun getStudyTime(subject: Subject): Flow<Int> { |     fun getStudyTime(subject: Subject): Flow<Int> { | ||||||
|         return subjectDAO.getStudyTime(subject) |         return subjectDAO.getStudyTime(subject) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -2,20 +2,28 @@ package be.ugent.sel.studeez.screens.subjects.form | ||||||
| 
 | 
 | ||||||
| import androidx.annotation.StringRes | import androidx.annotation.StringRes | ||||||
| import androidx.compose.foundation.layout.Column | import androidx.compose.foundation.layout.Column | ||||||
| import androidx.compose.material.OutlinedTextField | import androidx.compose.foundation.shape.RoundedCornerShape | ||||||
|  | import androidx.compose.material.Button | ||||||
|  | import androidx.compose.material.ButtonDefaults | ||||||
| import androidx.compose.material.Text | import androidx.compose.material.Text | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.runtime.getValue | import androidx.compose.runtime.getValue | ||||||
|  | import androidx.compose.runtime.rememberCoroutineScope | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.compose.ui.graphics.Color | import androidx.compose.ui.graphics.Color | ||||||
| import androidx.compose.ui.res.stringResource | import androidx.compose.ui.res.stringResource | ||||||
| import androidx.compose.ui.tooling.preview.Preview | import androidx.compose.ui.tooling.preview.Preview | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
| import be.ugent.sel.studeez.common.composable.BasicButton | import be.ugent.sel.studeez.common.composable.BasicButton | ||||||
| import be.ugent.sel.studeez.common.composable.DeleteButton | import be.ugent.sel.studeez.common.composable.DeleteButton | ||||||
|  | import be.ugent.sel.studeez.common.composable.FormComposable | ||||||
|  | import be.ugent.sel.studeez.common.composable.LabelledInputField | ||||||
| import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate | import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate | ||||||
| import be.ugent.sel.studeez.common.ext.basicButton | import be.ugent.sel.studeez.common.ext.basicButton | ||||||
| import be.ugent.sel.studeez.common.ext.fieldModifier | import be.ugent.sel.studeez.common.ext.fieldModifier | ||||||
|  | import be.ugent.sel.studeez.common.ext.generateRandomArgb | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
|  | import kotlinx.coroutines.launch | ||||||
| import be.ugent.sel.studeez.R.string as AppText | import be.ugent.sel.studeez.R.string as AppText | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
|  | @ -31,7 +39,7 @@ fun SubjectCreateRoute( | ||||||
|         uiState = uiState, |         uiState = uiState, | ||||||
|         onConfirm = { viewModel.onCreate(openAndPopUp) }, |         onConfirm = { viewModel.onCreate(openAndPopUp) }, | ||||||
|         onNameChange = viewModel::onNameChange, |         onNameChange = viewModel::onNameChange, | ||||||
|         onColorChange = {}, |         onColorChange = viewModel::onColorChange, | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -42,19 +50,22 @@ fun SubjectEditRoute( | ||||||
|     viewModel: SubjectEditFormViewModel, |     viewModel: SubjectEditFormViewModel, | ||||||
| ) { | ) { | ||||||
|     val uiState by viewModel.uiState |     val uiState by viewModel.uiState | ||||||
|  |     val coroutineScope = rememberCoroutineScope() | ||||||
|     SubjectForm( |     SubjectForm( | ||||||
|         title = AppText.edit_subject, |         title = AppText.edit_subject, | ||||||
|         goBack = goBack, |         goBack = goBack, | ||||||
|         uiState = uiState, |         uiState = uiState, | ||||||
|         onConfirm = { viewModel.onEdit(openAndPopUp) }, |         onConfirm = { viewModel.onEdit(openAndPopUp) }, | ||||||
|         onNameChange = viewModel::onNameChange, |         onNameChange = viewModel::onNameChange, | ||||||
|         onColorChange = {}, |         onColorChange = viewModel::onColorChange, | ||||||
|     ) { |     ) { | ||||||
|         DeleteButton(text = AppText.delete_subject) { |         DeleteButton(text = AppText.delete_subject) { | ||||||
|  |             coroutineScope.launch { | ||||||
|                 viewModel.onDelete(openAndPopUp) |                 viewModel.onDelete(openAndPopUp) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @Composable | @Composable | ||||||
| fun SubjectForm( | fun SubjectForm( | ||||||
|  | @ -63,21 +74,21 @@ fun SubjectForm( | ||||||
|     uiState: SubjectFormUiState, |     uiState: SubjectFormUiState, | ||||||
|     onConfirm: () -> Unit, |     onConfirm: () -> Unit, | ||||||
|     onNameChange: (String) -> Unit, |     onNameChange: (String) -> Unit, | ||||||
|     onColorChange: (Color) -> Unit, |     onColorChange: (Long) -> Unit, | ||||||
|     extraButton: @Composable () -> Unit = {}, |     extraButton: @Composable () -> Unit = {}, | ||||||
| ) { | ) { | ||||||
|     SecondaryScreenTemplate( |     FormComposable( | ||||||
|         title = resources().getString(title), |         title = resources().getString(title), | ||||||
|         popUp = goBack, |         popUp = goBack, | ||||||
|     ) { |     ) { | ||||||
|         Column { |         Column { | ||||||
|             OutlinedTextField( |             LabelledInputField( | ||||||
|                 singleLine = true, |                 singleLine = true, | ||||||
|                 value = uiState.name, |                 value = uiState.name, | ||||||
|                 onValueChange = onNameChange, |                 onNewValue = onNameChange, | ||||||
|                 placeholder = { Text(stringResource(id = AppText.name)) }, |                 label = AppText.name, | ||||||
|                 modifier = Modifier.fieldModifier(), |  | ||||||
|             ) |             ) | ||||||
|  |             ColorPicker(onColorChange, uiState) | ||||||
|             BasicButton( |             BasicButton( | ||||||
|                 text = AppText.confirm, |                 text = AppText.confirm, | ||||||
|                 modifier = Modifier.basicButton(), |                 modifier = Modifier.basicButton(), | ||||||
|  | @ -88,6 +99,24 @@ fun SubjectForm( | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Composable | ||||||
|  | fun ColorPicker( | ||||||
|  |     onColorChange: (Long) -> Unit, | ||||||
|  |     uiState: SubjectFormUiState, | ||||||
|  | ) { | ||||||
|  |     Button( | ||||||
|  |         onClick = { onColorChange(Color.generateRandomArgb()) }, | ||||||
|  |         modifier = Modifier.fieldModifier(), | ||||||
|  |         colors = ButtonDefaults.buttonColors( | ||||||
|  |             backgroundColor = Color(uiState.color), | ||||||
|  |             contentColor = Color.White, | ||||||
|  |         ), | ||||||
|  |         shape = RoundedCornerShape(4.dp), | ||||||
|  |     ) { | ||||||
|  |         Text(text = stringResource(id = AppText.regenerate_color)) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Preview | @Preview | ||||||
| @Composable | @Composable | ||||||
| fun AddSubjectFormPreview() { | fun AddSubjectFormPreview() { | ||||||
|  |  | ||||||
|  | @ -1,6 +1,9 @@ | ||||||
| package be.ugent.sel.studeez.screens.subjects.form | package be.ugent.sel.studeez.screens.subjects.form | ||||||
| 
 | 
 | ||||||
|  | import androidx.compose.ui.graphics.Color | ||||||
|  | import be.ugent.sel.studeez.common.ext.generateRandomArgb | ||||||
|  | 
 | ||||||
| data class SubjectFormUiState( | data class SubjectFormUiState( | ||||||
|     val name: String = "", |     val name: String = "", | ||||||
|     val color: Long = 0xFFFFD200, |     val color: Long = Color.generateRandomArgb(), | ||||||
| ) | ) | ||||||
|  | @ -2,10 +2,13 @@ package be.ugent.sel.studeez.screens.subjects.form | ||||||
| 
 | 
 | ||||||
| import androidx.compose.runtime.MutableState | import androidx.compose.runtime.MutableState | ||||||
| import androidx.compose.runtime.mutableStateOf | import androidx.compose.runtime.mutableStateOf | ||||||
|  | import androidx.compose.ui.graphics.Color | ||||||
|  | import be.ugent.sel.studeez.common.ext.generateRandomArgb | ||||||
| import be.ugent.sel.studeez.data.SelectedSubject | import be.ugent.sel.studeez.data.SelectedSubject | ||||||
| import be.ugent.sel.studeez.data.local.models.task.Subject | import be.ugent.sel.studeez.data.local.models.task.Subject | ||||||
| import be.ugent.sel.studeez.domain.LogService | import be.ugent.sel.studeez.domain.LogService | ||||||
| import be.ugent.sel.studeez.domain.SubjectDAO | import be.ugent.sel.studeez.domain.SubjectDAO | ||||||
|  | import be.ugent.sel.studeez.domain.TaskDAO | ||||||
| import be.ugent.sel.studeez.navigation.StudeezDestinations | import be.ugent.sel.studeez.navigation.StudeezDestinations | ||||||
| import be.ugent.sel.studeez.screens.StudeezViewModel | import be.ugent.sel.studeez.screens.StudeezViewModel | ||||||
| import dagger.hilt.android.lifecycle.HiltViewModel | import dagger.hilt.android.lifecycle.HiltViewModel | ||||||
|  | @ -59,6 +62,7 @@ class SubjectCreateFormViewModel @Inject constructor( | ||||||
| @HiltViewModel | @HiltViewModel | ||||||
| class SubjectEditFormViewModel @Inject constructor( | class SubjectEditFormViewModel @Inject constructor( | ||||||
|     subjectDAO: SubjectDAO, |     subjectDAO: SubjectDAO, | ||||||
|  |     private val taskDAO: TaskDAO, | ||||||
|     selectedSubject: SelectedSubject, |     selectedSubject: SelectedSubject, | ||||||
|     logService: LogService, |     logService: LogService, | ||||||
| ) : SubjectFormViewModel(subjectDAO, selectedSubject, logService) { | ) : SubjectFormViewModel(subjectDAO, selectedSubject, logService) { | ||||||
|  | @ -69,17 +73,19 @@ class SubjectEditFormViewModel @Inject constructor( | ||||||
|         ) |         ) | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     fun onDelete(openAndPopUp: (String, String) -> Unit) { |     suspend fun onDelete(openAndPopUp: (String, String) -> Unit) { | ||||||
|         subjectDAO.updateSubject(selectedSubject().copy(archived = true)) |         subjectDAO.archiveSubject(selectedSubject()) | ||||||
|         openAndPopUp(StudeezDestinations.SUBJECT_SCREEN, StudeezDestinations.EDIT_SUBJECT_FORM) |         openAndPopUp(StudeezDestinations.SUBJECT_SCREEN, StudeezDestinations.EDIT_SUBJECT_FORM) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun onEdit(openAndPopUp: (String, String) -> Unit) { |     fun onEdit(openAndPopUp: (String, String) -> Unit) { | ||||||
|         val newSubject = selectedSubject().copy( |         selectedSubject.set( | ||||||
|  |             selectedSubject().copy( | ||||||
|                 name = name, |                 name = name, | ||||||
|                 argb_color = color, |                 argb_color = color, | ||||||
|             ) |             ) | ||||||
|         subjectDAO.updateSubject(newSubject) |         ) | ||||||
|  |         subjectDAO.updateSubject(selectedSubject()) | ||||||
|         openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.EDIT_SUBJECT_FORM) |         openAndPopUp(StudeezDestinations.TASKS_SCREEN, StudeezDestinations.EDIT_SUBJECT_FORM) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -11,7 +11,7 @@ import androidx.compose.ui.res.stringResource | ||||||
| import androidx.compose.ui.tooling.preview.Preview | import androidx.compose.ui.tooling.preview.Preview | ||||||
| import be.ugent.sel.studeez.common.composable.BasicButton | import be.ugent.sel.studeez.common.composable.BasicButton | ||||||
| import be.ugent.sel.studeez.common.composable.DeleteButton | import be.ugent.sel.studeez.common.composable.DeleteButton | ||||||
| import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate | import be.ugent.sel.studeez.common.composable.FormComposable | ||||||
| import be.ugent.sel.studeez.common.ext.basicButton | import be.ugent.sel.studeez.common.ext.basicButton | ||||||
| import be.ugent.sel.studeez.common.ext.fieldModifier | import be.ugent.sel.studeez.common.ext.fieldModifier | ||||||
| import be.ugent.sel.studeez.resources | import be.ugent.sel.studeez.resources | ||||||
|  | @ -62,7 +62,7 @@ fun TaskForm( | ||||||
|     onNameChange: (String) -> Unit, |     onNameChange: (String) -> Unit, | ||||||
|     extraButton: @Composable () -> Unit = {} |     extraButton: @Composable () -> Unit = {} | ||||||
| ) { | ) { | ||||||
|     SecondaryScreenTemplate( |     FormComposable( | ||||||
|         title = resources().getString(title), |         title = resources().getString(title), | ||||||
|         popUp = goBack, |         popUp = goBack, | ||||||
|     ) { |     ) { | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.ui.res.stringResource | import androidx.compose.ui.res.stringResource | ||||||
| import be.ugent.sel.studeez.common.composable.DeleteButton | import be.ugent.sel.studeez.common.composable.DeleteButton | ||||||
| import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate | import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate | ||||||
|  | import be.ugent.sel.studeez.common.composable.FormComposable | ||||||
| import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo | import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo | ||||||
| import be.ugent.sel.studeez.R.string as AppText | import be.ugent.sel.studeez.R.string as AppText | ||||||
| 
 | 
 | ||||||
|  | @ -59,7 +60,10 @@ fun TimerFormScreen( | ||||||
| ) { | ) { | ||||||
|     val timerFormScreen = getTimerInfo().accept(GetTimerFormScreen()) |     val timerFormScreen = getTimerInfo().accept(GetTimerFormScreen()) | ||||||
| 
 | 
 | ||||||
|     SecondaryScreenTemplate(title = stringResource(id = label), popUp = popUp) { |     FormComposable( | ||||||
|  |         title = stringResource(id = label), | ||||||
|  |         popUp = popUp | ||||||
|  |     ) { | ||||||
|         timerFormScreen(onConfirmClick, extraButton) |         timerFormScreen(onConfirmClick, extraButton) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -1,13 +1,7 @@ | ||||||
| package be.ugent.sel.studeez.screens.timer_form.form_screens | package be.ugent.sel.studeez.screens.timer_form.form_screens | ||||||
| 
 | 
 | ||||||
| import androidx.compose.foundation.layout.Arrangement |  | ||||||
| import androidx.compose.foundation.layout.Column | import androidx.compose.foundation.layout.Column | ||||||
| import androidx.compose.foundation.layout.fillMaxHeight |  | ||||||
| import androidx.compose.foundation.layout.fillMaxWidth |  | ||||||
| import androidx.compose.foundation.rememberScrollState |  | ||||||
| import androidx.compose.foundation.verticalScroll |  | ||||||
| import androidx.compose.runtime.* | import androidx.compose.runtime.* | ||||||
| import androidx.compose.ui.Alignment |  | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
| import androidx.compose.ui.text.input.KeyboardType | import androidx.compose.ui.text.input.KeyboardType | ||||||
| import be.ugent.sel.studeez.R | import be.ugent.sel.studeez.R | ||||||
|  | @ -37,16 +31,7 @@ abstract class AbstractTimerFormScreen(private val timerInfo: TimerInfo) { | ||||||
|         extraButton: @Composable () -> Unit = {}, |         extraButton: @Composable () -> Unit = {}, | ||||||
|     ) { |     ) { | ||||||
| 
 | 
 | ||||||
|         Column( |         Column { | ||||||
|             verticalArrangement = Arrangement.SpaceBetween, |  | ||||||
|             modifier = Modifier |  | ||||||
|                 .fillMaxHeight() |  | ||||||
|                 .verticalScroll(rememberScrollState()), |  | ||||||
|         ) { |  | ||||||
|             Column( |  | ||||||
|                 modifier = Modifier.fillMaxWidth(), |  | ||||||
|                 horizontalAlignment = Alignment.CenterHorizontally |  | ||||||
|             ) { |  | ||||||
| 
 | 
 | ||||||
|             // Fields that every timer shares (ommited id) |             // Fields that every timer shares (ommited id) | ||||||
|             LabeledErrorTextField( |             LabeledErrorTextField( | ||||||
|  | @ -76,21 +61,19 @@ abstract class AbstractTimerFormScreen(private val timerInfo: TimerInfo) { | ||||||
| 
 | 
 | ||||||
|             ExtraFields() |             ExtraFields() | ||||||
| 
 | 
 | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             Column { |  | ||||||
|             BasicButton(R.string.save, Modifier.basicButton()) { |             BasicButton(R.string.save, Modifier.basicButton()) { | ||||||
|                 if (valids.all { it.component2().value }) { // All fields are valid |                 if (valids.all { it.component2().value }) { // All fields are valid | ||||||
|                     onSaveClick(timerInfo) |                     onSaveClick(timerInfo) | ||||||
|                 } else { |                 } else { | ||||||
|                         firsts.map { it.component2().value = false } // dont mask error because its not been filled out yet |                     firsts.map { | ||||||
|  |                         it.component2().value = false | ||||||
|  |                     } // dont mask error because its not been filled out yet | ||||||
|                     SnackbarManager.showMessage(AppText.fill_out_error) |                     SnackbarManager.showMessage(AppText.fill_out_error) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             extraButton() |             extraButton() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     private fun textPredicate(text: String): Boolean { |     private fun textPredicate(text: String): Boolean { | ||||||
|         return text.isNotBlank() |         return text.isNotBlank() | ||||||
|  |  | ||||||
							
								
								
									
										5
									
								
								app/src/main/res/drawable/mood_1.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/src/main/res/drawable/mood_1.xml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | <vector android:height="75dp" android:tint="#999999" | ||||||
|  |     android:viewportHeight="24" android:viewportWidth="24" | ||||||
|  |     android:width="75dp" xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <path android:fillColor="@android:color/white" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z"/> | ||||||
|  | </vector> | ||||||
							
								
								
									
										5
									
								
								app/src/main/res/drawable/mood_2.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/src/main/res/drawable/mood_2.xml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | <vector android:height="75dp" android:tint="#999999" | ||||||
|  |     android:viewportHeight="24" android:viewportWidth="24" | ||||||
|  |     android:width="75dp" xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <path android:fillColor="@android:color/white" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,14c-2.33,0 -4.31,1.46 -5.11,3.5h10.22c-0.8,-2.04 -2.78,-3.5 -5.11,-3.5z"/> | ||||||
|  | </vector> | ||||||
|  | @ -46,6 +46,7 @@ | ||||||
|     <string name="delete_subject">Delete Subject</string> |     <string name="delete_subject">Delete Subject</string> | ||||||
|     <string name="delete_task">Delete Task</string> |     <string name="delete_task">Delete Task</string> | ||||||
|     <string name="view_tasks">View</string> |     <string name="view_tasks">View</string> | ||||||
|  |     <string name="regenerate_color">Regenerate Color</string> | ||||||
| 
 | 
 | ||||||
|     <!-- Sessions --> |     <!-- Sessions --> | ||||||
|     <string name="sessions_temp_description">Looks like you found the sessions screen! In here, your upcoming studying sessions with friends will be listed. You can accept invites or edit your own.</string> <!-- TODO Remove this description line once implemented. --> |     <string name="sessions_temp_description">Looks like you found the sessions screen! In here, your upcoming studying sessions with friends will be listed. You can accept invites or edit your own.</string> <!-- TODO Remove this description line once implemented. --> | ||||||
|  | @ -156,4 +157,11 @@ | ||||||
|     <string name="breakTime">Break Time</string> |     <string name="breakTime">Break Time</string> | ||||||
|     <string name="repeats">Number of Repeats</string> |     <string name="repeats">Number of Repeats</string> | ||||||
| 
 | 
 | ||||||
|  |     <!-- Session Recap --> | ||||||
|  |     <string name="congrats">"Congratulations! You studied: %s"</string> | ||||||
|  |     <string name="how_did_it_go">How did it go?</string> | ||||||
|  |     <string name="good">Good</string> | ||||||
|  |     <string name="bad">Bad</string> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| </resources> | </resources> | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 lbarraga
						lbarraga