From 6446045296ad222dcc865318bd61aea6bfd482b7 Mon Sep 17 00:00:00 2001 From: krzys Date: Tue, 7 Nov 2023 18:32:56 +0100 Subject: [PATCH] Working Note feature. --- .../eltescode/core_ui/components/TextField.kt | 17 ++++- core_ui/src/main/res/values/strings.xml | 3 + .../add_edit_note/AddEditNoteScreen.kt | 36 ++++++++--- .../add_edit_note/AddEditNoteViewModel.kt | 19 ++++-- .../add_edit_note/NoteTextFieldState.kt | 7 ++- .../notes_presentation/notes/NotesScreen.kt | 12 ++-- .../notes/NotesViewModel.kt | 5 -- .../notes/comopnents/NoteItem.kt | 1 + .../search_screen/SearchPhotoScreen.kt | 63 +++++++++++++------ .../utils/SearchPhotoScreenState.kt | 6 +- 10 files changed, 122 insertions(+), 47 deletions(-) diff --git a/core_ui/src/main/java/com/eltescode/core_ui/components/TextField.kt b/core_ui/src/main/java/com/eltescode/core_ui/components/TextField.kt index eaf35eb..1372f2d 100644 --- a/core_ui/src/main/java/com/eltescode/core_ui/components/TextField.kt +++ b/core_ui/src/main/java/com/eltescode/core_ui/components/TextField.kt @@ -9,8 +9,6 @@ import com.eltescode.core_ui.ui.SilverColors.Companion.color4c4e50 @OptIn(ExperimentalMaterial3Api::class) - - @Composable fun texFieldColors_1(): TextFieldColors { @@ -22,6 +20,21 @@ fun texFieldColors_1(): TextFieldColors { focusedLabelColor = Color.Black, focusedLeadingIconColor = Color.Black, cursorColor = Color.Black + ) +} +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun texFieldColors_2(): TextFieldColors { + + return TextFieldDefaults.textFieldColors( + containerColor = Color.Transparent, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + unfocusedSupportingTextColor = Color.Black, + textColor = Color.Black, + focusedLabelColor = Color.Black, + focusedLeadingIconColor = Color.Black, + cursorColor = Color.Black ) } \ No newline at end of file diff --git a/core_ui/src/main/res/values/strings.xml b/core_ui/src/main/res/values/strings.xml index 8134293..e5627a6 100644 --- a/core_ui/src/main/res/values/strings.xml +++ b/core_ui/src/main/res/values/strings.xml @@ -32,4 +32,7 @@ Note deleted Undo Your notes + Search photo… + Enter some content… + Enter title… \ No newline at end of file diff --git a/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/AddEditNoteScreen.kt b/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/AddEditNoteScreen.kt index 62503a9..90b3679 100644 --- a/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/AddEditNoteScreen.kt +++ b/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/AddEditNoteScreen.kt @@ -1,6 +1,9 @@ package com.eltescode.notes_presentation.add_edit_note +import android.content.Context import androidx.compose.animation.Animatable +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.AnimationVector4D import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -32,10 +35,12 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.eltescode.notes_presentation.add_edit_note.components.TransparentTextField import com.eltescode.notes_presentation.model.NoteDisplayable +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch @@ -53,6 +58,8 @@ fun AddEditNoteScreen( remember { Animatable(Color(if (noteColor != -1) noteColor else viewModel.noteColor.value)) } val scope = rememberCoroutineScope() + val context = LocalContext.current + LaunchedEffect(key1 = Unit, block = { viewModel.eventFlow.collectLatest { event -> when (event) { @@ -68,8 +75,26 @@ fun AddEditNoteScreen( } }) + AddEditNoteScreen( + titleState = titleState, + contentState = contentState, + noteBackgroundAnimatable = noteBackgroundAnimatable, + scope = scope, + context = context + ) +} +@Composable +private fun AddEditNoteScreen( + titleState: NoteTextFieldState, + contentState: NoteTextFieldState, + viewModel: AddEditNoteViewModel = hiltViewModel(), + noteBackgroundAnimatable: Animatable, + scope: CoroutineScope, + context: Context + +) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Column( @@ -110,29 +135,27 @@ fun AddEditNoteScreen( } viewModel.onEvent(AddEditNoteEvent.ChangeColor(colorInt)) } - ) } } Spacer(modifier = Modifier.height(16.dp)) TransparentTextField( text = titleState.text, - hint = titleState.hint, + hint = titleState.hint.asString(context), onValueChange = { viewModel.onEvent(AddEditNoteEvent.EnteredTitle(it)) }, onFocusChange = { viewModel.onEvent(AddEditNoteEvent.ChangeTitleFocus(it)) }, isHintVisible = titleState.isHintVisible, singleLine = true, -// textStyle = MaterialTheme.typography.h5 - ) + + ) Spacer(modifier = Modifier.height(16.dp)) TransparentTextField( text = contentState.text, - hint = contentState.hint, + hint = contentState.hint.asString(context), onValueChange = { viewModel.onEvent(AddEditNoteEvent.EnteredContent(it)) }, onFocusChange = { viewModel.onEvent(AddEditNoteEvent.ChangeContentFocus(it)) }, isHintVisible = contentState.isHintVisible, singleLine = false, -// textStyle = MaterialTheme.typography.body1, modifier = Modifier.fillMaxHeight() ) } @@ -146,5 +169,4 @@ fun AddEditNoteScreen( Icon(imageVector = Icons.Default.Save, contentDescription = null) } } - } \ No newline at end of file diff --git a/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/AddEditNoteViewModel.kt b/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/AddEditNoteViewModel.kt index e4bded7..465a16e 100644 --- a/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/AddEditNoteViewModel.kt +++ b/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/AddEditNoteViewModel.kt @@ -7,7 +7,8 @@ import androidx.compose.ui.graphics.toArgb import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.eltescode.notes.features.note.presentation.add_edit_note.NoteTextFieldState +import com.eltescode.core_ui.R +import com.eltescode.core_ui.utils.UiText import com.eltescode.notes_domain.model.Note import com.eltescode.notes_domain.repository.Result import com.eltescode.notes_domain.use_cases.NoteUseCases @@ -30,14 +31,14 @@ class AddEditNoteViewModel @Inject constructor( private val _noteTitle = mutableStateOf( NoteTextFieldState( - hint = "Enter title..." + hint = UiText.StringResource(R.string.enter_title_hint) ) ) val noteTitle: State = _noteTitle private val _noteContent = mutableStateOf( NoteTextFieldState( - hint = "Enter some content..." + hint = UiText.StringResource(R.string.enter_content_hint) ) ) val noteContent: State = _noteContent @@ -57,9 +58,15 @@ class AddEditNoteViewModel @Inject constructor( noteUseCases.getNoteUseCase(UUID.fromString(noteId))?.also { note: Note -> currentNoteId = UUID.fromString(note.noteId) _noteTitle.value = - noteTitle.value.copy(text = note.title, isHintVisible = false) + noteTitle.value.copy( + text = note.title, + isHintVisible = note.title.isBlank() + ) _noteContent.value = - noteContent.value.copy(text = note.content, isHintVisible = false) + noteContent.value.copy( + text = note.content, + isHintVisible = note.content.isBlank() + ) _noteColor.value = note.color } } @@ -123,7 +130,7 @@ class AddEditNoteViewModel @Inject constructor( } } catch (e: InvalidNoteException) { - _eventFlow.emit(UiEvent.ShowSnackBar("Error: $e")) + _eventFlow.emit(UiEvent.ShowSnackBar(e.message.toString())) } } } diff --git a/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/NoteTextFieldState.kt b/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/NoteTextFieldState.kt index 1b29829..a092129 100644 --- a/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/NoteTextFieldState.kt +++ b/notes_presentation/src/main/java/com/eltescode/notes_presentation/add_edit_note/NoteTextFieldState.kt @@ -1,7 +1,10 @@ -package com.eltescode.notes.features.note.presentation.add_edit_note +package com.eltescode.notes_presentation.add_edit_note + +import com.eltescode.core_ui.utils.UiText + data class NoteTextFieldState( val text: String = "", - val hint: String = "", + val hint: UiText, val isHintVisible: Boolean = true ) diff --git a/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/NotesScreen.kt b/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/NotesScreen.kt index d29ab67..dcc2aa8 100644 --- a/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/NotesScreen.kt +++ b/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/NotesScreen.kt @@ -5,6 +5,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -68,6 +69,7 @@ fun NotesScreen( is UiEvent.OnNextScreen -> { onNextScreen(event.route) } + is UiEvent.ShowSnackBar -> { scope.launch { snackBarHostState.currentSnackbarData?.dismiss() @@ -83,6 +85,7 @@ fun NotesScreen( } } } + else -> Unit } } @@ -90,13 +93,14 @@ fun NotesScreen( NotesScreen( state = state, - onEvent = viewModel::onEvent + onEvent = viewModel::onEvent, ) - } +@OptIn(ExperimentalFoundationApi::class) @Composable fun NotesScreen(state: NotesState, onEvent: (NotesEvent) -> Unit) { + Box( modifier = Modifier .fillMaxSize() @@ -134,10 +138,11 @@ fun NotesScreen(state: NotesState, onEvent: (NotesEvent) -> Unit) { } Spacer(modifier = Modifier.height(16.dp)) LazyColumn(modifier = Modifier.fillMaxSize(), content = { - items(state.notes) { note -> + items(items = state.notes, key = { item -> item.noteId }) { note -> NoteItem( note = note, modifier = Modifier + .animateItemPlacement() .fillMaxWidth() .clickable { onEvent( @@ -150,7 +155,6 @@ fun NotesScreen(state: NotesState, onEvent: (NotesEvent) -> Unit) { onDeleteClick = { onEvent(NotesEvent.DeleteNote(note)) }) - Spacer(modifier = Modifier.height(16.dp)) } }) } diff --git a/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/NotesViewModel.kt b/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/NotesViewModel.kt index a80127d..433a25f 100644 --- a/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/NotesViewModel.kt +++ b/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/NotesViewModel.kt @@ -1,6 +1,5 @@ package com.eltescode.notes_presentation.notes -import android.util.Log import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel @@ -42,13 +41,9 @@ class NotesViewModel @Inject constructor(private val noteUseCases: NoteUseCases) private var job: Job? = null - private var job2: Job? = null init { - - viewModelScope.launch { - Log.d("SYNC", "${noteUseCases.checkSyncNeedUseCase()}") if (noteUseCases.checkSyncNeedUseCase()) { syncData() getNotes() diff --git a/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/comopnents/NoteItem.kt b/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/comopnents/NoteItem.kt index f52fb5b..e32dd5e 100644 --- a/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/comopnents/NoteItem.kt +++ b/notes_presentation/src/main/java/com/eltescode/notes_presentation/notes/comopnents/NoteItem.kt @@ -68,4 +68,5 @@ fun NoteItem( Icon(imageVector = Icons.Default.Delete, contentDescription = null) } } + Spacer(modifier = Modifier.height(16.dp)) } \ No newline at end of file diff --git a/photo_presentation/src/main/java/com/eltescode/photo_presentation/search_screen/SearchPhotoScreen.kt b/photo_presentation/src/main/java/com/eltescode/photo_presentation/search_screen/SearchPhotoScreen.kt index 0a6bcbc..a23a292 100644 --- a/photo_presentation/src/main/java/com/eltescode/photo_presentation/search_screen/SearchPhotoScreen.kt +++ b/photo_presentation/src/main/java/com/eltescode/photo_presentation/search_screen/SearchPhotoScreen.kt @@ -1,29 +1,40 @@ package com.eltescode.photo_presentation.search_screen +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height 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.foundation.lazy.grid.items +import androidx.compose.foundation.shape.CutCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Search import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import com.eltescode.core_ui.R +import com.eltescode.core_ui.components.texFieldColors_2 +import com.eltescode.core_ui.ui.GreenColors import com.eltescode.core_ui.utils.UiEvent import com.eltescode.photo_presentation.components.PhotoDialog import com.eltescode.photo_presentation.components.PhotoItem @@ -38,7 +49,6 @@ fun SearchPhotoScreen( val state = viewModel.state LaunchedEffect(key1 = true, block = { - viewModel.uiEvent.collect { event -> when (event) { is UiEvent.ShowSnackBar -> {} @@ -47,11 +57,9 @@ fun SearchPhotoScreen( } else -> Unit - } } }) - val newState = state.photoDialogState.photoToSetProfilePicture SearchPhotoScreen( state = state, onEvent = viewModel::onEvent @@ -70,22 +78,41 @@ fun SearchPhotoScreen( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - TextField( - value = state.query, - onValueChange = { onEvent(SearchPhotoEvent.OnQueryEntered(it)) }, - trailingIcon = { - IconButton( - onClick = { onEvent(SearchPhotoEvent.OnPhotoSearch) }, - content = { - Icon( - imageVector = Icons.Default.Search, - contentDescription = null + Box( + modifier = Modifier + .fillMaxWidth() + .height(65.dp) + .clip(CutCornerShape(bottomStart = 10.dp, bottomEnd = 30.dp)) + .background( + Brush.linearGradient( + listOf( + GreenColors.color008c15, + GreenColors.colorCfea75, + Color.Companion.White ) - } - ) - }, - modifier = Modifier.fillMaxWidth() - ) + ) + ), + contentAlignment = Alignment.TopCenter + ) { + TextField( + value = state.query, + onValueChange = { onEvent(SearchPhotoEvent.OnQueryEntered(it)) }, + trailingIcon = { + IconButton( + onClick = { onEvent(SearchPhotoEvent.OnPhotoSearch) }, + content = { + Icon( + imageVector = Icons.Default.Search, + contentDescription = null + ) + } + ) + }, + colors = texFieldColors_2(), + modifier = Modifier.fillMaxWidth(), + placeholder = { Text(text = stringResource(id = R.string.search_photo_hint)) } + ) + } LazyVerticalGrid( columns = GridCells.Fixed(3), modifier = Modifier.fillMaxWidth(), diff --git a/photo_presentation/src/main/java/com/eltescode/photo_presentation/utils/SearchPhotoScreenState.kt b/photo_presentation/src/main/java/com/eltescode/photo_presentation/utils/SearchPhotoScreenState.kt index 57921e5..67958fe 100644 --- a/photo_presentation/src/main/java/com/eltescode/photo_presentation/utils/SearchPhotoScreenState.kt +++ b/photo_presentation/src/main/java/com/eltescode/photo_presentation/utils/SearchPhotoScreenState.kt @@ -5,11 +5,11 @@ import com.eltescode.photo_domain.model.Photo data class SearchPhotoScreenState( val photos: List = emptyList(), val isSearching: Boolean = false, - val query: String = "dog", - val photoDialogState: PhotoDialogState = PhotoDialogState() + val query: String = "", + val photoDialogState: PhotoDialogState = PhotoDialogState(), ) data class PhotoDialogState( val isDialogVisible: Boolean = false, - val photoToSetProfilePicture: String = "xxx" + val photoToSetProfilePicture: String = "" )