Basic friends overview screen

This commit is contained in:
Tibo De Peuter 2023-05-14 13:10:32 +02:00
parent 3b50054ff5
commit 87fe476724
4 changed files with 266 additions and 0 deletions

View file

@ -0,0 +1,218 @@
package be.ugent.sel.studeez.screens.friend
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.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
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.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextOverflow
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.BasicButton
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
import be.ugent.sel.studeez.common.ext.basicButton
import be.ugent.sel.studeez.data.local.models.Friendship
import be.ugent.sel.studeez.data.local.models.User
import be.ugent.sel.studeez.resources
import be.ugent.sel.studeez.ui.theme.StudeezTheme
import com.google.firebase.Timestamp
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import be.ugent.sel.studeez.R.string as AppText
data class FriendsOverviewActions(
val getFriendsFlow: () -> Flow<List<Pair<User, Friendship>>>,
val searchFriends: () -> Unit
)
fun getFriendsOverviewActions(
viewModel: FriendsOverviewViewModel,
open: (String) -> Unit
): FriendsOverviewActions {
return FriendsOverviewActions(
getFriendsFlow = viewModel::getAllFriends,
searchFriends = { viewModel.searchFriends(open) }
)
}
@Composable
fun FriendsOveriewRoute(
open: (String) -> Unit,
popUp: () -> Unit,
viewModel: FriendsOverviewViewModel
) {
FriendsOverviewScreen(
friendsOverviewActions = getFriendsOverviewActions(
viewModel = viewModel,
open = open
),
popUp = popUp
)
}
@Composable
fun FriendsOverviewScreen(
friendsOverviewActions: FriendsOverviewActions,
popUp: () -> Unit
) {
val friends = friendsOverviewActions.getFriendsFlow().collectAsState(initial = emptyList())
SecondaryScreenTemplate(
title = "TODO there needs to be a search field here", // TODO
popUp = popUp
) {
LazyColumn {
if (friends.value.isEmpty()) {
// Show a quick button to search friends when the user does not have any friends yet.
item {
BasicButton(
text = AppText.no_friends,
modifier = Modifier.basicButton()
) {
friendsOverviewActions.searchFriends()
}
}
}
items(friends.value) { friend ->
FriendsEntry(
user = friend.first,
friendship = friend.second
)
}
}
}
}
@Preview
@Composable
fun FriendsOverviewPreview() {
StudeezTheme {
FriendsOverviewScreen(
friendsOverviewActions = FriendsOverviewActions(
getFriendsFlow = { emptyFlow() },
searchFriends = {}
),
popUp = {}
)
}
}
@Composable
fun FriendsEntry(
user: User,
friendship: Friendship
) {
// TODO Styling
Row (
modifier = Modifier
.fillMaxWidth()
) {
Box(
modifier = Modifier
.fillMaxWidth(0.15f)
.background(MaterialTheme.colors.primary, CircleShape)
) {
Icon(
painter = painterResource(id = R.drawable.ic_visibility_on),
contentDescription = null,
modifier = Modifier
.fillMaxHeight()
.align(Alignment.Center),
tint = MaterialTheme.colors.onPrimary
)
}
Box (
modifier = Modifier
.fillMaxWidth(0.65f)
) {
Column (
modifier = Modifier
.padding(vertical = 4.dp)
) {
Text(
text = user.username,
fontSize = 16.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Text(
text = "${resources().getString(AppText.app_name)} ${resources().getString(AppText.friend)}",
fontSize = 14.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
Box(
modifier = Modifier.fillMaxWidth(0.15f)
) {
ThreeDots(friendship = friendship)
}
}
}
@Preview
@Composable
fun FriendsEntryPreview() {
StudeezTheme {
FriendsEntry(
user = User(
id = "",
username = "Tibo De Peuter",
biography = "short bio"
),
friendship = Friendship(
id = "",
friendId = "someId",
friendsSince = Timestamp.now(),
accepted = true
)
)
}
}
@Composable
fun ThreeDots(
friendship: Friendship
) {
IconButton(
onClick = { /* TODO Open dropdown */ }
) {
Icon(
imageVector = ImageVector.vectorResource(id = R.drawable.ic_more_horizontal),
contentDescription = resources().getString(AppText.view_more),
modifier = Modifier.fillMaxSize()
)
}
}
@Preview
@Composable
fun ThreeDotsPreview() {
StudeezTheme {
ThreeDots(
friendship = Friendship(
id = "",
friendId = "someId",
friendsSince = Timestamp.now(),
accepted = true
)
)
}
}

View file

@ -0,0 +1,41 @@
package be.ugent.sel.studeez.screens.friend
import be.ugent.sel.studeez.data.local.models.Friendship
import be.ugent.sel.studeez.data.local.models.User
import be.ugent.sel.studeez.domain.FriendshipDAO
import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.UserDAO
import be.ugent.sel.studeez.navigation.StudeezDestinations
import be.ugent.sel.studeez.screens.StudeezViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapConcat
import javax.inject.Inject
@HiltViewModel
class FriendsOverviewViewModel @Inject constructor(
private val userDAO: UserDAO,
private val friendshipDAO: FriendshipDAO,
logService: LogService
) : StudeezViewModel(logService) {
fun getAllFriends(): Flow<List<Pair<User, Friendship>>> {
return friendshipDAO.getAllFriendships()
.flatMapConcat { friendships ->
val userFlows = friendships.map { friendship ->
userDAO.getUserDetails(friendship.friendId)
}
combine(userFlows) { users ->
friendships.zip(users) { friendship, user ->
Pair(user, friendship)
}
}
}
}
fun searchFriends(open: (String) -> Unit) {
open(StudeezDestinations.SEARCH_FRIENDS_SCREEN)
}
}

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>

View file

@ -16,6 +16,7 @@
<string name="go_back">Go back</string>
<string name="next">Next</string>
<string name="start">Start</string>
<string name="view_more">View more</string>
<!-- Messages -->
<string name="success">Success!</string>
@ -112,6 +113,7 @@
<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="no_friends">You don\'t have any friends yet. Add one!</string>
<!-- ========== Create & edit screens ========== -->