Basic friends overview screen
This commit is contained in:
parent
3b50054ff5
commit
87fe476724
4 changed files with 266 additions and 0 deletions
|
@ -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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
5
app/src/main/res/drawable/ic_more_horizontal.xml
Normal file
5
app/src/main/res/drawable/ic_more_horizontal.xml
Normal 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>
|
|
@ -16,6 +16,7 @@
|
||||||
<string name="go_back">Go back</string>
|
<string name="go_back">Go back</string>
|
||||||
<string name="next">Next</string>
|
<string name="next">Next</string>
|
||||||
<string name="start">Start</string>
|
<string name="start">Start</string>
|
||||||
|
<string name="view_more">View more</string>
|
||||||
|
|
||||||
<!-- Messages -->
|
<!-- Messages -->
|
||||||
<string name="success">Success!</string>
|
<string name="success">Success!</string>
|
||||||
|
@ -112,6 +113,7 @@
|
||||||
<item quantity="other">%d Friends</item>
|
<item quantity="other">%d Friends</item>
|
||||||
</plurals>
|
</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. -->
|
||||||
|
<string name="no_friends">You don\'t have any friends yet. Add one!</string>
|
||||||
|
|
||||||
<!-- ========== Create & edit screens ========== -->
|
<!-- ========== Create & edit screens ========== -->
|
||||||
|
|
||||||
|
|
Reference in a new issue