QOL improvements & friendsSessionsDAOstuff
This commit is contained in:
parent
10c86c9bf0
commit
a814bd74d7
9 changed files with 154 additions and 46 deletions
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package be.ugent.sel.studeez.data.remote
|
||||||
|
|
||||||
|
object FirebaseSessionReport {
|
||||||
|
const val STUDYTIME: String = "studyTime"
|
||||||
|
const val ENDTIME: String = "endTime"
|
||||||
|
}
|
|
@ -1,12 +1,19 @@
|
||||||
package be.ugent.sel.studeez.domain
|
package be.ugent.sel.studeez.domain
|
||||||
|
|
||||||
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.timer_info.TimerInfo
|
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface SessionDAO {
|
interface SessionDAO {
|
||||||
|
|
||||||
fun getSessions(): Flow<List<SessionReport>>
|
fun getSessions(): Flow<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)
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,10 @@ interface UserDAO {
|
||||||
userId: String
|
userId: String
|
||||||
): Flow<User>
|
): Flow<User>
|
||||||
|
|
||||||
|
suspend fun getUsername(
|
||||||
|
userId: String
|
||||||
|
): String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return information on the currently logged in user.
|
* @return information on the currently logged in user.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,19 +1,33 @@
|
||||||
package be.ugent.sel.studeez.domain.implementation
|
package be.ugent.sel.studeez.domain.implementation
|
||||||
|
|
||||||
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.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.ENDTIME
|
||||||
|
import be.ugent.sel.studeez.data.remote.FirebaseSessionReport.STUDYTIME
|
||||||
import be.ugent.sel.studeez.domain.AccountDAO
|
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.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.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.snapshots
|
import com.google.firebase.firestore.ktx.snapshots
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.tasks.await
|
||||||
import javax.inject.Inject
|
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>> {
|
||||||
|
@ -22,6 +36,34 @@ class FirebaseSessionDAO @Inject constructor(
|
||||||
.map { it.toObjects(SessionReport::class.java) }
|
.map { it.toObjects(SessionReport::class.java) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getSessionsOfUser(userId: String): List<SessionReport> {
|
||||||
|
val collection = firestore.collection(USER_COLLECTION)
|
||||||
|
.document(userId)
|
||||||
|
.collection(SESSION_COLLECTION)
|
||||||
|
.get().await()
|
||||||
|
val list: MutableList<SessionReport> = mutableListOf()
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +73,7 @@ class FirebaseSessionDAO @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun currentUserSessionsCollection(): CollectionReference =
|
private fun currentUserSessionsCollection(): CollectionReference =
|
||||||
firestore.collection(FirebaseCollections.USER_COLLECTION)
|
firestore.collection(USER_COLLECTION)
|
||||||
.document(auth.currentUserId)
|
.document(auth.currentUserId)
|
||||||
.collection(FirebaseCollections.SESSION_COLLECTION)
|
.collection(SESSION_COLLECTION)
|
||||||
}
|
}
|
|
@ -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 {
|
override suspend fun getLoggedInUser(): User {
|
||||||
val userDocument = currentUserDocument().get().await()
|
val userDocument = currentUserDocument().get().await()
|
||||||
return User(
|
return User(
|
||||||
|
|
|
@ -14,7 +14,6 @@ import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
@ -23,6 +22,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import be.ugent.sel.studeez.R
|
import be.ugent.sel.studeez.R
|
||||||
import be.ugent.sel.studeez.common.composable.BasicButton
|
import be.ugent.sel.studeez.common.composable.BasicButton
|
||||||
|
import be.ugent.sel.studeez.common.composable.ProfilePicture
|
||||||
import be.ugent.sel.studeez.common.composable.SearchField
|
import be.ugent.sel.studeez.common.composable.SearchField
|
||||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerEntry
|
import be.ugent.sel.studeez.common.composable.drawer.DrawerEntry
|
||||||
import be.ugent.sel.studeez.common.ext.basicButton
|
import be.ugent.sel.studeez.common.ext.basicButton
|
||||||
|
@ -162,29 +162,21 @@ fun FriendsEntry(
|
||||||
viewProfile: (String) -> Unit,
|
viewProfile: (String) -> Unit,
|
||||||
removeFriend: (Friendship) -> Unit
|
removeFriend: (Friendship) -> Unit
|
||||||
) {
|
) {
|
||||||
// TODO Styling
|
|
||||||
Row (
|
Row (
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 15.dp, vertical = 7.dp),
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(0.15f)
|
.padding(vertical = 4.dp)
|
||||||
.background(MaterialTheme.colors.primary, CircleShape)
|
|
||||||
) {
|
) {
|
||||||
Icon(
|
ProfilePicture()
|
||||||
painter = painterResource(id = R.drawable.ic_visibility_on),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxHeight()
|
|
||||||
.align(Alignment.Center),
|
|
||||||
tint = MaterialTheme.colors.onPrimary
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Box (
|
Box (
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(0.65f)
|
.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Column (
|
Column (
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -203,16 +195,17 @@ fun FriendsEntry(
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxWidth(0.15f)
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
contentAlignment = Alignment.CenterEnd
|
||||||
FriendsOverviewDropDown(
|
) {
|
||||||
friendship = friendship,
|
FriendsOverviewDropDown(
|
||||||
viewProfile = viewProfile,
|
friendship = friendship,
|
||||||
removeFriend = removeFriend
|
viewProfile = viewProfile,
|
||||||
)
|
removeFriend = removeFriend
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
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.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import be.ugent.sel.studeez.R
|
import be.ugent.sel.studeez.R
|
||||||
|
import be.ugent.sel.studeez.common.composable.ProfilePicture
|
||||||
import be.ugent.sel.studeez.common.composable.SearchField
|
import be.ugent.sel.studeez.common.composable.SearchField
|
||||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerEntry
|
import be.ugent.sel.studeez.common.composable.drawer.DrawerEntry
|
||||||
import be.ugent.sel.studeez.data.local.models.User
|
import be.ugent.sel.studeez.data.local.models.User
|
||||||
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
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import be.ugent.sel.studeez.R.string as AppText
|
import be.ugent.sel.studeez.R.string as AppText
|
||||||
|
|
||||||
data class SearchFriendsActions(
|
data class SearchFriendsActions(
|
||||||
|
@ -153,25 +154,19 @@ fun UserEntry(
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 15.dp, vertical = 7.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(15.dp)
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(0.15f)
|
.padding(vertical = 4.dp)
|
||||||
.background(MaterialTheme.colors.primary, CircleShape)
|
|
||||||
) {
|
) {
|
||||||
Icon(
|
ProfilePicture()
|
||||||
painter = painterResource(id = R.drawable.ic_visibility_on),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxHeight()
|
|
||||||
.align(Alignment.Center),
|
|
||||||
tint = MaterialTheme.colors.onPrimary
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Box (
|
Box (
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(0.65f)
|
.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Column (
|
Column (
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -190,15 +185,16 @@ fun UserEntry(
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxWidth(0.15f)
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
contentAlignment = Alignment.CenterEnd
|
||||||
SearchFriendsDropDown(
|
) {
|
||||||
user = user,
|
SearchFriendsDropDown(
|
||||||
goToProfile = goToProfile
|
user = user,
|
||||||
)
|
goToProfile = goToProfile
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import be.ugent.sel.studeez.screens.StudeezViewModel
|
||||||
import be.ugent.sel.studeez.screens.profile.public_profile.SelectedProfileState
|
import be.ugent.sel.studeez.screens.profile.public_profile.SelectedProfileState
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
|
@ -43,8 +44,16 @@ class SearchFriendsViewModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all users, except for the current user.
|
||||||
|
*/
|
||||||
fun getAllUsers(): Flow<List<User>> {
|
fun getAllUsers(): Flow<List<User>> {
|
||||||
return userDAO.getAllUsers()
|
return userDAO.getAllUsers()
|
||||||
|
.filter { users ->
|
||||||
|
users.any { user ->
|
||||||
|
user.id != userDAO.getCurrentUserId()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun goToProfile(
|
fun goToProfile(
|
||||||
|
|
Reference in a new issue