Skip to content

Commit

Permalink
Merge pull request #28 from omer358/dev
Browse files Browse the repository at this point in the history
fix #26 and #27
  • Loading branch information
omer358 authored Jul 2, 2024
2 parents 36f9225 + 05bb411 commit 13ebe8b
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 104 deletions.
4 changes: 3 additions & 1 deletion app/src/main/java/com/example/rememberme/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.example.rememberme.domain.usecases.people.GetAllPeople
import com.example.rememberme.domain.usecases.people.GetPersonById
import com.example.rememberme.domain.usecases.people.InsertNewPerson
import com.example.rememberme.domain.usecases.people.PeopleUseCases
import com.example.rememberme.domain.usecases.people.UpdatePerson
import com.example.rememberme.utils.Constants.PEOPLE_DATABASE_NAME
import com.example.remindme.database.PeopleDao
import dagger.Module
Expand Down Expand Up @@ -62,7 +63,8 @@ object AppModule {
return PeopleUseCases(
getAllPeople = GetAllPeople(peopleRepository),
getPersonById = GetPersonById(peopleRepository),
insertPerson = InsertNewPerson(peopleRepository)
insertPerson = InsertNewPerson(peopleRepository),
updatePerson = UpdatePerson(peopleRepository)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ package com.example.rememberme.domain.usecases.people
data class PeopleUseCases(
val getAllPeople: GetAllPeople,
val getPersonById: GetPersonById,
val insertPerson: InsertNewPerson
val insertPerson: InsertNewPerson,
val updatePerson: UpdatePerson
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.rememberme.domain.usecases.people

import android.util.Log
import com.example.rememberme.domain.model.People
import com.example.rememberme.domain.repository.PeopleRepository

class UpdatePerson(
private val peopleRepository: PeopleRepository
) {
suspend operator fun invoke(person: People) {
Log.i(TAG,"UpdatePersonUseCase: invoked")
peopleRepository.updatePeople(person)
}
companion object {
private const val TAG = "UpdatePerson"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ 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.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
Expand All @@ -54,6 +54,7 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.example.rememberme.R
import com.example.rememberme.presentation.common.composables.CustomButton
import com.example.rememberme.presentation.common.composables.CustomErrorText
Expand All @@ -62,23 +63,43 @@ import com.example.rememberme.ui.theme.RememberMeTheme
import kotlinx.coroutines.launch
import java.util.Calendar

@OptIn(ExperimentalMaterial3Api::class)
private const val TAG = "AddPersonScreen"

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AddPersonScreen(
viewModel: AddPersonViewModel = hiltViewModel(),
popUp: () -> Unit,
personId: Long?
) {
val uiState = viewModel.uiState.collectAsState().value
val isPersonSaved by viewModel.isPersonSaved.collectAsState()
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val isPersonSaved by viewModel.isPersonSaved.collectAsStateWithLifecycle()

val sheetState = rememberModalBottomSheetState()
val scope = rememberCoroutineScope()
var showBottomSheet by remember { mutableStateOf(false) }
var selectedAvatarResId by remember { mutableIntStateOf(R.drawable.ic_m1) }
var selectedAvatarResId by remember {
if (personId == null) {
Log.i(TAG, "AddPersonScreen: Person is null")
mutableIntStateOf(R.drawable.ic_m1)
} else {
Log.i(TAG, "AddPersonScreen: Person is not null")
mutableIntStateOf(uiState.avatar)
}
}
if (isPersonSaved) {
popUp()
}

LaunchedEffect(personId) {
if (personId != null) {
Log.i(TAG,"LoadPersonDetails on the addPerson screen")
viewModel.loadPersonDetails(personId)
} else {
Log.i(TAG,"creating new person screen")
viewModel.resetForm()
}
}
AddPersonContent(
uiState = uiState,
onFirstNameChange = { viewModel.onEvent(AddPersonEvents.OnFirstNameChange(it)) },
Expand Down Expand Up @@ -174,9 +195,8 @@ fun AddPersonContent(
errorText = uiState.placeError
)
DateTimePicker(
initialDateTime = uiState.time,
uiState = uiState,
onDateTimeChange = onTimeChange,
uiState
)
GenderRadioButton(
selectedGender = uiState.gender,
Expand Down Expand Up @@ -209,23 +229,25 @@ fun AddPersonContent(
Spacer(modifier = Modifier.size(16.dp))
CustomButton(
onClick = onSavePerson,
text = "Save"
text = if (uiState.id != null) "Update" else "Save"
)
}
}
}


@Composable
fun DateTimePicker(
initialDateTime: String,
uiState: AddPersonUiState,
onDateTimeChange: (String) -> Unit,
uiState: AddPersonUiState
) {
val context = LocalContext.current
val calendar = Calendar.getInstance()
var selectedDateTime by remember { mutableStateOf(initialDateTime) }
val selectedDateTime = remember { mutableStateOf("") }
selectedDateTime.value = uiState.time
Log.i(TAG,"currentDate from the UiState: ${uiState.time}")

if (selectedDateTime.isEmpty()) {
if (uiState.time.isBlank()) {
calendar.timeInMillis = System.currentTimeMillis()
}
// Create a ContextThemeWrapper with your custom theme
Expand All @@ -241,8 +263,8 @@ fun DateTimePicker(
{ _: TimePicker, hourOfDay: Int, minute: Int ->
calendar.set(Calendar.HOUR_OF_DAY, hourOfDay)
calendar.set(Calendar.MINUTE, minute)
selectedDateTime = "${dayOfMonth}/${month + 1}/${year} ${hourOfDay}:${minute}"
onDateTimeChange(selectedDateTime)
selectedDateTime.value = "${dayOfMonth}/${month + 1}/${year} ${hourOfDay}:${minute}"
onDateTimeChange(selectedDateTime.value)
},
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
Expand All @@ -257,7 +279,11 @@ fun DateTimePicker(

Column {
OutlinedButton(onClick = { datePickerDialog.show() }) {
Text(text = selectedDateTime.ifEmpty { "Pick Date & Time" })
if(selectedDateTime.value.isEmpty()) {
Text(text = "Pick Date & Time")
}else{
Text(text = uiState.time)
}
}
if (uiState.timeError != null) {
Text(
Expand Down Expand Up @@ -335,7 +361,7 @@ fun GenderRadioButton(
modifier: Modifier = Modifier,
errorMessage: String?
) {
Log.d(TAG, "GenderRadioButton: $errorMessage")
Log.d(TAG, "GenderRadioButtonError: $errorMessage")
val genderOptions = listOf("Male", "Female")
Column(modifier = modifier) {
Text("Gender", modifier = Modifier.padding(bottom = 4.dp))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ package com.example.rememberme.presentation.addperson
import com.example.rememberme.R

data class AddPersonUiState(
val id: Long? = null,
val firstName: String = "",
val firstNameError: String? = null,
val secondName: String = "",
val secondNameError: String? = null,
val place: String = "",
val placeError: String? = null,
val time: String = "",
val timeError: String? = null,
val note: String? = null,
val gender: String = "",
val genderError: String? = null,
val avatar: Int = R.drawable.ic_f1,
)
val avatar: Int = R.drawable.ic_m1,
val firstNameError: String? = null,
val secondNameError: String? = null,
val placeError: String? = null,
val timeError: String? = null,
val genderError: String? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class AddPersonViewModel @Inject constructor(
private val peopleUseCases: PeopleUseCases,
private val addPersonUseCases: AddPersonUseCases
) : ViewModel() {

private val _uiState = MutableStateFlow(AddPersonUiState())
val uiState: StateFlow<AddPersonUiState> = _uiState

Expand All @@ -28,66 +29,122 @@ class AddPersonViewModel @Inject constructor(
fun onEvent(event: AddPersonEvents) {
when (event) {
is AddPersonEvents.OnFirstNameChange -> {
Log.i(TAG, "onEvent: OnFirstNameChange -> ${event.firstName}")
_uiState.value = _uiState.value.copy(firstName = event.firstName, firstNameError = null)
}

is AddPersonEvents.OnSecondNameChange -> {
Log.i(TAG, "onEvent: OnSecondNameChange -> ${event.secondName}")
_uiState.value = _uiState.value.copy(secondName = event.secondName, secondNameError = null)
}

is AddPersonEvents.OnPlaceChange -> {
Log.i(TAG, "onEvent: OnPlaceChange -> ${event.place}")
_uiState.value = _uiState.value.copy(place = event.place, placeError = null)
}

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

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

is AddPersonEvents.OnGenderChange -> {
Log.i(TAG, "onEvent: OnGenderChange -> ${event.gender}")
_uiState.value = _uiState.value.copy(gender = event.gender, genderError = null)
}

is AddPersonEvents.OnAvatarChange -> {

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

AddPersonEvents.OnSavePerson -> {
Log.i(TAG, "onEvent: OnSavePerson")
savePerson()
if (_uiState.value.id != null) {
updatePerson()
} else {
savePerson()
}
}
}
}

fun loadPersonDetails(personId: Long) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
val person = peopleUseCases.getPersonById(personId)
person.collect { person ->
if (person != null) {
_uiState.value = _uiState.value.copy(
id = person.id,
firstName = person.firstName,
secondName = person.secondName,
place = person.place,
gender = person.gender,
avatar = person.avatar,
time = person.time,
note = person.note,
)
}
}
}
}
}

fun resetForm() {
_uiState.value = AddPersonUiState()
}

private fun savePerson() {
if (validateInput()) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
val person = People(
firstName = _uiState.value.firstName,
secondName = _uiState.value.secondName,
place = _uiState.value.place,
time = _uiState.value.time,
note = _uiState.value.note,
gender = _uiState.value.gender,
avatar = _uiState.value.avatar
)
peopleUseCases.insertPerson(person)
}
_isPersonSaved.value = true
}
}
}

private fun updatePerson() {
if (validateInput()) {
Log.i(TAG,"validateInput on update: input are valid!")
viewModelScope.launch {
withContext(Dispatchers.IO) {
val person :People = _uiState.value.id?.let {
People(
id = it,
firstName = _uiState.value.firstName,
secondName = _uiState.value.secondName,
place = _uiState.value.place,
time = _uiState.value.time,
note = _uiState.value.note,
gender = _uiState.value.gender,
avatar = _uiState.value.avatar
)
}!!
peopleUseCases.updatePerson(person)
}
_isPersonSaved.value = true
}
}
}

private fun validateInput(): Boolean {
val firstNameResult = addPersonUseCases.validateFirstNameUseCase(_uiState.value.firstName)
val secondNameResult =
addPersonUseCases.validateSecondNameUseCase(_uiState.value.secondName)
val secondNameResult = addPersonUseCases.validateSecondNameUseCase(_uiState.value.secondName)
val placeResult = addPersonUseCases.validatePlaceUseCase(_uiState.value.place)
val timeResult = addPersonUseCases.validateTimeUseCase(_uiState.value.time)
val genderResult = addPersonUseCases.validateGenderSelectionUseCase(_uiState.value.gender)
Log.d(TAG, "savePerson: $genderResult")

val hasError = listOf(
firstNameResult,
secondNameResult,
placeResult,
timeResult,
genderResult
).any { !it.successful }

if (hasError) {
Log.e(TAG, "savePerson: There are some unvalidated inputs")
Log.e(TAG, "savePerson: ${_uiState.value}")
_uiState.value = _uiState.value.copy(
firstNameError = firstNameResult.errorMessage,
secondNameError = secondNameResult.errorMessage,
Expand All @@ -96,30 +153,12 @@ class AddPersonViewModel @Inject constructor(
genderError = genderResult.errorMessage
)
_isPersonSaved.value = false

} else {
viewModelScope.launch {
withContext(Dispatchers.IO) {
Log.i(TAG, "savePerson: ${_uiState.value}")
val person = People(
firstName = _uiState.value.firstName,
secondName = _uiState.value.secondName,
place = _uiState.value.place,
time = _uiState.value.time,
note = _uiState.value.note,
gender = _uiState.value.gender,
avatar = _uiState.value.avatar
)
peopleUseCases.insertPerson(person)
}
_isPersonSaved.value = true

}
return false
}
return true
}

companion object {
private const val TAG = "AddPersonViewModel"
}

}
}
Loading

0 comments on commit 13ebe8b

Please sign in to comment.