#63 Add bio to profile
This commit is contained in:
parent
33b8a32330
commit
81e777f21d
10 changed files with 124 additions and 48 deletions
|
@ -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 = ""
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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({}, {}, {}, {}))
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package be.ugent.sel.studeez.screens.profile
|
||||
|
||||
data class ProfileEditUiState (
|
||||
val username: String = ""
|
||||
val username: String = "",
|
||||
val biography: String = ""
|
||||
)
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }, {}, {}, {}, {}, {}, {}, {})
|
||||
)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ========== -->
|
||||
|
||||
|
|
Reference in a new issue