From 439bc0ab61991cbfb86beaaa249ecf37894de21f Mon Sep 17 00:00:00 2001 From: lbarraga Date: Tue, 16 May 2023 10:04:21 +0200 Subject: [PATCH 1/6] changed sessions to feed in navbar --- .../navbar/NavigationBarComposable.kt | 10 +-- .../navbar/NavigationBarViewModel.kt | 4 +- .../be/ugent/sel/studeez/domain/SessionDAO.kt | 3 +- .../be/ugent/sel/studeez/domain/TaskDAO.kt | 2 + .../implementation/FirebaseSessionDAO.kt | 35 +++++----- .../domain/implementation/FirebaseTaskDAO.kt | 11 +++- .../sel/studeez/navigation/StudeezNavGraph.kt | 8 ++- .../screens/friends_feed/FriendsFeedScreen.kt | 65 +++++++++++++++++++ .../friends_feed/FriendsFeedViewModel.kt | 23 +++++++ .../screens/sessions/SessionsScreen.kt | 42 ------------ 10 files changed, 131 insertions(+), 72 deletions(-) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedScreen.kt create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedViewModel.kt delete mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/sessions/SessionsScreen.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt index c4d6e33..ecf26b0 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarComposable.kt @@ -8,13 +8,15 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.List import androidx.compose.material.icons.filled.Person +import androidx.compose.material.icons.outlined.Check import androidx.compose.material.icons.outlined.DateRange +import androidx.compose.material.icons.outlined.Face import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import be.ugent.sel.studeez.navigation.StudeezDestinations.FRIENDS_FEED import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN -import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.SUBJECT_SCREEN import be.ugent.sel.studeez.resources import be.ugent.sel.studeez.ui.theme.StudeezTheme @@ -99,11 +101,11 @@ fun NavigationBar( BottomNavigationItem( icon = { Icon( - imageVector = Icons.Outlined.DateRange, resources().getString(AppText.sessions) + imageVector = Icons.Outlined.Face, resources().getString(AppText.friends_feed) ) }, - label = { Text(text = resources().getString(AppText.sessions)) }, - selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN), + label = { Text(text = resources().getString(AppText.friends_feed)) }, + selected = navigationBarActions.isSelectedTab(FRIENDS_FEED), onClick = navigationBarActions.onSessionsClick ) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt index 07a5bf9..3b8c142 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/navbar/NavigationBarViewModel.kt @@ -2,9 +2,9 @@ package be.ugent.sel.studeez.common.composable.navbar import be.ugent.sel.studeez.common.snackbar.SnackbarManager import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.navigation.StudeezDestinations.FRIENDS_FEED import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN -import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN import be.ugent.sel.studeez.navigation.StudeezDestinations.SUBJECT_SCREEN import be.ugent.sel.studeez.screens.StudeezViewModel import dagger.hilt.android.lifecycle.HiltViewModel @@ -25,7 +25,7 @@ class NavigationBarViewModel @Inject constructor( } fun onSessionsClick(open: (String) -> Unit) { - open(SESSIONS_SCREEN) + open(FRIENDS_FEED) } fun onProfileClick(open: (String) -> Unit) { diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/SessionDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/SessionDAO.kt index bb233e9..53d6996 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/SessionDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/SessionDAO.kt @@ -2,6 +2,7 @@ package be.ugent.sel.studeez.domain import be.ugent.sel.studeez.data.local.models.SessionReport import be.ugent.sel.studeez.data.local.models.User +import be.ugent.sel.studeez.data.local.models.task.Task import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo import kotlinx.coroutines.flow.Flow @@ -13,7 +14,7 @@ interface SessionDAO { /** * Return a list of pairs, containing the username and all the studysessions of that user. */ - fun getFriendsSessions(): Flow>>> + fun getFriendsSessions(): Flow>>> fun saveSession(newSessionReport: SessionReport) diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/TaskDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/TaskDAO.kt index 8a2dd41..c27cf7d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/TaskDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/TaskDAO.kt @@ -15,4 +15,6 @@ interface TaskDAO { fun deleteTask(oldTask: Task) suspend fun getTask(subjectId: String, taskId: String): Task + + suspend fun getTaskFromUser(subjectId: String, taskId: String, userId: String): Task } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSessionDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSessionDAO.kt index e7cb763..7072de6 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSessionDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSessionDAO.kt @@ -2,14 +2,12 @@ package be.ugent.sel.studeez.domain.implementation import be.ugent.sel.studeez.data.local.models.SessionReport import be.ugent.sel.studeez.data.local.models.User +import be.ugent.sel.studeez.data.local.models.task.Task import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo import be.ugent.sel.studeez.data.remote.FirebaseSessionReport import be.ugent.sel.studeez.data.remote.FirebaseSessionReport.ENDTIME import be.ugent.sel.studeez.data.remote.FirebaseSessionReport.STUDYTIME -import be.ugent.sel.studeez.domain.AccountDAO -import be.ugent.sel.studeez.domain.FriendshipDAO -import be.ugent.sel.studeez.domain.SessionDAO -import be.ugent.sel.studeez.domain.UserDAO +import be.ugent.sel.studeez.domain.* import be.ugent.sel.studeez.domain.implementation.FirebaseCollections.SESSION_COLLECTION import be.ugent.sel.studeez.domain.implementation.FirebaseCollections.USER_COLLECTION import com.google.firebase.Timestamp @@ -17,6 +15,7 @@ import com.google.firebase.firestore.CollectionReference import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.ktx.getField import com.google.firebase.firestore.ktx.snapshots +import com.google.firebase.firestore.ktx.toObject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.map @@ -27,7 +26,8 @@ class FirebaseSessionDAO @Inject constructor( private val firestore: FirebaseFirestore, private val auth: AccountDAO, private val userDAO: UserDAO, - private val friendshipDAO: FriendshipDAO + private val friendshipDAO: FriendshipDAO, + private val taskDAO: TaskDAO, ) : SessionDAO { override fun getSessions(): Flow> { @@ -37,29 +37,28 @@ class FirebaseSessionDAO @Inject constructor( } override suspend fun getSessionsOfUser(userId: String): List { - val collection = firestore.collection(USER_COLLECTION) + return firestore.collection(USER_COLLECTION) .document(userId) .collection(SESSION_COLLECTION) .get().await() - val list: MutableList = mutableListOf() - for (document in collection) { - val id = document.id - val studyTime: Int = document.getField(STUDYTIME)!! - val endTime: Timestamp = document.getField(ENDTIME)!! - list.add(SessionReport(id, studyTime, endTime)) - } - return list + .map { it.toObject(SessionReport::class.java) } } - override fun getFriendsSessions(): Flow>>> { + override fun getFriendsSessions(): Flow>>> { return friendshipDAO.getAllFriendships(auth.currentUserId) .map { friendships -> friendships.map { friendship -> val userId: String = friendship.friendId val username = userDAO.getUsername(userId) - val userSessions = getSessionsOfUser(userId) - - Pair(username, userSessions) + val userTasks = getSessionsOfUser(userId) + .map { sessionReport -> + taskDAO.getTaskFromUser( + sessionReport.subjectId, + sessionReport.taskId, + userId + ) + } + Pair(username, userTasks) } } } diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseTaskDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseTaskDAO.kt index 93bc221..1ca60e4 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseTaskDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseTaskDAO.kt @@ -30,6 +30,13 @@ class FirebaseTaskDAO @Inject constructor( return selectedSubjectTasksCollection(subjectId).document(taskId).get().await().toObject()!! } + override suspend fun getTaskFromUser(subjectId: String, taskId: String, userId: String): Task { + return selectedSubjectTasksCollection(subjectId, userId) + .document(taskId) + .get() + .await().toObject(Task::class.java)!! + } + override fun saveTask(newTask: Task) { selectedSubjectTasksCollection(newTask.subjectId).add(newTask) } @@ -44,9 +51,9 @@ class FirebaseTaskDAO @Inject constructor( selectedSubjectTasksCollection(oldTask.subjectId).document(oldTask.id).delete() } - private fun selectedSubjectTasksCollection(subjectId: String): CollectionReference = + private fun selectedSubjectTasksCollection(subjectId: String, id: String = auth.currentUserId): CollectionReference = firestore.collection(FirebaseCollections.USER_COLLECTION) - .document(auth.currentUserId) + .document(id) .collection(FirebaseCollections.SUBJECT_COLLECTION) .document(subjectId) .collection(FirebaseCollections.TASK_COLLECTION) diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt index 6b59abc..1953d03 100644 --- a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt @@ -16,6 +16,8 @@ import be.ugent.sel.studeez.common.composable.navbar.NavigationBarViewModel import be.ugent.sel.studeez.common.composable.navbar.getNavigationBarActions import be.ugent.sel.studeez.screens.friends.friends_overview.FriendsOveriewRoute import be.ugent.sel.studeez.screens.friends.friends_search.SearchFriendsRoute +import be.ugent.sel.studeez.screens.friends_feed.FriendsFeedRoute +import be.ugent.sel.studeez.screens.friends_feed.FriendsFeedScreen import be.ugent.sel.studeez.screens.home.HomeRoute import be.ugent.sel.studeez.screens.log_in.LoginRoute import be.ugent.sel.studeez.screens.profile.edit_profile.EditProfileRoute @@ -23,7 +25,6 @@ import be.ugent.sel.studeez.screens.profile.ProfileRoute import be.ugent.sel.studeez.screens.profile.public_profile.PublicProfileRoute import be.ugent.sel.studeez.screens.session.SessionRoute import be.ugent.sel.studeez.screens.session_recap.SessionRecapRoute -import be.ugent.sel.studeez.screens.sessions.SessionsRoute import be.ugent.sel.studeez.screens.settings.SettingsRoute import be.ugent.sel.studeez.screens.sign_up.SignUpRoute import be.ugent.sel.studeez.screens.splash.SplashRoute @@ -127,9 +128,10 @@ fun StudeezNavGraph( composable(StudeezDestinations.SESSIONS_SCREEN) { - SessionsRoute( + FriendsFeedRoute( drawerActions = drawerActions, - navigationBarActions = navigationBarActions + navigationBarActions = navigationBarActions, + viewModel = hiltViewModel() ) } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedScreen.kt new file mode 100644 index 0000000..62e7050 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedScreen.kt @@ -0,0 +1,65 @@ +package be.ugent.sel.studeez.screens.friends_feed + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.Divider +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate +import be.ugent.sel.studeez.common.composable.TimerEntry +import be.ugent.sel.studeez.common.composable.drawer.DrawerActions +import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions +import be.ugent.sel.studeez.data.local.models.SessionReport +import be.ugent.sel.studeez.data.local.models.task.Task +import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds +import be.ugent.sel.studeez.resources +import be.ugent.sel.studeez.R.string as AppText + +@Composable +fun FriendsFeedRoute( + viewModel: FriendsFeedViewModel, + drawerActions: DrawerActions, + navigationBarActions: NavigationBarActions +) { + FriendsFeedScreen( + drawerActions = drawerActions, + navigationBarActions = navigationBarActions, + viewModel = viewModel + ) +} + +@Composable +fun FriendsFeedScreen( + drawerActions: DrawerActions, + navigationBarActions: NavigationBarActions, + viewModel: FriendsFeedViewModel +) { + PrimaryScreenTemplate( + title = resources().getString(AppText.upcoming_sessions), + drawerActions = drawerActions, + navigationBarActions = navigationBarActions + ) { + + val friendsSessions = viewModel.getFriendsSessions().collectAsState(initial = emptyList()) + LazyColumn() { + // Default Timers, cannot be edited + items(friendsSessions.value) { + FriendsFeedEntry(name = it.first, sessions = it.second) + Divider() + } + } + + } +} + +@Composable +fun FriendsFeedEntry(name: String, sessions: List) { + Column() { + Text(text = "$name Werkte ") + sessions.forEach { + Text(text = "${HoursMinutesSeconds(it.time)} aan ${it.name}") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedViewModel.kt new file mode 100644 index 0000000..6426161 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedViewModel.kt @@ -0,0 +1,23 @@ +package be.ugent.sel.studeez.screens.friends_feed + +import be.ugent.sel.studeez.data.local.models.task.Task +import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.domain.SessionDAO +import be.ugent.sel.studeez.screens.StudeezViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +@HiltViewModel +class FriendsFeedViewModel @Inject constructor( + private val sessionDAO: SessionDAO, + logService: LogService +) : StudeezViewModel(logService) { + + fun getFriendsSessions(): Flow>>> { + return sessionDAO.getFriendsSessions() + } + + +} + diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/sessions/SessionsScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/sessions/SessionsScreen.kt deleted file mode 100644 index fe60ca8..0000000 --- a/app/src/main/java/be/ugent/sel/studeez/screens/sessions/SessionsScreen.kt +++ /dev/null @@ -1,42 +0,0 @@ -package be.ugent.sel.studeez.screens.sessions - -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextAlign -import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate -import be.ugent.sel.studeez.common.composable.drawer.DrawerActions -import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions -import be.ugent.sel.studeez.resources -import be.ugent.sel.studeez.R.string as AppText - -@Composable -fun SessionsRoute( - // viewModel: SessionsViewModel, - drawerActions: DrawerActions, - navigationBarActions: NavigationBarActions -) { - SessionsScreen( - drawerActions = drawerActions, - navigationBarActions = navigationBarActions - ) -} - -@Composable -fun SessionsScreen( - drawerActions: DrawerActions, - navigationBarActions: NavigationBarActions -) { - PrimaryScreenTemplate( - title = resources().getString(AppText.upcoming_sessions), - drawerActions = drawerActions, - navigationBarActions = navigationBarActions - ) { - Text( - text = resources().getString(AppText.sessions_temp_description), - modifier = Modifier.fillMaxSize(), - textAlign = TextAlign.Center - ) - } -} \ No newline at end of file From 4d2abaec12ede44cdab4938f93f405d2a7610231 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Tue, 16 May 2023 10:04:50 +0200 Subject: [PATCH 2/6] changed dateText to Medium instead of bold --- .../be/ugent/sel/studeez/common/composable/TextComposable.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextComposable.kt index 25fa3c4..425d8f6 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/TextComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/TextComposable.kt @@ -32,7 +32,7 @@ fun Headline( fun DateText(date: String) { Text( text = date, - fontWeight = FontWeight.Bold, + fontWeight = FontWeight.Medium, fontSize = 20.sp, modifier = Modifier.padding(horizontal = 10.dp) ) From 43b46dd4a15318e4e19f2d593b27677b428898c3 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Tue, 16 May 2023 10:05:37 +0200 Subject: [PATCH 3/6] changed some DAOs to take ids and added a friends feed getter --- .../be/ugent/sel/studeez/domain/FeedDAO.kt | 3 + .../be/ugent/sel/studeez/domain/SessionDAO.kt | 6 +- .../be/ugent/sel/studeez/domain/SubjectDAO.kt | 1 + .../domain/implementation/FirebaseFeedDAO.kt | 66 +++++++++++++++++-- .../implementation/FirebaseSessionDAO.kt | 22 +------ .../implementation/FirebaseSubjectDAO.kt | 13 ++-- 6 files changed, 75 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/FeedDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/FeedDAO.kt index 2d91781..e9e95b9 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/FeedDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/FeedDAO.kt @@ -7,4 +7,7 @@ interface FeedDAO { fun getFeedEntries(): Flow>> + suspend fun getFeedEntriesFromUser(id: String): Map> + + fun getFriendsSessions(): Flow>>> } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/SessionDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/SessionDAO.kt index 53d6996..4ac2891 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/SessionDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/SessionDAO.kt @@ -1,5 +1,6 @@ package be.ugent.sel.studeez.domain +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.User import be.ugent.sel.studeez.data.local.models.task.Task @@ -11,11 +12,6 @@ interface SessionDAO { fun getSessions(): Flow> suspend fun getSessionsOfUser(userId: String): List - /** - * Return a list of pairs, containing the username and all the studysessions of that user. - */ - fun getFriendsSessions(): Flow>>> - fun saveSession(newSessionReport: SessionReport) fun deleteSession(newTimer: TimerInfo) diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/SubjectDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/SubjectDAO.kt index d887ef5..7b89bba 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/SubjectDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/SubjectDAO.kt @@ -20,4 +20,5 @@ interface SubjectDAO { fun getStudyTime(subject: Subject): Flow suspend fun getSubject(subjectId: String): Subject? + suspend fun getSubjectOfUSer(subjectId: String, userId: String): Subject } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseFeedDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseFeedDAO.kt index 6c445bf..be4893d 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseFeedDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseFeedDAO.kt @@ -5,19 +5,19 @@ 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.SubjectDAO -import be.ugent.sel.studeez.domain.TaskDAO +import be.ugent.sel.studeez.domain.* import com.google.firebase.Timestamp import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import javax.inject.Inject class FirebaseFeedDAO @Inject constructor( + private val friendshipDAO: FriendshipDAO, private val sessionDAO: SessionDAO, private val taskDAO: TaskDAO, - private val subjectDAO: SubjectDAO + private val subjectDAO: SubjectDAO, + private val auth: AccountDAO, + private val userDAO: UserDAO, ) : FeedDAO { /** @@ -37,6 +37,45 @@ class FirebaseFeedDAO @Inject constructor( } } + /** + * Return a map as with key the day and value a list of feedentries for that day. + */ + override suspend fun getFeedEntriesFromUser(id: String): Map> { + return sessionDAO.getSessionsOfUser(id) + .map { sessionReport -> sessionToFeedEntryFromUser(sessionReport, id) } + .sortedByDescending { it.endTime } + .groupBy { getFormattedTime(it) } + .mapValues { (_, entries) -> + entries + .groupBy { it.taskId } + .map { fuseFeedEntries(it.component2()) } + } + } + + override fun getFriendsSessions(): Flow>>> { + return friendshipDAO.getAllFriendships(auth.currentUserId) + .map { friendships -> + friendships.map { friendship -> + val userId: String = friendship.friendId + val username = userDAO.getUsername(userId) + val friendFeed = getFeedEntriesFromUser(userId) + Pair(username, friendFeed) + } + }.map { + mergeNameAndEntries(it) + } + } + + private fun mergeNameAndEntries(l: List>>>): Map>> { + val new: MutableMap>> = mutableMapOf() + for ((name, map) in l) { + for ((day, feedEntries: List) in map) { + new[day] = new.getOrDefault(day, listOf()) + feedEntries.map { Pair(name, it) } + } + } + return new + } + private fun getFormattedTime(entry: FeedEntry): String { return DateFormat.getDateInstance().format(entry.endTime.toDate()) } @@ -67,6 +106,10 @@ class FirebaseFeedDAO @Inject constructor( val task: Task = taskDAO.getTask(subjectId, taskId) val subject: Subject = subjectDAO.getSubject(subjectId)!! + return makeFeedEntry(sessionReport, subject, task) + } + + private fun makeFeedEntry(sessionReport: SessionReport, subject: Subject, task: Task): FeedEntry { return FeedEntry( argb_color = subject.argb_color, subJectName = subject.name, @@ -78,4 +121,17 @@ class FirebaseFeedDAO @Inject constructor( isArchived = task.archived || subject.archived ) } + + /** + * Convert a sessionReport to a feedEntry. Fetch Task and Subject to get names + */ + private suspend fun sessionToFeedEntryFromUser(sessionReport: SessionReport, id: String): FeedEntry { + val subjectId: String = sessionReport.subjectId + val taskId: String = sessionReport.taskId + + val task: Task = taskDAO.getTaskFromUser(subjectId, taskId, id) + val subject: Subject = subjectDAO.getSubjectOfUSer(subjectId, id) + + return makeFeedEntry(sessionReport, subject, task) + } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSessionDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSessionDAO.kt index 7072de6..df271c6 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSessionDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSessionDAO.kt @@ -1,5 +1,6 @@ package be.ugent.sel.studeez.domain.implementation +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.User import be.ugent.sel.studeez.data.local.models.task.Task @@ -25,9 +26,6 @@ import javax.inject.Inject class FirebaseSessionDAO @Inject constructor( private val firestore: FirebaseFirestore, private val auth: AccountDAO, - private val userDAO: UserDAO, - private val friendshipDAO: FriendshipDAO, - private val taskDAO: TaskDAO, ) : SessionDAO { override fun getSessions(): Flow> { @@ -44,24 +42,6 @@ class FirebaseSessionDAO @Inject constructor( .map { it.toObject(SessionReport::class.java) } } - override fun getFriendsSessions(): Flow>>> { - return friendshipDAO.getAllFriendships(auth.currentUserId) - .map { friendships -> - friendships.map { friendship -> - val userId: String = friendship.friendId - val username = userDAO.getUsername(userId) - val userTasks = getSessionsOfUser(userId) - .map { sessionReport -> - taskDAO.getTaskFromUser( - sessionReport.subjectId, - sessionReport.taskId, - userId - ) - } - Pair(username, userTasks) - } - } - } override fun saveSession(newSessionReport: SessionReport) { currentUserSessionsCollection().add(newSessionReport) diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSubjectDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSubjectDAO.kt index f1571d7..65c11a5 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSubjectDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseSubjectDAO.kt @@ -1,6 +1,5 @@ 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.SubjectDocument import be.ugent.sel.studeez.data.local.models.task.Task @@ -35,6 +34,10 @@ class FirebaseSubjectDAO @Inject constructor( return currentUserSubjectsCollection().document(subjectId).get().await().toObject() } + override suspend fun getSubjectOfUSer(subjectId: String, userId: String): Subject { + return currentUserSubjectsCollection(userId).document(subjectId).get().await().toObject()!! + } + override fun saveSubject(newSubject: Subject) { currentUserSubjectsCollection().add(newSubject) } @@ -74,14 +77,14 @@ class FirebaseSubjectDAO @Inject constructor( .map { tasks -> tasks.sumOf { it.time } } } - private fun currentUserSubjectsCollection(): CollectionReference = + private fun currentUserSubjectsCollection(id: String = auth.currentUserId): CollectionReference = firestore.collection(FirebaseCollections.USER_COLLECTION) - .document(auth.currentUserId) + .document(id) .collection(FirebaseCollections.SUBJECT_COLLECTION) - private fun subjectTasksCollection(subject: Subject): CollectionReference = + private fun subjectTasksCollection(subject: Subject, id: String = auth.currentUserId): CollectionReference = firestore.collection(FirebaseCollections.USER_COLLECTION) - .document(auth.currentUserId) + .document(id) .collection(FirebaseCollections.SUBJECT_COLLECTION) .document(subject.id) .collection(FirebaseCollections.TASK_COLLECTION) From bd9fce4418fa615ed3f46a58d0af2ed4dd709adf Mon Sep 17 00:00:00 2001 From: lbarraga Date: Tue, 16 May 2023 10:06:04 +0200 Subject: [PATCH 4/6] changed sessions to feed --- .../java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt | 2 +- .../java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt index 578c74a..32ad7ff 100644 --- a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezDestinations.kt @@ -4,7 +4,7 @@ object StudeezDestinations { // NavBar const val HOME_SCREEN = "home" const val SUBJECT_SCREEN = "subjects" - const val SESSIONS_SCREEN = "sessions" + const val FRIENDS_FEED = "friends_feed" const val PROFILE_SCREEN = "profile" // Drawer diff --git a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt index 1953d03..067896e 100644 --- a/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt +++ b/app/src/main/java/be/ugent/sel/studeez/navigation/StudeezNavGraph.kt @@ -127,7 +127,7 @@ fun StudeezNavGraph( } - composable(StudeezDestinations.SESSIONS_SCREEN) { + composable(StudeezDestinations.FRIENDS_FEED) { FriendsFeedRoute( drawerActions = drawerActions, navigationBarActions = navigationBarActions, From f5ae4f157cb8e2d6c180d1f9cecf7c49ce4dfa1f Mon Sep 17 00:00:00 2001 From: lbarraga Date: Tue, 16 May 2023 10:06:24 +0200 Subject: [PATCH 5/6] implemented friends feed --- .../screens/friends_feed/FriendsFeedScreen.kt | 87 +++++++++++++++++-- .../friends_feed/FriendsFeedViewModel.kt | 10 ++- 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedScreen.kt index 62e7050..ced14b3 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedScreen.kt @@ -1,20 +1,36 @@ package be.ugent.sel.studeez.screens.friends_feed -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.Card import androidx.compose.material.Divider import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState +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.unit.dp +import androidx.compose.ui.unit.sp +import be.ugent.sel.studeez.common.composable.DateText import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate +import be.ugent.sel.studeez.common.composable.StealthButton import be.ugent.sel.studeez.common.composable.TimerEntry import be.ugent.sel.studeez.common.composable.drawer.DrawerActions import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions +import be.ugent.sel.studeez.common.ext.spacer +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.Task import be.ugent.sel.studeez.data.local.models.timer_functional.HoursMinutesSeconds import be.ugent.sel.studeez.resources +import kotlinx.coroutines.flow.toList import be.ugent.sel.studeez.R.string as AppText @Composable @@ -37,17 +53,25 @@ fun FriendsFeedScreen( viewModel: FriendsFeedViewModel ) { PrimaryScreenTemplate( - title = resources().getString(AppText.upcoming_sessions), + title = resources().getString(AppText.friends_feed), drawerActions = drawerActions, navigationBarActions = navigationBarActions ) { val friendsSessions = viewModel.getFriendsSessions().collectAsState(initial = emptyList()) + + + + LazyColumn() { // Default Timers, cannot be edited items(friendsSessions.value) { - FriendsFeedEntry(name = it.first, sessions = it.second) - Divider() + val (day, feedEntries) = it + DateText(date = day) + feedEntries.forEach { (name, feedEntry) -> + FriendsFeedEntry(name = name, feedEntry = feedEntry) + } + Spacer(modifier = Modifier.height(10.dp)) } } @@ -55,11 +79,56 @@ fun FriendsFeedScreen( } @Composable -fun FriendsFeedEntry(name: String, sessions: List) { - Column() { - Text(text = "$name Werkte ") - sessions.forEach { - Text(text = "${HoursMinutesSeconds(it.time)} aan ${it.name}") +fun FriendsFeedEntry( + name: String, + feedEntry: FeedEntry +) { + 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 = "$name studied for ${feedEntry.subJectName}", + fontWeight = FontWeight.Medium, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + ) + Text( + text = feedEntry.taskName, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + ) + } + Text(text = HoursMinutesSeconds(feedEntry.totalStudyTime).toString()) + } + } + } } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedViewModel.kt index 6426161..d4ae2dc 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/friends_feed/FriendsFeedViewModel.kt @@ -1,21 +1,25 @@ package be.ugent.sel.studeez.screens.friends_feed +import be.ugent.sel.studeez.data.local.models.FeedEntry import be.ugent.sel.studeez.data.local.models.task.Task +import be.ugent.sel.studeez.domain.FeedDAO import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.domain.SessionDAO import be.ugent.sel.studeez.screens.StudeezViewModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toList import javax.inject.Inject @HiltViewModel class FriendsFeedViewModel @Inject constructor( - private val sessionDAO: SessionDAO, + private val feedDAO: FeedDAO, logService: LogService ) : StudeezViewModel(logService) { - fun getFriendsSessions(): Flow>>> { - return sessionDAO.getFriendsSessions() + fun getFriendsSessions(): Flow>>>> { + return feedDAO.getFriendsSessions().map { it.toList() } } From c61853b8bd7a98bf7965103be7259b0d01b6accc Mon Sep 17 00:00:00 2001 From: lbarraga Date: Tue, 16 May 2023 10:06:46 +0200 Subject: [PATCH 6/6] added friends feed string resources --- app/src/main/res/values/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f7d2666..2f8896b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -36,6 +36,9 @@ This is your feed Click here to create you first subject and tasks to get started + + Feed + Tasks Task