#63 Add getFriendshipCount and add to profile screen

This commit is contained in:
Tibo De Peuter 2023-05-14 12:07:56 +02:00
parent bb64875bad
commit 3b50054ff5
7 changed files with 111 additions and 9 deletions

View file

@ -31,7 +31,11 @@ import be.ugent.sel.studeez.common.ext.defaultButtonShape
import be.ugent.sel.studeez.R.string as AppText import be.ugent.sel.studeez.R.string as AppText
@Composable @Composable
fun BasicTextButton(@StringRes text: Int, modifier: Modifier, action: () -> Unit) { fun BasicTextButton(
@StringRes text: Int,
modifier: Modifier,
action: () -> Unit
) {
TextButton( TextButton(
onClick = action, onClick = action,
modifier = modifier modifier = modifier

View file

@ -1,5 +1,6 @@
package be.ugent.sel.studeez.domain.implementation package be.ugent.sel.studeez.domain.implementation
import be.ugent.sel.studeez.common.snackbar.SnackbarManager
import be.ugent.sel.studeez.data.local.models.Friendship import be.ugent.sel.studeez.data.local.models.Friendship
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.FriendshipDAO
@ -7,8 +8,14 @@ import com.google.firebase.firestore.DocumentReference
import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.FirebaseFirestore
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.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
import be.ugent.sel.studeez.R.string as AppText
class FirebaseFriendshipDAO @Inject constructor( class FirebaseFriendshipDAO @Inject constructor(
private val firestore: FirebaseFirestore, private val firestore: FirebaseFirestore,
@ -27,7 +34,22 @@ class FirebaseFriendshipDAO @Inject constructor(
} }
override fun getFriendshipCount(): Flow<Int> { override fun getFriendshipCount(): Flow<Int> {
TODO("Not yet implemented") return flow {
val friendshipCount = suspendCoroutine { continuation ->
currentUserDocument()
.collection(FirebaseCollections.FRIENDS_COLLECTION)
.get()
.addOnSuccessListener { querySnapshot ->
continuation.resume(querySnapshot.size())
}
.addOnFailureListener { exception ->
continuation.resumeWithException(exception)
}
}
emit(friendshipCount)
}.catch {
SnackbarManager.showMessage(AppText.generic_error)
}
} }
override fun getFriendshipDetails(id: String): Friendship { override fun getFriendshipDetails(id: String): Friendship {

View file

@ -30,6 +30,7 @@ object StudeezDestinations {
const val EDIT_TASK_FORM = "edit_task" const val EDIT_TASK_FORM = "edit_task"
// Friends flow // Friends flow
const val FRIENDS_OVERVIEW_SCREEN = "friends_overview"
const val SEARCH_FRIENDS_SCREEN = "search_friends" const val SEARCH_FRIENDS_SCREEN = "search_friends"
// Create & edit screens // Create & edit screens

View file

@ -220,6 +220,10 @@ fun StudeezNavGraph(
} }
// Friends flow // Friends flow
composable(StudeezDestinations.FRIENDS_OVERVIEW_SCREEN) {
// TODO
}
composable(StudeezDestinations.SEARCH_FRIENDS_SCREEN) { composable(StudeezDestinations.SEARCH_FRIENDS_SCREEN) {
// TODO // TODO
} }

View file

@ -1,30 +1,38 @@
package be.ugent.sel.studeez.screens.profile package be.ugent.sel.studeez.screens.profile
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Button
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.IconButton import androidx.compose.material.IconButton
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Edit
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
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.R
import be.ugent.sel.studeez.common.composable.Headline import be.ugent.sel.studeez.common.composable.Headline
import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions
import be.ugent.sel.studeez.common.ext.defaultButtonShape
import be.ugent.sel.studeez.resources import be.ugent.sel.studeez.resources
import be.ugent.sel.studeez.ui.theme.StudeezTheme
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import be.ugent.sel.studeez.R.string as AppText import be.ugent.sel.studeez.R.string as AppText
data class ProfileActions( data class ProfileActions(
val getUsername: suspend CoroutineScope.() -> String?, val getUsername: suspend CoroutineScope.() -> String?,
val getBiography: suspend CoroutineScope.() -> String?, val getBiography: suspend CoroutineScope.() -> String?,
val onEditProfileClick: () -> Unit val getAmountOfFriends: () -> Flow<Int>,
val onEditProfileClick: () -> Unit,
val onViewFriendsClick: () -> Unit
) )
fun getProfileActions( fun getProfileActions(
@ -34,7 +42,9 @@ fun getProfileActions(
return ProfileActions( return ProfileActions(
getUsername = { viewModel.getUsername() }, getUsername = { viewModel.getUsername() },
getBiography = { viewModel.getBiography() }, getBiography = { viewModel.getBiography() },
onEditProfileClick = { viewModel.onEditProfileClick(open) } getAmountOfFriends = { viewModel.getAmountOfFriends() },
onEditProfileClick = { viewModel.onEditProfileClick(open) },
onViewFriendsClick = { viewModel.onViewFriendsClick(open) }
) )
} }
@ -60,6 +70,8 @@ fun ProfileScreen(
) { ) {
var username: String? by remember { mutableStateOf("") } var username: String? by remember { mutableStateOf("") }
var biography: String? by remember { mutableStateOf("") } var biography: String? by remember { mutableStateOf("") }
val amountOfFriends = profileActions.getAmountOfFriends().collectAsState(initial = 0)
LaunchedEffect(key1 = Unit) { LaunchedEffect(key1 = Unit) {
username = profileActions.getUsername(this) username = profileActions.getUsername(this)
biography = profileActions.getBiography(this) biography = profileActions.getBiography(this)
@ -76,6 +88,21 @@ fun ProfileScreen(
item { item {
Headline(text = username ?: resources().getString(AppText.no_username)) Headline(text = username ?: resources().getString(AppText.no_username))
} }
item {
Row(
horizontalArrangement = Arrangement.spacedBy(5.dp),
modifier = Modifier.fillMaxWidth()
.wrapContentWidth(align = Alignment.CenterHorizontally)
) {
AmountOfFriendsButton(
amountOfFriends = amountOfFriends.value
) {
profileActions.onViewFriendsClick()
}
}
}
item { item {
Text( Text(
text = biography ?: "", text = biography ?: "",
@ -96,7 +123,6 @@ fun EditAction(
imageVector = Icons.Default.Edit, imageVector = Icons.Default.Edit,
contentDescription = resources().getString(AppText.edit_profile) contentDescription = resources().getString(AppText.edit_profile)
) )
} }
} }
@ -104,8 +130,38 @@ fun EditAction(
@Composable @Composable
fun ProfileScreenPreview() { fun ProfileScreenPreview() {
ProfileScreen( ProfileScreen(
profileActions = ProfileActions({ null }, { null }, {}), profileActions = ProfileActions({ null }, { null }, { emptyFlow() }, {}, {}),
drawerActions = DrawerActions({}, {}, {}, {}, {}), drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {}) navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {})
) )
} }
@Composable
fun AmountOfFriendsButton(
amountOfFriends: Int,
onClick: () -> Unit
){
Button(
onClick = onClick,
shape = defaultButtonShape()
) {
Text(
text = resources().getQuantityString(
/* id = */ R.plurals.friends_amount,
/* quantity = */ amountOfFriends,
/* ...formatArgs = */ amountOfFriends
)
)
}
}
@Preview
@Composable
fun AmountOfFriendsButtonPreview() {
StudeezTheme {
Column {
AmountOfFriendsButton(amountOfFriends = 1) { }
AmountOfFriendsButton(amountOfFriends = 100) { }
}
}
}

View file

@ -1,15 +1,18 @@
package be.ugent.sel.studeez.screens.profile package be.ugent.sel.studeez.screens.profile
import be.ugent.sel.studeez.domain.FriendshipDAO
import be.ugent.sel.studeez.domain.LogService import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.UserDAO import be.ugent.sel.studeez.domain.UserDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class ProfileViewModel @Inject constructor( class ProfileViewModel @Inject constructor(
private val userDAO: UserDAO, private val userDAO: UserDAO,
private val friendshipDAO: FriendshipDAO,
logService: LogService logService: LogService
) : StudeezViewModel(logService) { ) : StudeezViewModel(logService) {
@ -21,8 +24,16 @@ class ProfileViewModel @Inject constructor(
return userDAO.getLoggedInUser().biography return userDAO.getLoggedInUser().biography
} }
fun getAmountOfFriends(): Flow<Int> {
return friendshipDAO.getFriendshipCount()
}
fun onEditProfileClick(open: (String) -> Unit) { fun onEditProfileClick(open: (String) -> Unit) {
open(StudeezDestinations.EDIT_PROFILE_SCREEN) open(StudeezDestinations.EDIT_PROFILE_SCREEN)
} }
fun onViewFriendsClick(open: (String) -> Unit) {
open(StudeezDestinations.FRIENDS_OVERVIEW_SCREEN)
}
} }

View file

@ -20,7 +20,7 @@
<!-- Messages --> <!-- Messages -->
<string name="success">Success!</string> <string name="success">Success!</string>
<string name="try_again">Try again</string> <string name="try_again">Try again</string>
<string name="generic_error">Something wrong happened. Please try again.</string> <string name="generic_error">Something went wrong. Please try again.</string>
<string name="email_error">Please insert a valid email.</string> <string name="email_error">Please insert a valid email.</string>
<!-- ========== NavBar ========== --> <!-- ========== NavBar ========== -->
@ -107,6 +107,10 @@
<string name="friends">Friends</string> <string name="friends">Friends</string>
<string name="friend">Friend</string> <string name="friend">Friend</string>
<plurals name="friends_amount">
<item quantity="one">%d Friend</item>
<item quantity="other">%d Friends</item>
</plurals>
<string name="add_friend_not_possible_yet">Adding friends still needs to be implemented. Hang on tight!</string> <!-- TODO Remove this description line once implemented. --> <string name="add_friend_not_possible_yet">Adding friends still needs to be implemented. Hang on tight!</string> <!-- TODO Remove this description line once implemented. -->
<!-- ========== Create & edit screens ========== --> <!-- ========== Create & edit screens ========== -->