Skip to content

Commit

Permalink
Impl AvatarPicker feature
Browse files Browse the repository at this point in the history
  • Loading branch information
omer358 committed Jun 23, 2024
1 parent 6b641cf commit 7d063bd
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.example.rememberme.presentation.addperson

import androidx.annotation.DrawableRes

sealed class AddPersonEvents {
data class OnFirstNameChange(val firstName: String) : AddPersonEvents()
data class OnSecondNameChange(val secondName: String) : AddPersonEvents()
data class OnPlaceChange(val place: String) : AddPersonEvents()
data class OnTimeChange(val time: String) : AddPersonEvents()
data class OnNoteChange(val note: String?) : AddPersonEvents()
data class OnGenderChange(val gender: String) : AddPersonEvents()
data class OnAvatarChange(val avatar: String) : AddPersonEvents()
data class OnAvatarChange(@DrawableRes val avatar: Int) : AddPersonEvents()
data object OnSavePerson : AddPersonEvents()
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,99 @@
package com.example.rememberme.presentation.addperson

import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.example.rememberme.R
import com.example.rememberme.presentation.common.composables.CustomButton
import com.example.rememberme.presentation.common.composables.CustomOutlinedTextField
import com.example.rememberme.ui.theme.RememberMeTheme
import kotlinx.coroutines.launch

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AddPersonScreen(
viewModel: AddPersonViewModel = hiltViewModel(),
popUp: () -> Unit,
) {
val uiState = viewModel.uiState.collectAsState().value
val sheetState = rememberModalBottomSheetState()
val scope = rememberCoroutineScope()
var showBottomSheet by remember { mutableStateOf(false) }
var selectedAvatarResId by remember { mutableIntStateOf(R.drawable.ic_m1) }

AddPersonContent(
uiState,
uiState = uiState,
onFirstNameChange = { viewModel.onEvent(AddPersonEvents.OnFirstNameChange(it)) },
onSecondNameChange = { viewModel.onEvent(AddPersonEvents.OnSecondNameChange(it)) },
onPlaceChange = { viewModel.onEvent(AddPersonEvents.OnPlaceChange(it)) },
onTimeChange = { viewModel.onEvent(AddPersonEvents.OnTimeChange(it)) },
onNoteChange = { viewModel.onEvent(AddPersonEvents.OnNoteChange(it)) },
onGenderChange = { viewModel.onEvent(AddPersonEvents.OnGenderChange(it)) },
onAvatarChange = { viewModel.onEvent(AddPersonEvents.OnAvatarChange(it)) },
onSavePerson = { viewModel.onEvent(AddPersonEvents.OnSavePerson) },
onSavePerson = {
viewModel.onEvent(AddPersonEvents.OnSavePerson)
popUp()
},
onAvatarPickerClick = {
showBottomSheet = true
scope.launch { sheetState.show() }
},
selectedAvatarResId = selectedAvatarResId,
popUp = popUp
)

if (showBottomSheet) {
AvatarPicker(
onAvatarSelected = {
selectedAvatarResId = it
viewModel.onEvent(AddPersonEvents.OnAvatarChange(it))
scope.launch { sheetState.hide() }
showBottomSheet = false
},
onDismissRequest = {
scope.launch { sheetState.hide() }
showBottomSheet = false
}
)
}
}

@Composable
Expand All @@ -59,29 +107,32 @@ fun AddPersonContent(
onTimeChange: (String) -> Unit,
onNoteChange: (String) -> Unit,
onGenderChange: (String) -> Unit,
onAvatarChange: (String) -> Unit,
onAvatarChange: (Int) -> Unit,
onSavePerson: () -> Unit,
onAvatarPickerClick: () -> Unit,
selectedAvatarResId: Int,
popUp: () -> Unit
) {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(text = "Add Person")
},
title = { Text(text = "Add Person") },
navigationIcon = {
IconButton(onClick = { popUp() }) {
Icon(imageVector = Icons.AutoMirrored.Default.ArrowBack, contentDescription = null)
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = null
)
}
}
)
}
) {
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 8.dp)
.padding(paddingValues = it)
.padding(paddingValues)
) {
CustomOutlinedTextField(
value = uiState.firstName,
Expand All @@ -107,16 +158,28 @@ fun AddPersonContent(
selectedGender = uiState.gender,
onGenderSelected = onGenderChange
)
CustomOutlinedTextField(
value = uiState.avatar.toString(),
onValueChange = onAvatarChange,
label = "Avatar"
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = selectedAvatarResId),
contentDescription = null,
modifier = Modifier.size(70.dp)
)
OutlinedButton(onClick = onAvatarPickerClick) {
Text(text = "Pick an avatar")
}
}
CustomOutlinedTextField(
value = uiState.note ?: "",
onValueChange = onNoteChange,
label = "Note"
)
Spacer(modifier = Modifier.size(16.dp))
CustomButton(
onClick = onSavePerson,
text = "Save"
Expand All @@ -125,6 +188,63 @@ fun AddPersonContent(
}
}

@Composable
fun AvatarPicker(
onAvatarSelected: (Int) -> Unit,
onDismissRequest: () -> Unit
) {
ModalBottomSheet(onDismissRequest = onDismissRequest) {
val listOfMaleAvatars = remember {
listOf(
R.drawable.ic_m1,
R.drawable.ic_m2,
R.drawable.ic_m3,
R.drawable.ic_m4,
R.drawable.ic_m5
)
}
val listOfFemaleAvatars = remember {
listOf(
R.drawable.ic_f1,
R.drawable.ic_f2,
R.drawable.ic_f3,
R.drawable.ic_f4,
R.drawable.ic_f5
)
}
val allAvatars = remember {
listOfMaleAvatars + listOfFemaleAvatars
}
Column(
modifier = Modifier.padding(16.dp)
) {
Text(
"Pick an Avatar",
style = MaterialTheme.typography.displaySmall
)
Spacer(modifier = Modifier.size(16.dp))
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 90.dp)) {
items(allAvatars.size) { index ->
Image(
painter = painterResource(id = allAvatars[index]),
contentDescription = null,
modifier = Modifier
.size(70.dp)
.padding(vertical = 4.dp)
.clickable { onAvatarSelected(allAvatars[index]) }
)
}
}
Spacer(modifier = Modifier.size(16.dp))
Button(
onClick = { /* Save button action if needed */ },
modifier = Modifier.align(Alignment.CenterHorizontally)
) {
Text(text = "Save")
}
}
}
}

@Composable
fun GenderRadioButton(
Expand All @@ -138,20 +258,20 @@ fun GenderRadioButton(
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.fillMaxWidth()
){
genderOptions.forEach { gender ->
Row(
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(
selected = (gender == selectedGender),
onClick = { onGenderSelected(gender) }
)
Text(text = gender, modifier = Modifier.padding(start = 4.dp))
) {
genderOptions.forEach { gender ->
Row(
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(
selected = (gender == selectedGender),
onClick = { onGenderSelected(gender) }
)
Text(text = gender, modifier = Modifier.padding(start = 4.dp))
}
}
}
}
}
}

@Preview(showBackground = true)
Expand All @@ -169,6 +289,8 @@ fun AddPersonContentPreview() {
onGenderChange = {},
onAvatarChange = {},
onSavePerson = {},
onAvatarPickerClick = {},
selectedAvatarResId = R.drawable.ic_m1,
popUp = {}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ data class AddPersonUiState(
val time: String = "",
val note: String? = null,
val gender: String = "",
val avatar: String = ""
val avatar: Int = 0,
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.example.rememberme.presentation.addperson

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.rememberme.R
import com.example.rememberme.domain.model.People
import com.example.rememberme.domain.usecases.people.PeopleUseCases
import dagger.hilt.android.lifecycle.HiltViewModel
Expand Down Expand Up @@ -47,6 +47,7 @@ class AddPersonViewModel @Inject constructor(
}

is AddPersonEvents.OnAvatarChange -> {
Log.i(TAG, "onEvent: OnAvatarChange -> ${event.avatar}")
_uiState.value = _uiState.value.copy(avatar = event.avatar)
}

Expand All @@ -67,10 +68,14 @@ class AddPersonViewModel @Inject constructor(
note = _uiState.value.note,
gender = _uiState.value.gender,
// TODO: get avatar from the ui
avatar = R.drawable.ic_m1
avatar = _uiState.value.avatar
)
peopleUseCases.insertPerson(person)
}
}
}
companion object {
private const val TAG = "AddPersonViewModel"
}

}

0 comments on commit 7d063bd

Please sign in to comment.