#63 Add bio to profile

This commit is contained in:
Tibo De Peuter 2023-05-10 12:13:48 +02:00
parent 33b8a32330
commit 81e777f21d
10 changed files with 124 additions and 48 deletions

View file

@ -1,3 +1,9 @@
package be.ugent.sel.studeez.data.local.models
data class User(val id: String = "")
import com.google.firebase.firestore.DocumentId
data class User(
@DocumentId val id: String = "",
val username: String = "",
val biography: String = ""
)

View file

@ -1,9 +1,15 @@
package be.ugent.sel.studeez.domain
import be.ugent.sel.studeez.data.local.models.User
interface UserDAO {
suspend fun getUsername(): String?
suspend fun save(newUsername: String)
suspend fun getUser(): User
suspend fun saveUser(
newUsername: String,
newBiography: String = ""
)
/**
* Delete all references to this user in the database. Similar to the deleteCascade in

View file

@ -2,6 +2,7 @@ package be.ugent.sel.studeez.domain.implementation
import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.snackbar.SnackbarManager
import be.ugent.sel.studeez.data.local.models.User
import be.ugent.sel.studeez.domain.AccountDAO
import be.ugent.sel.studeez.domain.UserDAO
import com.google.firebase.firestore.DocumentReference
@ -14,12 +15,22 @@ class FirebaseUserDAO @Inject constructor(
private val auth: AccountDAO
) : UserDAO {
override suspend fun getUsername(): String? {
return currentUserDocument().get().await().getString("username")
override suspend fun getUser(): User {
val userDocument = currentUserDocument().get().await()
return User(
username = userDocument.getString(USERNAME_FIELD) ?: "",
biography = userDocument.getString(BIOGRAPHY_FIELD) ?: ""
)
}
override suspend fun save(newUsername: String) {
currentUserDocument().set(mapOf("username" to newUsername))
override suspend fun saveUser(
newUsername: String,
newBiography: String
) {
currentUserDocument().set(mapOf(
USERNAME_FIELD to newUsername,
BIOGRAPHY_FIELD to newBiography
))
}
private fun currentUserDocument(): DocumentReference =
@ -27,6 +38,8 @@ class FirebaseUserDAO @Inject constructor(
companion object {
private const val USER_COLLECTION = "users"
private const val USERNAME_FIELD = "username"
private const val BIOGRAPHY_FIELD = "biography"
}
override suspend fun deleteUserReferences() {

View file

@ -1,20 +1,21 @@
package be.ugent.sel.studeez.screens.profile
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.composable.BasicTextButton
import be.ugent.sel.studeez.common.composable.LabelledInputField
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
import be.ugent.sel.studeez.common.ext.textButton
import be.ugent.sel.studeez.resources
import be.ugent.sel.studeez.ui.theme.StudeezTheme
import be.ugent.sel.studeez.R.string as AppText
data class EditProfileActions(
val onUserNameChange: (String) -> Unit,
val onBiographyChange: (String) -> Unit,
val onSaveClick: () -> Unit,
val onDeleteClick: () -> Unit
)
@ -25,6 +26,7 @@ fun getEditProfileActions(
): EditProfileActions {
return EditProfileActions(
onUserNameChange = { viewModel.onUsernameChange(it) },
onBiographyChange = { viewModel.onBiographyChange(it) },
onSaveClick = { viewModel.onSaveClick() },
onDeleteClick = { viewModel.onDeleteClick(openAndPopUp) },
)
@ -51,28 +53,41 @@ fun EditProfileScreen(
editProfileActions: EditProfileActions,
) {
SecondaryScreenTemplate(
title = resources().getString(R.string.editing_profile),
title = resources().getString(AppText.editing_profile),
popUp = goBack
) {
Column {
LabelledInputField(
value = uiState.username,
onNewValue = editProfileActions.onUserNameChange,
label = R.string.username
)
BasicTextButton(
text = R.string.save,
Modifier.textButton(),
action = {
editProfileActions.onSaveClick()
goBack()
}
)
BasicTextButton(
text = R.string.delete_profile,
Modifier.textButton(),
action = editProfileActions.onDeleteClick
)
LazyColumn {
item {
LabelledInputField(
value = uiState.username,
onNewValue = editProfileActions.onUserNameChange,
label = AppText.username
)
}
item {
LabelledInputField(
value = uiState.biography,
onNewValue = editProfileActions.onBiographyChange,
label = AppText.biography
)
}
item {
BasicTextButton(
text = AppText.save,
Modifier.textButton(),
action = {
editProfileActions.onSaveClick()
goBack()
}
)
}
item {
BasicTextButton(
text = AppText.delete_profile,
Modifier.textButton(),
action = editProfileActions.onDeleteClick
)
}
}
}
}
@ -81,6 +96,6 @@ fun EditProfileScreen(
@Composable
fun EditProfileScreenComposable() {
StudeezTheme {
EditProfileScreen({}, ProfileEditUiState(), EditProfileActions({}, {}, {}))
EditProfileScreen({}, ProfileEditUiState(), EditProfileActions({}, {}, {}, {}))
}
}

View file

@ -1,5 +1,6 @@
package be.ugent.sel.studeez.screens.profile
data class ProfileEditUiState (
val username: String = ""
val username: String = "",
val biography: String = ""
)

View file

@ -3,6 +3,7 @@ package be.ugent.sel.studeez.screens.profile
import androidx.compose.runtime.mutableStateOf
import be.ugent.sel.studeez.R
import be.ugent.sel.studeez.common.snackbar.SnackbarManager
import be.ugent.sel.studeez.data.local.models.User
import be.ugent.sel.studeez.domain.AccountDAO
import be.ugent.sel.studeez.domain.LogService
import be.ugent.sel.studeez.domain.UserDAO
@ -23,7 +24,11 @@ class ProfileEditViewModel @Inject constructor(
init {
launchCatching {
uiState.value = uiState.value.copy(username = userDAO.getUsername()!!)
val user: User = userDAO.getUser()
uiState.value = uiState.value.copy(
username = user.username,
biography = user.biography
)
}
}
@ -31,9 +36,16 @@ class ProfileEditViewModel @Inject constructor(
uiState.value = uiState.value.copy(username = newValue)
}
fun onBiographyChange(newValue: String) {
uiState.value = uiState.value.copy(biography = newValue)
}
fun onSaveClick() {
launchCatching {
userDAO.save(uiState.value.username)
userDAO.saveUser(
newUsername = uiState.value.username,
newBiography = uiState.value.biography
)
SnackbarManager.showMessage(R.string.success)
}
}

View file

@ -1,17 +1,18 @@
package be.ugent.sel.studeez.screens.profile
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import be.ugent.sel.studeez.R
import androidx.compose.ui.unit.dp
import be.ugent.sel.studeez.common.composable.Headline
import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
@ -22,16 +23,18 @@ import be.ugent.sel.studeez.R.string as AppText
data class ProfileActions(
val getUsername: suspend CoroutineScope.() -> String?,
val onEditProfileClick: () -> Unit,
val getBiography: suspend CoroutineScope.() -> String?,
val onEditProfileClick: () -> Unit
)
fun getProfileActions(
viewModel: ProfileViewModel,
open: (String) -> Unit,
open: (String) -> Unit
): ProfileActions {
return ProfileActions(
getUsername = { viewModel.getUsername() },
onEditProfileClick = { viewModel.onEditProfileClick(open) },
getBiography = { viewModel.getBiography() },
onEditProfileClick = { viewModel.onEditProfileClick(open) }
)
}
@ -56,8 +59,10 @@ fun ProfileScreen(
navigationBarActions: NavigationBarActions,
) {
var username: String? by remember { mutableStateOf("") }
var biography: String? by remember { mutableStateOf("") }
LaunchedEffect(key1 = Unit) {
username = profileActions.getUsername(this)
biography = profileActions.getBiography(this)
}
PrimaryScreenTemplate(
title = resources().getString(AppText.profile),
@ -65,7 +70,20 @@ fun ProfileScreen(
navigationBarActions = navigationBarActions,
barAction = { EditAction(onClick = profileActions.onEditProfileClick) }
) {
Headline(text = (username ?: resources().getString(R.string.no_username)))
LazyColumn(
verticalArrangement = Arrangement.spacedBy(15.dp)
) {
item {
Headline(text = username ?: resources().getString(AppText.no_username))
}
item {
Text(
text = biography ?: "",
textAlign = TextAlign.Center,
modifier = Modifier.padding(48.dp, 0.dp)
)
}
}
}
}
@ -86,7 +104,7 @@ fun EditAction(
@Composable
fun ProfileScreenPreview() {
ProfileScreen(
profileActions = ProfileActions({ null }, {}),
profileActions = ProfileActions({ null }, { null }, {}),
drawerActions = DrawerActions({}, {}, {}, {}, {}),
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {})
)

View file

@ -13,8 +13,12 @@ class ProfileViewModel @Inject constructor(
logService: LogService
) : StudeezViewModel(logService) {
suspend fun getUsername(): String? {
return userDAO.getUsername()
suspend fun getUsername(): String {
return userDAO.getUser().username
}
suspend fun getBiography(): String {
return userDAO.getUser().biography
}
fun onEditProfileClick(open: (String) -> Unit) {

View file

@ -66,7 +66,7 @@ class SignUpViewModel @Inject constructor(
launchCatching {
accountDAO.signUpWithEmailAndPassword(email, password)
accountDAO.signInWithEmailAndPassword(email, password)
userDAO.save(username)
userDAO.saveUser(username)
openAndPopUp(HOME_SCREEN, SIGN_UP_SCREEN)
}
}

View file

@ -54,6 +54,7 @@
<string name="edit_profile">Edit profile</string>
<string name="editing_profile">Editing profile</string>
<string name="delete_profile">Delete profile</string>
<string name="biography">Bio</string>
<!-- ========== Drawer ========== -->