Merge pull request #103 from SELab1/feed

Feed
This commit is contained in:
brreynie 2023-05-09 19:33:53 +02:00 committed by GitHub Enterprise
commit d9d83569db
26 changed files with 549 additions and 51 deletions

View file

@ -3,10 +3,13 @@ package be.ugent.sel.studeez.common.composable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
@ -23,4 +26,14 @@ fun Headline(
fontSize = 34.sp
)
}
}
@Composable
fun DateText(date: String) {
Text(
text = date,
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
modifier = Modifier.padding(horizontal = 10.dp)
)
}

View file

@ -0,0 +1,160 @@
package be.ugent.sel.studeez.common.composable.feed
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import be.ugent.sel.studeez.common.composable.BasicTextButton
import be.ugent.sel.studeez.common.composable.DateText
import be.ugent.sel.studeez.common.composable.Headline
import be.ugent.sel.studeez.common.ext.textButton
import be.ugent.sel.studeez.data.local.models.FeedEntry
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
import be.ugent.sel.studeez.R.string as AppText
@Composable
fun Feed(
uiState: FeedUiState,
continueTask: (String, String) -> Unit,
onEmptyFeedHelp: () -> Unit
) {
when (uiState) {
FeedUiState.Loading -> LoadingFeed()
is FeedUiState.Succes -> LoadedFeed(
uiState = uiState,
continueTask = continueTask,
onEmptyFeedHelp = onEmptyFeedHelp
)
}
}
@Composable
fun LoadedFeed(
uiState: FeedUiState.Succes,
continueTask: (String, String) -> Unit,
onEmptyFeedHelp: () -> Unit,
) {
if (uiState.feedEntries.isEmpty()) EmptyFeed(onEmptyFeedHelp)
else FeedWithElements(uiState = uiState, continueTask = continueTask)
}
@Composable
fun LoadingFeed() {
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator(color = MaterialTheme.colors.onBackground)
}
}
@Composable
fun FeedWithElements(
uiState: FeedUiState.Succes,
continueTask: (String, String) -> Unit,
) {
val feedEntries = uiState.feedEntries
LazyColumn {
items(feedEntries.toList()) { (date, feedEntries) ->
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
val totalDayStudyTime: Int = feedEntries.sumOf { it.totalStudyTime }
DateText(date = date)
Text(
text = "${HoursMinutesSeconds(totalDayStudyTime)}",
fontSize = 15.sp,
fontWeight = FontWeight.Bold
)
}
feedEntries.forEach { feedEntry ->
FeedEntry(feedEntry = feedEntry) {
continueTask(feedEntry.subjectId, feedEntry.taskId)
}
}
Spacer(modifier = Modifier.height(20.dp))
}
}
}
@Composable
fun EmptyFeed(onEmptyFeedHelp: () -> Unit) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
Headline(text = stringResource(id = AppText.your_feed))
BasicTextButton(
AppText.empty_feed_help_text,
Modifier.textButton(),
action = onEmptyFeedHelp,
)
}
}
}
@Preview
@Composable
fun FeedLoadingPreview() {
Feed(
uiState = FeedUiState.Loading,
continueTask = { _, _ -> run {} }, {}
)
}
@Preview
@Composable
fun FeedPreview() {
Feed(
uiState = FeedUiState.Succes(
mapOf(
"08 May 2023" to listOf(
FeedEntry(
argb_color = 0xFFFFD200,
subJectName = "Test Subject",
taskName = "Test Task",
totalStudyTime = 600,
),
FeedEntry(
argb_color = 0xFFFFD200,
subJectName = "Test Subject",
taskName = "Test Task",
totalStudyTime = 20,
),
),
"09 May 2023" to listOf(
FeedEntry(
argb_color = 0xFFFD1200,
subJectName = "Test Subject",
taskName = "Test Task",
),
FeedEntry(
argb_color = 0xFFFFD200,
subJectName = "Test Subject",
taskName = "Test Task",
),
)
)
),
continueTask = { _, _ -> run {} }, {}
)
}

View file

@ -0,0 +1,96 @@
package be.ugent.sel.studeez.common.composable.feed
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.composable.StealthButton
import be.ugent.sel.studeez.data.local.models.FeedEntry
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
@Composable
fun FeedEntry(
feedEntry: FeedEntry,
continueWithTask: () -> Unit,
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 10.dp, vertical = 5.dp),
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(start = 10.dp)
.weight(11f)
) {
Box(
modifier = Modifier
.size(20.dp)
.clip(CircleShape)
.background(Color(feedEntry.argb_color)),
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Column(
verticalArrangement = Arrangement.spacedBy(0.dp)
) {
Text(
text = feedEntry.subJectName,
fontWeight = FontWeight.Bold,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
Text(
text = feedEntry.taskName,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
}
Text(text = HoursMinutesSeconds(feedEntry.totalStudyTime).toString())
}
}
StealthButton(
text = R.string.continue_task,
modifier = Modifier
.padding(start = 10.dp, end = 5.dp)
.weight(6f)
) {
continueWithTask()
}
}
}
}
@Preview
@Composable
fun FeedEntryPreview() {
FeedEntry(
continueWithTask = {},
feedEntry = FeedEntry(
argb_color = 0xFFFFD200,
subJectName = "Test Subject",
taskName = "Test Taskkkkkkkkkkkkkkkkkkkkkkkkk",
totalStudyTime = 20,
)
)
}

View file

@ -0,0 +1,8 @@
package be.ugent.sel.studeez.common.composable.feed
import be.ugent.sel.studeez.data.local.models.FeedEntry
sealed interface FeedUiState {
object Loading : FeedUiState
data class Succes(val feedEntries: Map<String, List<FeedEntry>>) : FeedUiState
}

View file

@ -0,0 +1,43 @@
package be.ugent.sel.studeez.common.composable.feed
import androidx.lifecycle.viewModelScope
import be.ugent.sel.studeez.data.SelectedTask
import be.ugent.sel.studeez.data.local.models.FeedEntry
import be.ugent.sel.studeez.domain.FeedDAO
import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.TaskDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class FeedViewModel @Inject constructor(
feedDAO: FeedDAO,
private val taskDAO: TaskDAO,
private val selectedTask: SelectedTask,
logService: LogService
) : StudeezViewModel(logService) {
val uiState: StateFlow<FeedUiState> = feedDAO.getFeedEntries()
.map { FeedUiState.Succes(it) }
.stateIn(
scope = viewModelScope,
initialValue = FeedUiState.Loading,
started = SharingStarted.Eagerly,
)
fun continueTask(open: (String) -> Unit, subjectId: String, taskId: String) {
viewModelScope.launch {
val task = taskDAO.getTask(subjectId, taskId)
selectedTask.set(task)
open(StudeezDestinations.TIMER_SELECTION_SCREEN)
}
}
fun onEmptyFeedHelp(open: (String) -> Unit) {
open(StudeezDestinations.ADD_SUBJECT_FORM)
}
}

View file

@ -32,6 +32,7 @@ fun TaskEntry(
task: Task,
onCheckTask: (Boolean) -> Unit,
onDeleteTask: () -> Unit,
onStartTask: () -> Unit
) {
Card(
modifier = Modifier
@ -95,6 +96,7 @@ fun TaskEntry(
modifier = Modifier
.padding(end = 5.dp),
) {
onStartTask()
}
}
}
@ -110,7 +112,7 @@ fun TaskEntryPreview() {
name = "Test Task",
completed = false,
),
{}, {},
{}, {}, {}
)
}
@ -122,7 +124,7 @@ fun CompletedTaskEntryPreview() {
name = "Test Task",
completed = true,
),
{}, {},
{}, {}, {},
)
}
@ -134,6 +136,6 @@ fun OverflowTaskEntryPreview() {
name = "Test Taskkkkkkkkkkkkkkkkkkkkkkkkkkk",
completed = false,
),
{}, {},
{}, {}, {}
)
}

View file

@ -0,0 +1,13 @@
package be.ugent.sel.studeez.data.local.models
import com.google.firebase.Timestamp
data class FeedEntry(
val argb_color: Long = 0,
val subJectName: String = "",
val taskName: String = "",
val taskId: String = "", // Name of task is not unique
val subjectId: String = "",
val totalStudyTime: Int = 0,
val endTime: Timestamp = Timestamp(0, 0)
)

View file

@ -6,5 +6,7 @@ import com.google.firebase.firestore.DocumentId
data class SessionReport(
@DocumentId val id: String = "",
val studyTime: Int = 0,
val endTime: Timestamp = Timestamp(0, 0)
val endTime: Timestamp = Timestamp(0, 0),
val taskId: String = "",
val subjectId: String = ""
)

View file

@ -2,6 +2,7 @@ package be.ugent.sel.studeez.data.local.models.timer_functional
import be.ugent.sel.studeez.data.local.models.SessionReport
import com.google.firebase.Timestamp
import com.google.firebase.firestore.DocumentReference
abstract class FunctionalTimer(initialValue: Int) {
var time: Time = Time(initialValue)
@ -17,10 +18,12 @@ abstract class FunctionalTimer(initialValue: Int) {
abstract fun hasCurrentCountdownEnded(): Boolean
fun getSessionReport(): SessionReport {
fun getSessionReport(subjectId: String, taskId: String): SessionReport {
return SessionReport(
studyTime = totalStudyTime,
endTime = Timestamp.now()
endTime = Timestamp.now(),
taskId = taskId,
subjectId = subjectId
)
}

View file

@ -33,4 +33,7 @@ abstract class DatabaseModule {
@Binds
abstract fun provideTaskDAO(impl: FireBaseTaskDAO): TaskDAO
@Binds
abstract fun provideFeedDAO(impl: FirebaseFeedDAO): FeedDAO
}

View file

@ -0,0 +1,10 @@
package be.ugent.sel.studeez.domain
import be.ugent.sel.studeez.data.local.models.FeedEntry
import kotlinx.coroutines.flow.Flow
interface FeedDAO {
fun getFeedEntries(): Flow<Map<String, List<FeedEntry>>>
}

View file

@ -12,4 +12,5 @@ interface SubjectDAO {
fun deleteSubject(oldSubject: Subject)
fun updateSubject(newSubject: Subject)
suspend fun getSubject(subjectId: String): Subject?
}

View file

@ -15,4 +15,6 @@ interface TaskDAO {
fun deleteTask(oldTask: Task)
fun toggleTaskCompleted(task: Task, completed: Boolean)
suspend fun getTask(subjectId: String, taskId: String): Task
}

View file

@ -1,13 +1,16 @@
package be.ugent.sel.studeez.domain.implementation
import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.data.local.models.task.Task
import be.ugent.sel.studeez.domain.AccountDAO
import be.ugent.sel.studeez.domain.SubjectDAO
import com.google.firebase.firestore.CollectionReference
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.snapshots
import com.google.firebase.firestore.ktx.toObject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
class FireBaseSubjectDAO @Inject constructor(
@ -20,6 +23,10 @@ class FireBaseSubjectDAO @Inject constructor(
.map { it.toObjects(Subject::class.java) }
}
override suspend fun getSubject(subjectId: String): Subject? {
return currentUserSubjectsCollection().document(subjectId).get().await().toObject()
}
override fun saveSubject(newSubject: Subject) {
currentUserSubjectsCollection().add(newSubject)
}

View file

@ -8,8 +8,11 @@ import be.ugent.sel.studeez.domain.TaskDAO
import com.google.firebase.firestore.CollectionReference
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.snapshots
import com.google.firebase.firestore.ktx.toObject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
class FireBaseTaskDAO @Inject constructor(
@ -22,6 +25,10 @@ class FireBaseTaskDAO @Inject constructor(
.map { it.toObjects(Task::class.java) }
}
override suspend fun getTask(subjectId: String, taskId: String): Task {
return selectedSubjectTasksCollection(subjectId).document(taskId).get().await().toObject()!!
}
override fun saveTask(newTask: Task) {
selectedSubjectTasksCollection(newTask.subjectId).add(newTask)
}

View file

@ -0,0 +1,78 @@
package be.ugent.sel.studeez.domain.implementation
import android.icu.text.DateFormat
import be.ugent.sel.studeez.data.local.models.FeedEntry
import be.ugent.sel.studeez.data.local.models.SessionReport
import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.data.local.models.task.Task
import be.ugent.sel.studeez.domain.FeedDAO
import be.ugent.sel.studeez.domain.SessionDAO
import be.ugent.sel.studeez.domain.TaskDAO
import com.google.firebase.Timestamp
import kotlinx.coroutines.flow.*
import javax.inject.Inject
class FirebaseFeedDAO @Inject constructor(
private val sessionDAO: SessionDAO,
private val taskDAO: TaskDAO,
private val subjectDAO: FireBaseSubjectDAO
) : FeedDAO {
/**
* Return a map as with key the day and value a list of feedentries for that day.
*/
override fun getFeedEntries(): Flow<Map<String, List<FeedEntry>>> {
return sessionDAO.getSessions().map {sessionReports ->
sessionReports
.map { sessionReport -> sessionToFeedEntry(sessionReport) }
.sortedByDescending { it.endTime }
.groupBy { getFormattedTime(it) }
.mapValues { (_, entries) ->
entries
.groupBy { it.taskId }
.map { fuseFeedEntries(it.component2()) }
}
}
}
private fun getFormattedTime(entry: FeedEntry): String {
return DateFormat.getDateInstance().format(entry.endTime.toDate())
}
/**
* Givin a list of entries referencing the same task, in the same day, fuse them into one
* feed-entry by adding the studytime and keeping the most recent end-timestamp
*/
private fun fuseFeedEntries(entries: List<FeedEntry>): FeedEntry =
entries.drop(1).fold(entries[0]) { accEntry, newEntry ->
accEntry.copy(
totalStudyTime = accEntry.totalStudyTime + newEntry.totalStudyTime,
endTime = getMostRecent(accEntry.endTime, newEntry.endTime)
)
}
private fun getMostRecent(t1: Timestamp, t2: Timestamp): Timestamp {
return if (t1 < t2) t2 else t1
}
/**
* Convert a sessionReport to a feedEntry. Fetch Task and Subject to get names
*/
private suspend fun sessionToFeedEntry(sessionReport: SessionReport): FeedEntry {
val subjectId: String = sessionReport.subjectId
val taskId: String = sessionReport.taskId
val task: Task = taskDAO.getTask(subjectId, taskId)
val subject: Subject = subjectDAO.getSubject(subjectId)!!
return FeedEntry(
argb_color = subject.argb_color,
subJectName = subject.name,
taskName = task.name,
taskId = task.id,
subjectId = subject.id,
totalStudyTime = sessionReport.studyTime,
endTime = sessionReport.endTime
)
}
}

View file

@ -65,9 +65,9 @@ fun StudeezNavGraph(
composable(StudeezDestinations.HOME_SCREEN) {
HomeRoute(
open,
viewModel = hiltViewModel(),
drawerActions = drawerActions,
navigationBarActions = navigationBarActions
navigationBarActions = navigationBarActions,
feedViewModel = hiltViewModel(),
)
}

View file

@ -5,35 +5,45 @@ import androidx.compose.material.IconButton
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Person
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.tooling.preview.Preview
import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.composable.BasicButton
import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
import be.ugent.sel.studeez.common.composable.feed.Feed
import be.ugent.sel.studeez.common.composable.feed.FeedUiState
import be.ugent.sel.studeez.common.composable.feed.FeedViewModel
import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions
import be.ugent.sel.studeez.common.ext.basicButton
import be.ugent.sel.studeez.data.local.models.FeedEntry
import be.ugent.sel.studeez.resources
@Composable
fun HomeRoute(
open: (String) -> Unit,
viewModel: HomeViewModel,
drawerActions: DrawerActions,
navigationBarActions: NavigationBarActions,
feedViewModel: FeedViewModel,
) {
val feedUiState by feedViewModel.uiState.collectAsState()
HomeScreen(
onStartSessionClick = { viewModel.onStartSessionClick(open) },
drawerActions = drawerActions,
open = open,
navigationBarActions = navigationBarActions,
feedUiState = feedUiState,
continueTask = { subjectId, taskId -> feedViewModel.continueTask(open, subjectId, taskId) },
onEmptyFeedHelp = { feedViewModel.onEmptyFeedHelp(open) }
)
}
@Composable
fun HomeScreen(
onStartSessionClick: () -> Unit,
open: (String) -> Unit,
drawerActions: DrawerActions,
navigationBarActions: NavigationBarActions
navigationBarActions: NavigationBarActions,
feedUiState: FeedUiState,
continueTask: (String, String) -> Unit,
onEmptyFeedHelp: () -> Unit,
) {
PrimaryScreenTemplate(
title = resources().getString(R.string.home),
@ -41,9 +51,7 @@ fun HomeScreen(
navigationBarActions = navigationBarActions,
// TODO barAction = { FriendsAction() }
) {
BasicButton(R.string.start_session, Modifier.basicButton()) {
onStartSessionClick()
}
Feed(feedUiState, continueTask, onEmptyFeedHelp)
}
}
@ -61,8 +69,40 @@ fun FriendsAction() {
@Composable
fun HomeScreenPreview() {
HomeScreen(
onStartSessionClick = {},
drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {})
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}),
open = {},
feedUiState = FeedUiState.Succes(
mapOf(
"08 May 2023" to listOf(
FeedEntry(
argb_color = 0xFFABD200,
subJectName = "Test Subject",
taskName = "Test Task",
totalStudyTime = 600,
),
FeedEntry(
argb_color = 0xFFFFD200,
subJectName = "Test Subject",
taskName = "Test Task",
totalStudyTime = 20,
),
),
"09 May 2023" to listOf(
FeedEntry(
argb_color = 0xFFFD1200,
subJectName = "Test Subject",
taskName = "Test Task",
),
FeedEntry(
argb_color = 0xFFFF5C89,
subJectName = "Test Subject",
taskName = "Test Task",
),
)
)
),
continueTask = { _, _ -> run {} },
onEmptyFeedHelp = {}
)
}

View file

@ -1,19 +0,0 @@
package be.ugent.sel.studeez.screens.home
import be.ugent.sel.studeez.domain.AccountDAO
import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class HomeViewModel @Inject constructor(
private val accountDAO: AccountDAO,
logService: LogService
) : StudeezViewModel(logService) {
fun onStartSessionClick(open: (String) -> Unit) {
open(StudeezDestinations.TIMER_SELECTION_SCREEN)
}
}

View file

@ -1,7 +1,9 @@
package be.ugent.sel.studeez.screens.session
import be.ugent.sel.studeez.data.SelectedTask
import be.ugent.sel.studeez.data.SelectedTimerState
import be.ugent.sel.studeez.data.SessionReportState
import be.ugent.sel.studeez.data.local.models.task.Task
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.navigation.StudeezDestinations
@ -13,21 +15,22 @@ import javax.inject.Inject
class SessionViewModel @Inject constructor(
private val selectedTimerState: SelectedTimerState,
private val sessionReportState: SessionReportState,
private val selectedTask: SelectedTask,
logService: LogService
) : StudeezViewModel(logService) {
private val task : String = "No task selected" // placeholder for tasks implementation
private val task : Task = selectedTask()
fun getTimer() : FunctionalTimer {
return selectedTimerState.selectedTimer!!
}
fun getTask(): String {
return task
return task.name
}
fun endSession(openAndPopUp: (String, String) -> Unit) {
sessionReportState.sessionReport = getTimer().getSessionReport()
sessionReportState.sessionReport = getTimer().getSessionReport(task.subjectId, task.id)
openAndPopUp(StudeezDestinations.SESSION_RECAP, StudeezDestinations.SESSION_SCREEN)
}
}

View file

@ -30,6 +30,7 @@ data class TaskActions(
val deleteTask: (Task) -> Unit,
val onCheckTask: (Task, Boolean) -> Unit,
val editSubject: () -> Unit,
val startTask: (Task) -> Unit
)
fun getTaskActions(viewModel: TaskViewModel, open: (String) -> Unit): TaskActions {
@ -39,7 +40,8 @@ fun getTaskActions(viewModel: TaskViewModel, open: (String) -> Unit): TaskAction
getSubject = viewModel::getSelectedSubject,
deleteTask = viewModel::deleteTask,
onCheckTask = { task, isChecked -> viewModel.toggleTaskCompleted(task, isChecked) },
editSubject = { viewModel.editSubject(open) }
editSubject = { viewModel.editSubject(open) },
startTask = { task -> viewModel.startTask(task, open) }
)
}
@ -75,6 +77,7 @@ fun TaskScreen(
task = it,
onCheckTask = { isChecked -> taskActions.onCheckTask(it, isChecked) },
onDeleteTask = { taskActions.deleteTask(it) },
onStartTask = { taskActions.startTask(it) }
)
}
}
@ -108,6 +111,7 @@ fun TaskScreenPreview() {
{},
{ _, _ -> run {} },
{},
{}
)
)
}

View file

@ -1,6 +1,7 @@
package be.ugent.sel.studeez.screens.tasks
import be.ugent.sel.studeez.data.SelectedSubject
import be.ugent.sel.studeez.data.SelectedTask
import be.ugent.sel.studeez.data.local.models.task.Subject
import be.ugent.sel.studeez.data.local.models.task.Task
import be.ugent.sel.studeez.domain.LogService
@ -17,6 +18,7 @@ class TaskViewModel @Inject constructor(
private val taskDAO: TaskDAO,
private val subjectDAO: SubjectDAO,
private val selectedSubject: SelectedSubject,
private val selectedTask: SelectedTask,
logService: LogService,
) : StudeezViewModel(logService) {
fun addTask(open: (String) -> Unit) {
@ -47,4 +49,9 @@ class TaskViewModel @Inject constructor(
fun editSubject(open: (String) -> Unit) {
open(StudeezDestinations.EDIT_SUBJECT_FORM)
}
fun startTask(task: Task, open: (String) -> Unit) {
selectedTask.set(task)
open(StudeezDestinations.TIMER_SELECTION_SCREEN)
}
}

View file

@ -82,12 +82,13 @@ fun TimerOverviewScreen(
items(timers.value) { timerInfo ->
TimerEntry(
timerInfo = timerInfo,
) {
StealthButton(
text = R.string.edit,
onClick = { timerOverviewActions.onEditClick(timerInfo) }
)
}
rightButton = {
StealthButton(
text = R.string.edit,
onClick = { timerOverviewActions.onEditClick(timerInfo) }
)
}
)
}

View file

@ -1,10 +1,13 @@
package be.ugent.sel.studeez.screens.timer_selection
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
import be.ugent.sel.studeez.common.composable.StealthButton
@ -99,7 +102,10 @@ fun CustomTimerEntry(
)
},
rightButton = {
TimePickerButton(initialSeconds = hms.getTotalSeconds()) { chosenTime ->
TimePickerButton(
initialSeconds = hms.getTotalSeconds(),
modifier = Modifier.padding(horizontal = 5.dp)
) { chosenTime ->
timerInfo.studyTime = chosenTime
}
}

View file

@ -5,6 +5,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import be.ugent.sel.studeez.data.SelectedTimerState
import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.TimerDAO
@ -21,7 +22,9 @@ class TimerSelectionViewModel @Inject constructor(
logService: LogService
) : StudeezViewModel(logService) {
var customTimerStudyTime: MutableState<Int> = mutableStateOf(0)
var customTimerStudyTime: MutableState<Int> = mutableStateOf(
HoursMinutesSeconds(1, 0, 0).getTotalSeconds()
)
fun getAllTimers() : Flow<List<TimerInfo>> {
return timerDAO.getAllTimers()

View file

@ -29,6 +29,11 @@
<string name="home">Home</string>
<string name="start_session">Start session</string>
<!-- Feed-->
<string name="continue_task">Continue</string>
<string name="your_feed">This is your feed</string>
<string name="empty_feed_help_text">Create you first subject and tasks to get started</string>
<!-- Tasks -->
<string name="tasks">Tasks</string>
<string name="task">Task</string>