commit
373a0e6209
16 changed files with 271 additions and 96 deletions
|
@ -8,13 +8,15 @@ import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
import androidx.compose.material.icons.filled.List
|
import androidx.compose.material.icons.filled.List
|
||||||
import androidx.compose.material.icons.filled.Person
|
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.DateRange
|
||||||
|
import androidx.compose.material.icons.outlined.Face
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
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 be.ugent.sel.studeez.navigation.StudeezDestinations.FRIENDS_FEED
|
||||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN
|
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.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.navigation.StudeezDestinations.SUBJECT_SCREEN
|
||||||
import be.ugent.sel.studeez.resources
|
import be.ugent.sel.studeez.resources
|
||||||
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
import be.ugent.sel.studeez.ui.theme.StudeezTheme
|
||||||
|
@ -99,11 +101,11 @@ fun NavigationBar(
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
icon = {
|
icon = {
|
||||||
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)) },
|
label = { Text(text = resources().getString(AppText.friends_feed)) },
|
||||||
selected = navigationBarActions.isSelectedTab(SESSIONS_SCREEN),
|
selected = navigationBarActions.isSelectedTab(FRIENDS_FEED),
|
||||||
onClick = navigationBarActions.onSessionsClick
|
onClick = navigationBarActions.onSessionsClick
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package be.ugent.sel.studeez.common.composable.navbar
|
||||||
|
|
||||||
import be.ugent.sel.studeez.common.snackbar.SnackbarManager
|
import be.ugent.sel.studeez.common.snackbar.SnackbarManager
|
||||||
import be.ugent.sel.studeez.domain.LogService
|
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.HOME_SCREEN
|
||||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN
|
import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN
|
||||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.SEARCH_FRIENDS_SCREEN
|
import be.ugent.sel.studeez.navigation.StudeezDestinations.SEARCH_FRIENDS_SCREEN
|
||||||
|
@ -27,7 +28,7 @@ class NavigationBarViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSessionsClick(open: (String) -> Unit) {
|
fun onSessionsClick(open: (String) -> Unit) {
|
||||||
open(SESSIONS_SCREEN)
|
open(FRIENDS_FEED)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onProfileClick(open: (String) -> Unit) {
|
fun onProfileClick(open: (String) -> Unit) {
|
||||||
|
|
|
@ -7,4 +7,7 @@ interface FeedDAO {
|
||||||
|
|
||||||
fun getFeedEntries(): Flow<Map<String, List<FeedEntry>>>
|
fun getFeedEntries(): Flow<Map<String, List<FeedEntry>>>
|
||||||
|
|
||||||
|
suspend fun getFeedEntriesFromUser(id: String): Map<String, List<FeedEntry>>
|
||||||
|
|
||||||
|
fun getFriendsSessions(): Flow<Map<String, List<Pair<String, FeedEntry>>>>
|
||||||
}
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
package be.ugent.sel.studeez.domain
|
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.SessionReport
|
||||||
import be.ugent.sel.studeez.data.local.models.User
|
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.local.models.timer_info.TimerInfo
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@ -10,11 +12,6 @@ interface SessionDAO {
|
||||||
fun getSessions(): Flow<List<SessionReport>>
|
fun getSessions(): Flow<List<SessionReport>>
|
||||||
suspend fun getSessionsOfUser(userId: String): List<SessionReport>
|
suspend fun getSessionsOfUser(userId: String): List<SessionReport>
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a list of pairs, containing the username and all the studysessions of that user.
|
|
||||||
*/
|
|
||||||
fun getFriendsSessions(): Flow<List<Pair<String,List<SessionReport>>>>
|
|
||||||
|
|
||||||
fun saveSession(newSessionReport: SessionReport)
|
fun saveSession(newSessionReport: SessionReport)
|
||||||
|
|
||||||
fun deleteSession(newTimer: TimerInfo)
|
fun deleteSession(newTimer: TimerInfo)
|
||||||
|
|
|
@ -20,4 +20,5 @@ interface SubjectDAO {
|
||||||
fun getStudyTime(subject: Subject): Flow<Int>
|
fun getStudyTime(subject: Subject): Flow<Int>
|
||||||
|
|
||||||
suspend fun getSubject(subjectId: String): Subject?
|
suspend fun getSubject(subjectId: String): Subject?
|
||||||
|
suspend fun getSubjectOfUSer(subjectId: String, userId: String): Subject
|
||||||
}
|
}
|
|
@ -15,4 +15,6 @@ interface TaskDAO {
|
||||||
fun deleteTask(oldTask: Task)
|
fun deleteTask(oldTask: Task)
|
||||||
|
|
||||||
suspend fun getTask(subjectId: String, taskId: String): Task
|
suspend fun getTask(subjectId: String, taskId: String): Task
|
||||||
|
|
||||||
|
suspend fun getTaskFromUser(subjectId: String, taskId: String, userId: String): Task
|
||||||
}
|
}
|
|
@ -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.SessionReport
|
||||||
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.Task
|
import be.ugent.sel.studeez.data.local.models.task.Task
|
||||||
import be.ugent.sel.studeez.domain.FeedDAO
|
import be.ugent.sel.studeez.domain.*
|
||||||
import be.ugent.sel.studeez.domain.SessionDAO
|
|
||||||
import be.ugent.sel.studeez.domain.SubjectDAO
|
|
||||||
import be.ugent.sel.studeez.domain.TaskDAO
|
|
||||||
import com.google.firebase.Timestamp
|
import com.google.firebase.Timestamp
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class FirebaseFeedDAO @Inject constructor(
|
class FirebaseFeedDAO @Inject constructor(
|
||||||
|
private val friendshipDAO: FriendshipDAO,
|
||||||
private val sessionDAO: SessionDAO,
|
private val sessionDAO: SessionDAO,
|
||||||
private val taskDAO: TaskDAO,
|
private val taskDAO: TaskDAO,
|
||||||
private val subjectDAO: SubjectDAO
|
private val subjectDAO: SubjectDAO,
|
||||||
|
private val auth: AccountDAO,
|
||||||
|
private val userDAO: UserDAO,
|
||||||
) : FeedDAO {
|
) : 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<String, List<FeedEntry>> {
|
||||||
|
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<Map<String, List<Pair<String, FeedEntry>>>> {
|
||||||
|
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<Pair<String, Map<String, List<FeedEntry>>>>): Map<String, List<Pair<String, FeedEntry>>> {
|
||||||
|
val new: MutableMap<String, List<Pair<String, FeedEntry>>> = mutableMapOf()
|
||||||
|
for ((name, map) in l) {
|
||||||
|
for ((day, feedEntries: List<FeedEntry>) in map) {
|
||||||
|
new[day] = new.getOrDefault(day, listOf()) + feedEntries.map { Pair(name, it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
|
||||||
private fun getFormattedTime(entry: FeedEntry): String {
|
private fun getFormattedTime(entry: FeedEntry): String {
|
||||||
return DateFormat.getDateInstance().format(entry.endTime.toDate())
|
return DateFormat.getDateInstance().format(entry.endTime.toDate())
|
||||||
}
|
}
|
||||||
|
@ -67,6 +106,10 @@ class FirebaseFeedDAO @Inject constructor(
|
||||||
val task: Task = taskDAO.getTask(subjectId, taskId)
|
val task: Task = taskDAO.getTask(subjectId, taskId)
|
||||||
val subject: Subject = subjectDAO.getSubject(subjectId)!!
|
val subject: Subject = subjectDAO.getSubject(subjectId)!!
|
||||||
|
|
||||||
|
return makeFeedEntry(sessionReport, subject, task)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeFeedEntry(sessionReport: SessionReport, subject: Subject, task: Task): FeedEntry {
|
||||||
return FeedEntry(
|
return FeedEntry(
|
||||||
argb_color = subject.argb_color,
|
argb_color = subject.argb_color,
|
||||||
subJectName = subject.name,
|
subJectName = subject.name,
|
||||||
|
@ -78,4 +121,17 @@ class FirebaseFeedDAO @Inject constructor(
|
||||||
isArchived = task.archived || subject.archived
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,15 +1,14 @@
|
||||||
package be.ugent.sel.studeez.domain.implementation
|
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.SessionReport
|
||||||
import be.ugent.sel.studeez.data.local.models.User
|
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.local.models.timer_info.TimerInfo
|
||||||
import be.ugent.sel.studeez.data.remote.FirebaseSessionReport
|
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.ENDTIME
|
||||||
import be.ugent.sel.studeez.data.remote.FirebaseSessionReport.STUDYTIME
|
import be.ugent.sel.studeez.data.remote.FirebaseSessionReport.STUDYTIME
|
||||||
import be.ugent.sel.studeez.domain.AccountDAO
|
import be.ugent.sel.studeez.domain.*
|
||||||
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.implementation.FirebaseCollections.SESSION_COLLECTION
|
import be.ugent.sel.studeez.domain.implementation.FirebaseCollections.SESSION_COLLECTION
|
||||||
import be.ugent.sel.studeez.domain.implementation.FirebaseCollections.USER_COLLECTION
|
import be.ugent.sel.studeez.domain.implementation.FirebaseCollections.USER_COLLECTION
|
||||||
import com.google.firebase.Timestamp
|
import com.google.firebase.Timestamp
|
||||||
|
@ -17,6 +16,7 @@ import com.google.firebase.firestore.CollectionReference
|
||||||
import com.google.firebase.firestore.FirebaseFirestore
|
import com.google.firebase.firestore.FirebaseFirestore
|
||||||
import com.google.firebase.firestore.ktx.getField
|
import com.google.firebase.firestore.ktx.getField
|
||||||
import com.google.firebase.firestore.ktx.snapshots
|
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.emptyFlow
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
@ -26,8 +26,6 @@ import javax.inject.Inject
|
||||||
class FirebaseSessionDAO @Inject constructor(
|
class FirebaseSessionDAO @Inject constructor(
|
||||||
private val firestore: FirebaseFirestore,
|
private val firestore: FirebaseFirestore,
|
||||||
private val auth: AccountDAO,
|
private val auth: AccountDAO,
|
||||||
private val userDAO: UserDAO,
|
|
||||||
private val friendshipDAO: FriendshipDAO
|
|
||||||
) : SessionDAO {
|
) : SessionDAO {
|
||||||
|
|
||||||
override fun getSessions(): Flow<List<SessionReport>> {
|
override fun getSessions(): Flow<List<SessionReport>> {
|
||||||
|
@ -37,32 +35,13 @@ class FirebaseSessionDAO @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getSessionsOfUser(userId: String): List<SessionReport> {
|
override suspend fun getSessionsOfUser(userId: String): List<SessionReport> {
|
||||||
val collection = firestore.collection(USER_COLLECTION)
|
return firestore.collection(USER_COLLECTION)
|
||||||
.document(userId)
|
.document(userId)
|
||||||
.collection(SESSION_COLLECTION)
|
.collection(SESSION_COLLECTION)
|
||||||
.get().await()
|
.get().await()
|
||||||
val list: MutableList<SessionReport> = mutableListOf()
|
.map { it.toObject(SessionReport::class.java) }
|
||||||
for (document in collection) {
|
|
||||||
val id = document.id
|
|
||||||
val studyTime: Int = document.getField<Int>(STUDYTIME)!!
|
|
||||||
val endTime: Timestamp = document.getField<Timestamp>(ENDTIME)!!
|
|
||||||
list.add(SessionReport(id, studyTime, endTime))
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFriendsSessions(): Flow<List<Pair<String, List<SessionReport>>>> {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun saveSession(newSessionReport: SessionReport) {
|
override fun saveSession(newSessionReport: SessionReport) {
|
||||||
currentUserSessionsCollection().add(newSessionReport)
|
currentUserSessionsCollection().add(newSessionReport)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
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.Task
|
||||||
|
@ -35,6 +34,10 @@ class FirebaseSubjectDAO @Inject constructor(
|
||||||
return currentUserSubjectsCollection().document(subjectId).get().await().toObject()
|
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) {
|
override fun saveSubject(newSubject: Subject) {
|
||||||
currentUserSubjectsCollection().add(newSubject)
|
currentUserSubjectsCollection().add(newSubject)
|
||||||
}
|
}
|
||||||
|
@ -74,14 +77,14 @@ class FirebaseSubjectDAO @Inject constructor(
|
||||||
.map { tasks -> tasks.sumOf { it.time } }
|
.map { tasks -> tasks.sumOf { it.time } }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun currentUserSubjectsCollection(): CollectionReference =
|
private fun currentUserSubjectsCollection(id: String = auth.currentUserId): CollectionReference =
|
||||||
firestore.collection(FirebaseCollections.USER_COLLECTION)
|
firestore.collection(FirebaseCollections.USER_COLLECTION)
|
||||||
.document(auth.currentUserId)
|
.document(id)
|
||||||
.collection(FirebaseCollections.SUBJECT_COLLECTION)
|
.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)
|
firestore.collection(FirebaseCollections.USER_COLLECTION)
|
||||||
.document(auth.currentUserId)
|
.document(id)
|
||||||
.collection(FirebaseCollections.SUBJECT_COLLECTION)
|
.collection(FirebaseCollections.SUBJECT_COLLECTION)
|
||||||
.document(subject.id)
|
.document(subject.id)
|
||||||
.collection(FirebaseCollections.TASK_COLLECTION)
|
.collection(FirebaseCollections.TASK_COLLECTION)
|
||||||
|
|
|
@ -30,6 +30,13 @@ class FirebaseTaskDAO @Inject constructor(
|
||||||
return selectedSubjectTasksCollection(subjectId).document(taskId).get().await().toObject()!!
|
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) {
|
override fun saveTask(newTask: Task) {
|
||||||
selectedSubjectTasksCollection(newTask.subjectId).add(newTask)
|
selectedSubjectTasksCollection(newTask.subjectId).add(newTask)
|
||||||
}
|
}
|
||||||
|
@ -44,9 +51,9 @@ class FirebaseTaskDAO @Inject constructor(
|
||||||
selectedSubjectTasksCollection(oldTask.subjectId).document(oldTask.id).delete()
|
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)
|
firestore.collection(FirebaseCollections.USER_COLLECTION)
|
||||||
.document(auth.currentUserId)
|
.document(id)
|
||||||
.collection(FirebaseCollections.SUBJECT_COLLECTION)
|
.collection(FirebaseCollections.SUBJECT_COLLECTION)
|
||||||
.document(subjectId)
|
.document(subjectId)
|
||||||
.collection(FirebaseCollections.TASK_COLLECTION)
|
.collection(FirebaseCollections.TASK_COLLECTION)
|
||||||
|
|
|
@ -4,7 +4,7 @@ object StudeezDestinations {
|
||||||
// NavBar
|
// NavBar
|
||||||
const val HOME_SCREEN = "home"
|
const val HOME_SCREEN = "home"
|
||||||
const val SUBJECT_SCREEN = "subjects"
|
const val SUBJECT_SCREEN = "subjects"
|
||||||
const val SESSIONS_SCREEN = "sessions"
|
const val FRIENDS_FEED = "friends_feed"
|
||||||
const val PROFILE_SCREEN = "profile"
|
const val PROFILE_SCREEN = "profile"
|
||||||
|
|
||||||
// Drawer
|
// Drawer
|
||||||
|
|
|
@ -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.common.composable.navbar.getNavigationBarActions
|
||||||
import be.ugent.sel.studeez.screens.friends.friends_overview.FriendsOveriewRoute
|
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.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.home.HomeRoute
|
||||||
import be.ugent.sel.studeez.screens.log_in.LoginRoute
|
import be.ugent.sel.studeez.screens.log_in.LoginRoute
|
||||||
import be.ugent.sel.studeez.screens.profile.edit_profile.EditProfileRoute
|
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.profile.public_profile.PublicProfileRoute
|
||||||
import be.ugent.sel.studeez.screens.session.SessionRoute
|
import be.ugent.sel.studeez.screens.session.SessionRoute
|
||||||
import be.ugent.sel.studeez.screens.session_recap.SessionRecapRoute
|
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.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
|
||||||
|
@ -135,10 +136,11 @@ fun StudeezNavGraph(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
composable(StudeezDestinations.SESSIONS_SCREEN) {
|
composable(StudeezDestinations.FRIENDS_FEED) {
|
||||||
SessionsRoute(
|
FriendsFeedRoute(
|
||||||
drawerActions = drawerActions,
|
drawerActions = drawerActions,
|
||||||
navigationBarActions = navigationBarActions
|
navigationBarActions = navigationBarActions,
|
||||||
|
viewModel = hiltViewModel()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
package be.ugent.sel.studeez.screens.friends_feed
|
||||||
|
|
||||||
|
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
|
||||||
|
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.friends_feed),
|
||||||
|
drawerActions = drawerActions,
|
||||||
|
navigationBarActions = navigationBarActions
|
||||||
|
) {
|
||||||
|
|
||||||
|
val friendsSessions = viewModel.getFriendsSessions().collectAsState(initial = emptyList())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LazyColumn() {
|
||||||
|
// Default Timers, cannot be edited
|
||||||
|
items(friendsSessions.value) {
|
||||||
|
val (day, feedEntries) = it
|
||||||
|
DateText(date = day)
|
||||||
|
feedEntries.forEach { (name, feedEntry) ->
|
||||||
|
FriendsFeedEntry(name = name, feedEntry = feedEntry)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
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 feedDAO: FeedDAO,
|
||||||
|
logService: LogService
|
||||||
|
) : StudeezViewModel(logService) {
|
||||||
|
|
||||||
|
fun getFriendsSessions(): Flow<List<Pair<String, List<Pair<String, FeedEntry>>>>> {
|
||||||
|
return feedDAO.getFriendsSessions().map { it.toList() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -36,6 +36,9 @@
|
||||||
<string name="your_feed">This is your feed</string>
|
<string name="your_feed">This is your feed</string>
|
||||||
<string name="empty_feed_help_text">Click here to create you first subject and tasks to get started</string>
|
<string name="empty_feed_help_text">Click here to create you first subject and tasks to get started</string>
|
||||||
|
|
||||||
|
<!-- Friends Feed -->
|
||||||
|
<string name="friends_feed">Feed</string>
|
||||||
|
|
||||||
<!-- Tasks -->
|
<!-- Tasks -->
|
||||||
<string name="tasks">Tasks</string>
|
<string name="tasks">Tasks</string>
|
||||||
<string name="task">Task</string>
|
<string name="task">Task</string>
|
||||||
|
|
Reference in a new issue