diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/ProfilePictureComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/ProfilePictureComposable.kt new file mode 100644 index 0000000..c214088 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/ProfilePictureComposable.kt @@ -0,0 +1,44 @@ +package be.ugent.sel.studeez.common.composable + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Person +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.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import be.ugent.sel.studeez.R +import be.ugent.sel.studeez.ui.theme.StudeezTheme + +@Composable +fun ProfilePicture() { + Box( + modifier = Modifier + .size(40.dp) + .background(MaterialTheme.colors.primary, CircleShape) + ) { + Icon( + imageVector = Icons.Default.Person, + contentDescription = stringResource(id = R.string.username), + modifier = Modifier + .size(30.dp) + .align(Alignment.Center), + tint = MaterialTheme.colors.onPrimary + ) + } +} + +@Preview +@Composable +fun ProfilePicturePreview() { + StudeezTheme { + ProfilePicture() + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/data/remote/FirebaseSessionReport.kt b/app/src/main/java/be/ugent/sel/studeez/data/remote/FirebaseSessionReport.kt new file mode 100644 index 0000000..f33718f --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/data/remote/FirebaseSessionReport.kt @@ -0,0 +1,6 @@ +package be.ugent.sel.studeez.data.remote + +object FirebaseSessionReport { + const val STUDYTIME: String = "studyTime" + const val ENDTIME: String = "endTime" +} \ 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 77087d2..bb233e9 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,12 +1,19 @@ 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.timer_info.TimerInfo import kotlinx.coroutines.flow.Flow 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) diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/UserDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/UserDAO.kt index 09179f1..80a7689 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/UserDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/UserDAO.kt @@ -27,6 +27,10 @@ interface UserDAO { userId: String ): Flow + suspend fun getUsername( + userId: String + ): String + /** * @return information on the currently logged in user. */ 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 ca7c6aa..e7cb763 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,19 +1,33 @@ 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.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.implementation.FirebaseCollections.SESSION_COLLECTION +import be.ugent.sel.studeez.domain.implementation.FirebaseCollections.USER_COLLECTION +import com.google.firebase.Timestamp 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 kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.tasks.await import javax.inject.Inject class FirebaseSessionDAO @Inject constructor( private val firestore: FirebaseFirestore, - private val auth: AccountDAO + private val auth: AccountDAO, + private val userDAO: UserDAO, + private val friendshipDAO: FriendshipDAO ) : SessionDAO { override fun getSessions(): Flow> { @@ -22,6 +36,34 @@ class FirebaseSessionDAO @Inject constructor( .map { it.toObjects(SessionReport::class.java) } } + override suspend fun getSessionsOfUser(userId: String): List { + val collection = 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 + } + + 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) + } + } + } + override fun saveSession(newSessionReport: SessionReport) { currentUserSessionsCollection().add(newSessionReport) } @@ -31,7 +73,7 @@ class FirebaseSessionDAO @Inject constructor( } private fun currentUserSessionsCollection(): CollectionReference = - firestore.collection(FirebaseCollections.USER_COLLECTION) + firestore.collection(USER_COLLECTION) .document(auth.currentUserId) - .collection(FirebaseCollections.SESSION_COLLECTION) + .collection(SESSION_COLLECTION) } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseUserDAO.kt b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseUserDAO.kt index f41fcd9..04239c0 100644 --- a/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseUserDAO.kt +++ b/app/src/main/java/be/ugent/sel/studeez/domain/implementation/FirebaseUserDAO.kt @@ -61,6 +61,13 @@ class FirebaseUserDAO @Inject constructor( } } + override suspend fun getUsername(userId: String): String { + val user = firestore.collection(USER_COLLECTION) + .document(userId) + .get().await() + return user.getString(USERNAME)!! + } + override suspend fun getLoggedInUser(): User { val userDocument = currentUserDocument().get().await() return User( diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_overview/FriendsOverviewScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_overview/FriendsOverviewScreen.kt index 7e2462d..8ea6d20 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_overview/FriendsOverviewScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_overview/FriendsOverviewScreen.kt @@ -14,7 +14,6 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.style.TextOverflow @@ -23,6 +22,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import be.ugent.sel.studeez.R import be.ugent.sel.studeez.common.composable.BasicButton +import be.ugent.sel.studeez.common.composable.ProfilePicture import be.ugent.sel.studeez.common.composable.SearchField import be.ugent.sel.studeez.common.composable.drawer.DrawerEntry import be.ugent.sel.studeez.common.ext.basicButton @@ -162,29 +162,21 @@ fun FriendsEntry( viewProfile: (String) -> Unit, removeFriend: (Friendship) -> Unit ) { - // TODO Styling Row ( modifier = Modifier .fillMaxWidth() + .padding(horizontal = 15.dp, vertical = 7.dp), ) { Box( modifier = Modifier - .fillMaxWidth(0.15f) - .background(MaterialTheme.colors.primary, CircleShape) + .padding(vertical = 4.dp) ) { - Icon( - painter = painterResource(id = R.drawable.ic_visibility_on), - contentDescription = null, - modifier = Modifier - .fillMaxHeight() - .align(Alignment.Center), - tint = MaterialTheme.colors.onPrimary - ) + ProfilePicture() } Box ( modifier = Modifier - .fillMaxWidth(0.65f) + .fillMaxWidth() ) { Column ( modifier = Modifier @@ -203,16 +195,17 @@ fun FriendsEntry( overflow = TextOverflow.Ellipsis ) } - } - Box( - modifier = Modifier.fillMaxWidth(0.15f) - ) { - FriendsOverviewDropDown( - friendship = friendship, - viewProfile = viewProfile, - removeFriend = removeFriend - ) + Box( + modifier = Modifier.fillMaxWidth(), + contentAlignment = Alignment.CenterEnd + ) { + FriendsOverviewDropDown( + friendship = friendship, + viewProfile = viewProfile, + removeFriend = removeFriend + ) + } } } } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_search/SearchFriendsScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_search/SearchFriendsScreen.kt index a91d0f4..e84bb9f 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_search/SearchFriendsScreen.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_search/SearchFriendsScreen.kt @@ -13,7 +13,6 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.style.TextOverflow @@ -21,12 +20,14 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import be.ugent.sel.studeez.R +import be.ugent.sel.studeez.common.composable.ProfilePicture import be.ugent.sel.studeez.common.composable.SearchField import be.ugent.sel.studeez.common.composable.drawer.DrawerEntry import be.ugent.sel.studeez.data.local.models.User import be.ugent.sel.studeez.resources import be.ugent.sel.studeez.ui.theme.StudeezTheme -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf import be.ugent.sel.studeez.R.string as AppText data class SearchFriendsActions( @@ -153,25 +154,19 @@ fun UserEntry( Row( modifier = Modifier .fillMaxWidth() + .padding(horizontal = 15.dp, vertical = 7.dp), + horizontalArrangement = Arrangement.spacedBy(15.dp) ) { Box( modifier = Modifier - .fillMaxWidth(0.15f) - .background(MaterialTheme.colors.primary, CircleShape) + .padding(vertical = 4.dp) ) { - Icon( - painter = painterResource(id = R.drawable.ic_visibility_on), - contentDescription = null, - modifier = Modifier - .fillMaxHeight() - .align(Alignment.Center), - tint = MaterialTheme.colors.onPrimary - ) + ProfilePicture() } Box ( modifier = Modifier - .fillMaxWidth(0.65f) + .fillMaxWidth() ) { Column ( modifier = Modifier @@ -190,15 +185,16 @@ fun UserEntry( overflow = TextOverflow.Ellipsis ) } - } - Box( - modifier = Modifier.fillMaxWidth(0.15f) - ) { - SearchFriendsDropDown( - user = user, - goToProfile = goToProfile - ) + Box( + modifier = Modifier.fillMaxWidth(), + contentAlignment = Alignment.CenterEnd + ) { + SearchFriendsDropDown( + user = user, + goToProfile = goToProfile + ) + } } } } diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_search/SearchFriendsViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_search/SearchFriendsViewModel.kt index a25e1a7..11aecd7 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_search/SearchFriendsViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/friends/friends_search/SearchFriendsViewModel.kt @@ -10,6 +10,7 @@ import be.ugent.sel.studeez.screens.StudeezViewModel import be.ugent.sel.studeez.screens.profile.public_profile.SelectedProfileState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter import javax.inject.Inject @HiltViewModel @@ -43,8 +44,16 @@ class SearchFriendsViewModel @Inject constructor( ) } + /** + * Get all users, except for the current user. + */ fun getAllUsers(): Flow> { return userDAO.getAllUsers() + .filter { users -> + users.any { user -> + user.id != userDAO.getCurrentUserId() + } + } } fun goToProfile(