diff --git a/petJournal/app/build.gradle.kts b/petJournal/app/build.gradle.kts index 567b704f..c312105e 100644 --- a/petJournal/app/build.gradle.kts +++ b/petJournal/app/build.gradle.kts @@ -120,7 +120,8 @@ dependencies { androidTestImplementation("androidx.test:runner:1.5.2") androidTestImplementation("androidx.arch.core:core-testing:2.1.0") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.2") + androidTestImplementation("io.mockk:mockk-android:1.12.0") + androidTestImplementation("io.mockk:mockk-agent:1.12.0") testImplementation("junit:junit:4.13.2") testImplementation("io.mockk:mockk:1.12.0") testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.25") diff --git a/petJournal/app/src/androidTest/java/com/soujunior/petjournal/componentes/PetFilterListTest.kt b/petJournal/app/src/androidTest/java/com/soujunior/petjournal/componentes/PetFilterListTest.kt new file mode 100644 index 00000000..359d3c7f --- /dev/null +++ b/petJournal/app/src/androidTest/java/com/soujunior/petjournal/componentes/PetFilterListTest.kt @@ -0,0 +1,90 @@ +package com.soujunior.petjournal.componentes + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.hasParent +import androidx.compose.ui.test.hasTestTag +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performClick +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +import androidx.compose.ui.res.painterResource +import com.soujunior.petjournal.R // Para carregar imagens de preview +import com.soujunior.petjournal.ui.components.PetFilterList +import com.soujunior.petjournal.ui.components.Pets +import io.mockk.mockk +import org.mockito.Mockito.verify + +@RunWith(AndroidJUnit4::class) +class PetFilterListTest { + + @get:Rule + val composeTestRule = createComposeRule() + + private val mockOnSelectedPet: (String) -> Unit = mockk(relaxed = true) + + private val dummyPetList = listOf( + Pets( + id = 1, + imageRes = null, + name = "Jujuba" + ), + Pets( + id = 2, + imageRes = null, + name = "Alfredo" + ) + ) + + @Before + fun setUp() { + composeTestRule.setContent { + val listWithPainters = dummyPetList.map { + it.copy(imageRes = painterResource(id = R.drawable.penguim)) + } + + PetFilterList( + listPet = listWithPainters, + onSelectedPet = mockOnSelectedPet + ) + } + } + + @Test + fun test_PetFilterList_DisplaysItems() { + composeTestRule.onNodeWithTag("PetItem_Todos").assertIsDisplayed() + composeTestRule.onNodeWithTag("PetItem_Jujuba").assertIsDisplayed() + composeTestRule.onNodeWithTag("PetItem_Alfredo").assertIsDisplayed() + } + + @Test + fun test_PetFilterList_SelectsAndDeselectsPet() { + val jujubaSelectedIconMatcher = + hasParent(hasTestTag("PetItem_Jujuba")) and hasTestTag("SelectedIcon") + + composeTestRule.onNode(jujubaSelectedIconMatcher).assertDoesNotExist() + + composeTestRule.onNodeWithTag("PetItem_Jujuba").performClick() + + composeTestRule.onNode(jujubaSelectedIconMatcher).assertIsDisplayed() + + composeTestRule.onNodeWithTag("PetItem_Jujuba").performClick() + + composeTestRule.onNode(jujubaSelectedIconMatcher).assertDoesNotExist() + } + + @Test + fun test_PetFilterList_CallbackIsCalledOnSelection() { + composeTestRule.onNodeWithTag("PetItem_Alfredo").performClick() + + verify { mockOnSelectedPet("Alfredo") } + + composeTestRule.onNodeWithTag("PetItem_Todos").performClick() + + verify { mockOnSelectedPet("Todos") } + } +} \ No newline at end of file diff --git a/petJournal/app/src/androidTest/java/com/soujunior/petjournal/screen_pets/RegisterPetScreenTest.kt b/petJournal/app/src/androidTest/java/com/soujunior/petjournal/screen_pets/RegisterPetScreenTest.kt index 8c302940..a1f83870 100644 --- a/petJournal/app/src/androidTest/java/com/soujunior/petjournal/screen_pets/RegisterPetScreenTest.kt +++ b/petJournal/app/src/androidTest/java/com/soujunior/petjournal/screen_pets/RegisterPetScreenTest.kt @@ -60,10 +60,10 @@ class RegisterPetScreenTest { composeTestRule.setContent { InputText( - titleText = stringResource(R.string.pet_name), placeholderText = stringResource(R.string.placeholder_name_pet), + titleText = stringResource(R.string.pet_name), textValue = actualText, - onEvent = { actualText = it } + onEvent = { actualText = it }, ) } @@ -81,9 +81,9 @@ class RegisterPetScreenTest { InputText( titleText = stringResource(R.string.pet_name), textValue = "", - onEvent = {}, isError = true, textError = listOf(errorMessage), + onEvent = {}, ) } diff --git a/petJournal/app/src/androidTest/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerTaskScreen/components/ScreenRegisterTaskTest.kt b/petJournal/app/src/androidTest/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerTaskScreen/components/ScreenRegisterTaskTest.kt new file mode 100644 index 00000000..1970ae55 --- /dev/null +++ b/petJournal/app/src/androidTest/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerTaskScreen/components/ScreenRegisterTaskTest.kt @@ -0,0 +1,427 @@ +package com.soujunior.petjournal.ui.screens_app.screens_pets.registerTaskScreen.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.hasSetTextAction +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.performTextInput +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.soujunior.petjournal.ui.components.GroupSelectableButton +import com.soujunior.petjournal.ui.components.InputText +import com.soujunior.petjournal.ui.components.PetFilterList +import com.soujunior.petjournal.ui.components.Pets +import com.soujunior.petjournal.ui.components.SelectableButtonInfo +import com.soujunior.petjournal.ui.components.TextFieldCustom +import com.soujunior.petjournal.ui.components.TransactionTypeSelector +import com.soujunior.petjournal.ui.components.task.OneOffTask +import com.soujunior.petjournal.ui.components.task.RecurringTask +import com.soujunior.petjournal.ui.theme.ColorCustom +import com.soujunior.petjournal.ui.util.TransactionType +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ScreenRegisterTaskTest { + + @get:Rule + val composeTestRule = createComposeRule() + + private val pets = listOf( + Pets(id = 1, name = "Rex"), + Pets(id = 2, name = "Mia"), + Pets(id = 3, name = "Thor") + ) + + private val sampleListOfTasks = listOf( + SelectableButtonInfo("Vacinas", ColorCustom.color_selectable_button_1), + SelectableButtonInfo("Consultas", ColorCustom.color_selectable_button_2), + SelectableButtonInfo("Remédios", ColorCustom.color_selectable_button_3) + ) + + @Test + fun groupSelectableButton_displaysTitleCorrectly() { + composeTestRule.setContent { + GroupSelectableButton( + listOfTasks = sampleListOfTasks, + onSelection = {} + ) + } + + composeTestRule.onNodeWithText("Essa tarefa é...") + .assertIsDisplayed() + } + + @Test + fun groupSelectableButton_displaysAllButtons() { + composeTestRule.setContent { + GroupSelectableButton( + listOfTasks = sampleListOfTasks, + onSelection = {} + ) + } + + sampleListOfTasks.forEach { buttonInfo -> + composeTestRule.onNodeWithText(buttonInfo.title).assertIsDisplayed() + } + } + + @Test + fun groupSelectableButton_selectsAndDeselectsButtonCorrectly() { + composeTestRule.setContent { + GroupSelectableButton( + listOfTasks = sampleListOfTasks, + onSelection = {} + ) + } + + val firstButton = sampleListOfTasks[0] + + composeTestRule.onNodeWithText(firstButton.title).performClick() + + composeTestRule.onNodeWithText(firstButton.title).performClick() + } + + @Test + fun groupSelectableButton_selectsOnlyOneButtonAtATime_ifLogicImpliesThat() { + composeTestRule.setContent { + GroupSelectableButton( + listOfTasks = sampleListOfTasks, + onSelection = {} + ) + } + + val firstButton = sampleListOfTasks[0] + val secondButton = sampleListOfTasks[1] + + composeTestRule.onNodeWithText(firstButton.title).performClick() + + composeTestRule.onNodeWithText(secondButton.title).performClick() + + } + + @Test + fun inputText_displaysTitleCorrectly() { + val testTitle = "Nome da Tarefa" + composeTestRule.setContent { + InputText( + titleText = testTitle, + textValue = "", + onEvent = {}, + ) + } + + composeTestRule.onNodeWithText(testTitle).assertIsDisplayed() + } + + @Test + fun inputText_displaysPlaceholder_whenTextValueIsEmptyAndNotMasked() { + val testPlaceholder = "Digite o nome da tarefa" + composeTestRule.setContent { + InputText( + placeholderText = testPlaceholder, + textValue = "", + onEvent = {}, + ) + } + + composeTestRule.onNodeWithText(testPlaceholder).assertIsDisplayed() + } + + @Test + fun inputText_doesNotDisplayPlaceholder_whenTextValueIsNotEmpty() { + val testPlaceholder = "Digite o nome da tarefa" + composeTestRule.setContent { + InputText( + placeholderText = testPlaceholder, + textValue = "Minha Tarefa", + onEvent = {}, + ) + } + + composeTestRule.onNodeWithText(testPlaceholder).assertDoesNotExist() + } + + @Test + fun inputText_displaysErrorMessages_whenTextErrorIsProvided() { + val errorMessages = listOf("Nome muito curto", "Nome inválido") + composeTestRule.setContent { + InputText( + textValue = "Ops", + isError = true, + textError = errorMessages, + onEvent = {}, + ) + } + errorMessages.forEach { errorMessage -> + composeTestRule.onNodeWithText(errorMessage).assertIsDisplayed() + } + } + + private val title = "Descrição" + private val placeholder = "Digite a descrição aqui..." + + @Test + fun shouldDisplayTitleAndPlaceholder() { + composeTestRule.setContent { + TextFieldCustom( + title = title, + placeholder = placeholder, + value = "", + onValueChange = {} + ) + } + + composeTestRule.onNodeWithText(title).assertIsDisplayed() + + composeTestRule.onNodeWithText(placeholder).assertIsDisplayed() + } + + @Test + fun shouldUpdateTextWhenTyping() { + var textValue = "" + composeTestRule.setContent { + TextFieldCustom( + title = title, + placeholder = placeholder, + value = textValue, + onValueChange = { textValue = it } + ) + } + + val inputText = "Descrição do produto" + + composeTestRule.onNode( + hasSetTextAction() + ).performTextInput(inputText) + + assert(textValue == inputText) + } + + @Test + fun shouldDisplayTitleAndAllOption() { + composeTestRule.setContent { + PetFilterList(listPet = pets) + } + + composeTestRule.onNodeWithText("Quais pets precisam dessa tarefa?").assertIsDisplayed() + + composeTestRule.onNodeWithText("Todos").assertIsDisplayed() + } + + @Test + fun shouldDisplayAllPetsFromList() { + composeTestRule.setContent { + PetFilterList(listPet = pets) + } + + pets.forEach { pet -> + composeTestRule.onNodeWithText(pet.name!!).assertIsDisplayed() + } + } + + @Test + fun shouldSelectAndUnselectPet() { + var selected: String? = null + composeTestRule.setContent { + PetFilterList( + listPet = pets, + onSelectedPet = { selected = it } + ) + } + + composeTestRule.onNodeWithText("Rex").performClick() + assert(selected == "Rex") + + composeTestRule.onNodeWithText("Rex").performClick() + assert(selected == "") + } + + @Test + fun shouldSelectAllOption() { + var selected: String? = null + composeTestRule.setContent { + PetFilterList( + listPet = pets, + onSelectedPet = { selected = it } + ) + } + + composeTestRule.onNodeWithText("Todos").performClick() + assert(selected == "Todos") + + composeTestRule.onNodeWithText("Todos").performClick() + assert(selected == "") + } + + @Test + fun shouldShowRecurringTaskWhenRecurrentSelected() { + composeTestRule.setContent { + var selectedType: TransactionType? = null + + Column { + TransactionTypeSelector( + onSelectionChanged = { type -> + selectedType = type + } + ) + + when (selectedType) { + TransactionType.Recurrent -> { + RecurringTask( + setOf(), + onAmPmSelector = {}, + onTime = { _, _ -> }, + onWeekDaySelected = {}, + onDaySelected = {} + ) + } + + TransactionType.OneOff -> { + OneOffTask( + onDateSelected = {}, + onAmPmSelector = {}, + onTime = { _, _ -> } + ) + } + + null -> {} + } + } + } + + composeTestRule.onNodeWithText("Recorrente").performClick() + } + + @Test + fun test_TransactionTypeSelector_TogglesConditionalUI_Correctly() { + + composeTestRule.setContent { + var selectedType: TransactionType? = null + + Column { + TransactionTypeSelector( + onSelectionChanged = { type -> + selectedType = type + } + ) + + when (selectedType) { + TransactionType.Recurrent -> { + Box(modifier = Modifier.testTag("RecurringTaskComponent")) { + RecurringTask( + setOf(), + onAmPmSelector = {}, + onTime = { _, _ -> }, + onWeekDaySelected = {}, + onDaySelected = {} + ) + } + } + + TransactionType.OneOff -> { + Box(modifier = Modifier.testTag("OneOffTaskComponent")) { + OneOffTask( + onDateSelected = {}, + onAmPmSelector = {}, + onTime = { _, _ -> } + ) + } + } + + null -> {} + } + } + } + + composeTestRule.onNodeWithTag("RecurringTaskComponent").assertDoesNotExist() + composeTestRule.onNodeWithTag("OneOffTaskComponent").assertDoesNotExist() + + composeTestRule.onNodeWithTag("TaskRecurrent").performClick() + + composeTestRule.onNodeWithTag("RecurringTaskComponent").assertIsDisplayed() + composeTestRule.onNodeWithTag("OneOffTaskComponent").assertDoesNotExist() + + composeTestRule.onNodeWithTag("TaskOneOff").performClick() + + composeTestRule.onNodeWithTag("RecurringTaskComponent").assertDoesNotExist() + composeTestRule.onNodeWithTag("OneOffTaskComponent").assertIsDisplayed() + } + + @Test + fun shouldShowOneOffTaskWhenOneOffSelected() { + composeTestRule.setContent { + var selectedType: TransactionType? = null + + Column { + TransactionTypeSelector( + onSelectionChanged = { type -> + selectedType = type + } + ) + + when (selectedType) { + TransactionType.Recurrent -> { + RecurringTask( + setOf(), + onAmPmSelector = {}, + onTime = { _, _ -> }, + onWeekDaySelected = {}, + onDaySelected = {} + ) + } + + TransactionType.OneOff -> { + OneOffTask( + onDateSelected = {}, + onAmPmSelector = {}, + onTime = { _, _ -> } + ) + } + + null -> {} + } + } + } + + composeTestRule.onNodeWithText("Pontual").performClick() + } + + @Test + fun shouldUpdateObservationText() { + composeTestRule.setContent { + val ob = remember { mutableStateOf("") } + + TextFieldCustom( + title = "Observação", + placeholder = "Digite aqui a sua observação", + value = ob.value, + onValueChange = { ob.value = it }, + ) + } + + composeTestRule.onNodeWithText("Digite aqui a sua observação").assertIsDisplayed() + + val text = "Precisa dar o remédio às 14h" + composeTestRule.onNodeWithText("Digite aqui a sua observação").performTextInput(text) + } + + @Test + fun test_TransactionTypeSelector_ShowsConditionalUI() { + composeTestRule.onNodeWithTag("RecurringTaskComponent").assertDoesNotExist() + + composeTestRule.onNodeWithTag("TaskRecurrent").performClick() + + composeTestRule.onNodeWithTag("RecurringTaskComponent").assertIsDisplayed() + composeTestRule.onNodeWithTag("OneOffTaskComponent").assertDoesNotExist() + } + +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/navigation/MainActivity.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/navigation/MainActivity.kt index e4db3ebb..651c5e25 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/navigation/MainActivity.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/navigation/MainActivity.kt @@ -7,8 +7,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect import androidx.compose.ui.graphics.Color import androidx.core.view.WindowCompat +import androidx.navigation.compose.rememberNavController import com.google.accompanist.systemuicontroller.rememberSystemUiController -import com.soujunior.petjournal.ui.components.ActiveMonthsComponent +import com.soujunior.petjournal.ui.screens_app.screens_pets.registerTaskScreen.components.ScreenRegisterTask import com.soujunior.petjournal.ui.theme.PetJournalTheme class MainActivity : ComponentActivity() { @@ -17,8 +18,7 @@ class MainActivity : ComponentActivity() { WindowCompat.setDecorFitsSystemWindows(window, false) setContent { ChangeSystemBars() -// PresentationManager() - ActiveMonthsComponent(activeMonths = setOf("Jan", "Mar", "Mai")) + PresentationManager() } } } diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/navigation/NavHostElements.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/navigation/NavHostElements.kt index 75918754..c9a1715d 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/navigation/NavHostElements.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/navigation/NavHostElements.kt @@ -55,8 +55,7 @@ fun NavHostMainContent() { composable("account_manager") { AccountManager() } composable("tutorScreen") { TutorScreen(navController) } composable("pets/introRegisterPet") { IntroRegisterPetScreen(navController) } -// composable("pets/introRegisterPet") { RegisterPetScreen(navController) } - composable("pets/petList") { PetListScreen(navController) } + composable("pets/petListScreen") { PetListScreen(navController) } composable("pets/registerPet") { RegisterPetScreen(navController) } composable("pets/speciesChoice") { SpeciesChoiceScreen(navController) } diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/ActiveMonthsComponent.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/ActiveMonthsComponent.kt index 5a83c5b6..36ad6244 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/ActiveMonthsComponent.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/ActiveMonthsComponent.kt @@ -74,7 +74,8 @@ fun ActiveMonthsComponent(activeMonths: Set) { Text( text = month, style = MaterialTheme.typography.labelLarge, - color = if (isActive) MaterialTheme.colorScheme.onPrimary else ColorCustom.color_border_dialog, + //todo: corrigir ColorCustom.color_border_dialog, + color = if (isActive) MaterialTheme.colorScheme.onPrimary else ColorCustom.error_color, fontWeight = FontWeight(400) ) } @@ -104,7 +105,8 @@ fun ActiveMonthsComponent(activeMonths: Set) { ) { Text( text = month, - color = if (isActive) MaterialTheme.colorScheme.onPrimary else ColorCustom.color_border_dialog, + //todo: corrigir ColorCustom.color_border_dialog, + color = if (isActive) MaterialTheme.colorScheme.onPrimary else ColorCustom.error_color, fontWeight = FontWeight(400) ) } diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/Button3.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/Button3.kt index f16788c2..d2b37434 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/Button3.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/Button3.kt @@ -21,6 +21,8 @@ import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import ir.kaaveh.sdpcompose.sdp import ir.kaaveh.sdpcompose.ssp @@ -31,6 +33,8 @@ fun Button3( enableButton: Boolean, modifier: Modifier = Modifier, text: String = "Button", + textSize: TextUnit = 12.ssp, + contentPaddingValues : Dp = 12.sdp, buttonColor: ButtonColors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.background), textColor: Color = MaterialTheme.colorScheme.primary, isLoading: Boolean = false @@ -54,20 +58,20 @@ fun Button3( ) , border = BorderStroke( - width = 2.sdp, + width = 1.sdp, color = Color(0xFF959EA6) ), shape = RoundedCornerShape(size = 50.dp), colors = buttonColor, - contentPadding = PaddingValues(12.sdp) + contentPadding = PaddingValues(contentPaddingValues) ) { if (!isLoading) { Text( text = text, - fontWeight = FontWeight.W900, - fontSize = 12.ssp, - style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.W500, + fontSize = textSize, + style = MaterialTheme.typography.headlineLarge, color = textColor ) } else { diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DateInputText.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DateInputText.kt index e1d48763..9221ee6d 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DateInputText.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DateInputText.kt @@ -47,6 +47,7 @@ import ir.kaaveh.sdpcompose.ssp @Composable fun DateInputText( modifier: Modifier = Modifier, + textTitleModifier: Modifier = Modifier, textInputModifier: Modifier = Modifier, placeholderText: String = "Placeholder", titleText: String = "Title", @@ -67,9 +68,9 @@ fun DateInputText( color = MaterialTheme.colorScheme.scrim, style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight(500), - modifier = Modifier + modifier = textTitleModifier .fillMaxWidth() - .padding(start = 24.sdp, end = 24.sdp) + .padding(end = 24.sdp) ) } Row { diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DropDown.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DropDown.kt index e9dbf7e8..c75537cc 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DropDown.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DropDown.kt @@ -47,6 +47,7 @@ import ir.kaaveh.sdpcompose.sdp @Composable fun DropDown( modifier: Modifier = Modifier, + textTitleModifier: Modifier = Modifier, textInputModifier: Modifier = Modifier, placeholderText: String = "Porte do seu pet", titleText: String = "Title", @@ -66,9 +67,7 @@ fun DropDown( color = MaterialTheme.colorScheme.scrim, style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight(500), - modifier = Modifier - .fillMaxWidth() - .padding(start = 24.sdp, end = 24.sdp) + modifier = textTitleModifier.fillMaxWidth().padding(end = 24.sdp) ) } Row { diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DualActionButton.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DualActionButton.kt index 5e752de0..d99f56ba 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DualActionButton.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DualActionButton.kt @@ -43,20 +43,7 @@ fun DualActionButton( rightButtonTextColor: Color = MaterialTheme.colorScheme.primary, isLoading: Boolean = false ) { - Column(modifier = modifier) { - Row { - Text( - text = titleText, - textAlign = TextAlign.Start, - color = MaterialTheme.colorScheme.scrim, - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight(500), - modifier = Modifier - .fillMaxWidth() - .padding(start = 24.sdp, end = 24.sdp) - ) - } Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/InputText.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/InputText.kt index 0f8ab0ff..d200d00e 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/InputText.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/InputText.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -27,7 +28,6 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.shadow import androidx.compose.ui.geometry.CornerRadius -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource @@ -40,7 +40,6 @@ import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import com.soujunior.petjournal.R import com.soujunior.petjournal.ui.theme.ColorCustom import com.soujunior.petjournal.ui.theme.ColorGrid @@ -60,23 +59,24 @@ fun InputText( onEvent: (String) -> Unit, hasAMask: Boolean = false, keyboardOptions: KeyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text), - visualTransformation: VisualTransformation = VisualTransformation.None + visualTransformation: VisualTransformation = VisualTransformation.None, + textTitleModifier: Modifier = Modifier ) { var showPassword by remember { mutableStateOf(false) } - Column(modifier = modifier.padding(top = 16.sdp)) { + Column(modifier = modifier) { Row { Text( text = titleText, textAlign = TextAlign.Start, color = MaterialTheme.colorScheme.scrim, - style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight(500), - modifier = modifier + style = MaterialTheme.typography.titleMedium, + modifier = textTitleModifier .fillMaxWidth() - .padding(start = 24.sdp, end = 24.sdp) ) } + Spacer(modifier = Modifier.height(8.dp)) Row { BasicTextField( modifier = textInputModifier @@ -90,7 +90,7 @@ fun InputText( color = MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(size = 12.dp) ) - .padding(2.sdp) + .padding(0.sdp) .fillMaxWidth() .testTag("inputField_test") .drawBehind { @@ -121,25 +121,21 @@ fun InputText( else PasswordVisualTransformation() } else visualTransformation, keyboardOptions = keyboardOptions, - decorationBox = { + decorationBox = { innerTextField -> Row( modifier = Modifier - .background(Color.White) - .padding(start = 14.sdp), + .padding(horizontal = 14.sdp), verticalAlignment = Alignment.CenterVertically ) { Box( modifier = Modifier.weight(1f) ) { + innerTextField() if (textValue.isEmpty() && !hasAMask) { Text( text = placeholderText, - style = TextStyle( - fontSize = 14.sp, - lineHeight = 21.sp, - fontWeight = FontWeight(300), - color = MaterialTheme.colorScheme.scrim, - ) + color = ColorCustom.color_placeholder, + style = MaterialTheme.typography.bodyMedium ) } } @@ -194,5 +190,5 @@ fun InputText( @Preview(showBackground = true, showSystemUi = false, device = "id:pixel_4_xl") @Composable fun InputTextPreview() { - InputText(Modifier, onEvent = {}, textValue = "") + InputText(textValue = "", onEvent = {},) } \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/NavigationBarItems.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/NavigationBarItems.kt index 706ec91a..852d4803 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/NavigationBarItems.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/NavigationBarItems.kt @@ -25,7 +25,7 @@ sealed class NavigationBarItems( object Pets : NavigationBarItems( title = "Pets", - route = "pets/introRegisterPet", + route = "pets/petListScreen", icons = R.drawable.ic_pet, group = "pets" ) diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PeriodSelector.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PeriodSelector.kt new file mode 100644 index 00000000..8f79e586 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PeriodSelector.kt @@ -0,0 +1,91 @@ +package com.soujunior.petjournal.ui.components + +import androidx.compose.foundation.Canvas +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.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.soujunior.petjournal.ui.util.SelectedPeriodType + +@Composable +fun PeriodSelector( + selected: SelectedPeriodType, + onSelectionChanged: (SelectedPeriodType) -> Unit +) { + val items = listOf(SelectedPeriodType.Diária, SelectedPeriodType.Semanal, SelectedPeriodType.Mensal) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + items.forEach { item -> + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .clickable { onSelectionChanged(item) } + .padding(horizontal = 8.dp) + ) { + Text( + text = item.name, + style = MaterialTheme.typography.bodyMedium, + color = if (selected == item) Color(0xFF8D4CD2) else Color.Black, + ) + if (selected == item) { + TriangleIndicator() + } else { + Spacer(modifier = Modifier.height(6.dp)) + } + } + } + } +} + +@Composable +fun TriangleIndicator( + //TODO: colocar na tabela de cores. + color: Color = Color(0xFF8D4CD2), + modifier: Modifier = Modifier + .width(60.dp) + .height(2.dp) +) { + Canvas(modifier = modifier) { + val width = size.width + val height = size.height + + val inset = width * 0.1f + + val path = Path().apply { + moveTo(inset, 0f) + lineTo(width - inset, 0f) + lineTo(width, height) + lineTo(0f, height) + close() + } + + drawPath(path = path, color = color) + } +} + + +@Preview(showBackground = true) +@Composable +fun PeriodSelectorPreview() { + var selectedPeriod = SelectedPeriodType.Diária + PeriodSelector(selected = selectedPeriod) { + selectedPeriod = it + } +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PetItem.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PetItem.kt index 62e0d0dc..82ef1432 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PetItem.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PetItem.kt @@ -1,6 +1,7 @@ package com.soujunior.petjournal.ui.components import android.widget.ImageView +import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -13,7 +14,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import com.soujunior.petjournal.R import ir.kaaveh.sdpcompose.sdp import ir.kaaveh.sdpcompose.ssp @@ -34,12 +39,21 @@ fun PetItem( shape = RoundedCornerShape(16.sdp), onClick = onClick ) { - GlideImage( - modifier = Modifier.fillMaxSize(), - context = LocalContext.current, - url = imageRes, - scaleType = ImageView.ScaleType.CENTER_CROP - ) + if(!imageRes.isEmpty()) { + GlideImage( + modifier = Modifier.fillMaxSize(), + context = LocalContext.current, + url = imageRes, + scaleType = ImageView.ScaleType.CENTER_CROP + ) + }else{ + //placeholder de imagem vazia + Image( + painter = painterResource(id = R.drawable.image_pet_empty_selected), + contentDescription = "image description", + contentScale = ContentScale.Crop + ) + } } Text( @@ -50,4 +64,10 @@ fun PetItem( ) Spacer(Modifier.padding(bottom = 24.sdp)) } +} + +@Preview +@Composable +private fun previewPetItem(){ + PetItem(modifier = Modifier, imageRes = "", name = "", onClick = {}) } \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PetSelectorItem.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PetSelectorItem.kt index 7a2e0e89..6d991f39 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PetSelectorItem.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/PetSelectorItem.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.VectorPainter import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -56,7 +57,7 @@ fun PetIcon( ambientColor = ColorCustom.color_spot_pet_icon ) .padding(1.dp) - .size(66.dp) + .size(55.dp) .background( color = backgroundColor, shape = RoundedCornerShape(8.dp) @@ -77,6 +78,7 @@ fun PetIcon( modifier = Modifier .size(32.dp) .offset(y = 4.dp) + .testTag("SelectedIcon") ) } @@ -129,6 +131,7 @@ fun PetFilterItem( modifier = Modifier .padding(start = 8.dp, end = 8.dp) .clickable { onSelect(name) } + .testTag("PetItem_$name") ) { PetIcon( imageRes = if (name == "Todos") painterResource(id = R.drawable.icon_pet_selected) else imageRes, @@ -160,46 +163,56 @@ fun PetFilterList( var selectedPets by remember { mutableStateOf(listOf()) } - LazyRow( - modifier = Modifier - .fillMaxWidth() - .padding(top = 20.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - item { - PetFilterItem( - name = "Todos", - isSelected = selectedPets.contains(stringResource(R.string.label_all_pets)), - imageRes = null, - onSelect = { name -> - selectedPets = if (selectedPets.contains(name)) { - selectedPets - name - } else { - selectedPets + name + Column(modifier = Modifier) { + Text( + text = stringResource(R.string.which_pets_need_this_task), + color = MaterialTheme.colorScheme.scrim, + fontWeight = FontWeight(500), + style = MaterialTheme.typography.titleMedium + ) + + LazyRow( + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp, start = 10.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + item { + PetFilterItem( + name = stringResource(R.string.label_all_pets), + isSelected = selectedPets.contains(stringResource(R.string.label_all_pets)), + imageRes = null, + onSelect = { name -> + selectedPets = if (selectedPets.contains(name)) { + selectedPets - name + } else { + selectedPets + name + } + onSelectedPet(if (selectedPets.contains(name)) name else "") } - onSelectedPet(if (selectedPets.contains(name)) name else "") - } - ) - } - items( - items = listPet, - key = { it.id } - ) { item -> - PetFilterItem( - name = item.name!!, - isSelected = selectedPets.contains(item.name), - imageRes = item.imageRes, - onSelect = { name -> - selectedPets = if (selectedPets.contains(name)) { - selectedPets - name - } else { - selectedPets + name + ) + } + items( + items = listPet, + key = { it.id } + ) { item -> + PetFilterItem( + name = item.name!!, + isSelected = selectedPets.contains(item.name), + imageRes = item.imageRes, + onSelect = { name -> + selectedPets = if (selectedPets.contains(name)) { + selectedPets - name + } else { + selectedPets + name + } + onSelectedPet(if (selectedPets.contains(name)) name else "") } - onSelectedPet(if (selectedPets.contains(name)) name else "") - } - ) + ) + } } } + } @Preview(showBackground = true, showSystemUi = false, device = "id:pixel_4_xl") @@ -215,7 +228,26 @@ fun PetFilterListPreview() { id = 2, imageRes = painterResource(R.drawable.image_alfredo), name = "Alfredo" - ) + ),Pets( + id = 1423, + imageRes = painterResource(R.drawable.image_jujuba), + name = "Jujuba" + ), + Pets( + id = 245, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ), + Pets( + id = 1455, + imageRes = painterResource(R.drawable.image_jujuba), + name = "Jujuba" + ), + Pets( + id = 6452, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ) ) PetFilterList( diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/SelectableButtonData.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/SelectableButtonData.kt index 8eb8733c..c2ab27ac 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/SelectableButtonData.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/SelectableButtonData.kt @@ -1,6 +1,7 @@ package com.soujunior.petjournal.ui.components import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow @@ -8,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -38,10 +40,9 @@ fun SelectableButton( modifierSelectableButton: Modifier = Modifier, onSelectionChanged: (String, Boolean) -> Unit ) { - androidx.compose.material3.Button( + Button( modifier = modifierSelectableButton - .height(70.dp) - .padding(top = 15.dp, end = 15.dp, bottom = 15.dp) + .height(40.dp) .then( if (isSelected) { Modifier.shadow( @@ -79,57 +80,35 @@ fun SelectableButton( } } + + @OptIn(ExperimentalLayoutApi::class) @Composable fun GroupSelectableButton( - onSelection: (String) -> Unit = {} + listOfTasks: List, + onSelection: (String) -> Unit = {}, + modifier: Modifier = Modifier, + maxItemsInEachRow: Int = Int.MAX_VALUE ) { - val buttons = listOf( - SelectableButtonInfo( - stringResource(R.string.label_selectable_button_vaccines), - ColorCustom.color_selectable_button_1 - ), - SelectableButtonInfo( - stringResource(R.string.label_selectable_button_consultations), - ColorCustom.color_selectable_button_2 - ), - SelectableButtonInfo( - stringResource(R.string.label_selectable_button_medicine), - ColorCustom.color_selectable_button_3 - ), - SelectableButtonInfo( - stringResource(R.string.label_selectable_button_bath), - ColorCustom.color_selectable_button_4 - ), - SelectableButtonInfo( - stringResource(R.string.label_selectable_button_food), - ColorCustom.color_selectable_button_5 - ), - SelectableButtonInfo( - stringResource(R.string.label_selectable_button_pet_walk), - ColorCustom.color_selectable_button_6 - ), - ) - - val selectionState = remember { mutableStateListOf(*Array(buttons.size) { false }) } + val selectionState = remember { mutableStateListOf(*Array(listOfTasks.size) { false }) } Column( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) + modifier = modifier, + verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text( text = stringResource(R.string.label_select_main_category), - style = MaterialTheme.typography.titleLarge, + style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.scrim, fontWeight = FontWeight(500), lineHeight = 24.sp ) - FlowRow( - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(15.dp), + maxItemsInEachRow = maxItemsInEachRow ) { - buttons.forEachIndexed { index, buttonInfo -> + listOfTasks.forEachIndexed { index, buttonInfo -> SelectableButton( titleButton = buttonInfo.title, colorButton = buttonInfo.color, @@ -142,7 +121,9 @@ fun GroupSelectableButton( onSelection("") } }, - modifierSelectableButton = Modifier.adaptiveWidthForTitle(buttonInfo.title) + modifierSelectableButton = Modifier + .adaptiveWidthForTitle(buttonInfo.title) + .padding(bottom = 15.dp) ) } } @@ -155,9 +136,34 @@ data class SelectableButtonInfo( val color: Color ) - -@Preview(showBackground = true, showSystemUi = true, device = "id:pixel_4_xl") +@Preview() @Composable -fun CustomSelectableButtonPreview() { - GroupSelectableButton() -} \ No newline at end of file +fun CustomSelectableButtonWithoutDevicePreview() { + val listOfTasks = listOf( + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_vaccines), + ColorCustom.color_selectable_button_1 + ), + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_consultations), + ColorCustom.color_selectable_button_2 + ), + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_medicine), + ColorCustom.color_selectable_button_3 + ), + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_bath), + ColorCustom.color_selectable_button_4 + ), + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_food), + ColorCustom.color_selectable_button_5 + ), + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_pet_walk), + ColorCustom.color_selectable_button_6 + ), + ) + GroupSelectableButton(listOfTasks) +} diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TaskCard.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TaskCard.kt new file mode 100644 index 00000000..ce4084fd --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TaskCard.kt @@ -0,0 +1,229 @@ +package com.soujunior.petjournal.ui.components + +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.BorderStroke +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.Row +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.soujunior.petjournal.R +import com.soujunior.petjournal.ui.components.data.TaskData +import com.soujunior.petjournal.ui.components.data.TaskDummyData +import ir.kaaveh.sdpcompose.sdp +import ir.kaaveh.sdpcompose.ssp + +@Composable +fun TaskCard( + taskData: TaskData +) { + var expanded by remember { mutableStateOf(false) } + + Box( + modifier = Modifier.clip(RectangleShape) + ) { + Surface( + shape = RoundedCornerShape(8.sdp), + tonalElevation = 2.dp, + modifier = Modifier + .padding(2.sdp) + .animateContentSize() // Animates the size change + ) { + // Background icon when expanded - outside the Surface + if (expanded) { + Icon( + painter = painterResource(id = taskData.tipo.iconeVector!!), + contentDescription = "Ícone ${taskData.tipo.nome}", + tint = taskData.tipo.cor.copy(alpha = .5f), + modifier = Modifier + .align(Alignment.BottomStart) + .padding(start = 2.sdp, bottom = 42.sdp) + .size(150.sdp) + .offset(x = (-80).dp, y = (70).dp) + ) + } + Column { + // Main content: Title/Date on Start, Description on End + Row( + modifier = Modifier + .fillMaxWidth() + .padding(4.sdp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.Top + ) { + // Left side: Title and Date + Column( + modifier = Modifier + .padding(horizontal = 8.sdp) + .weight(0.4f), + horizontalAlignment = Alignment.Start + ) { + Text( + text = taskData.titulo, + modifier = Modifier.padding(bottom = 2.sdp), + style = MaterialTheme.typography.titleMedium, + fontSize = 15.ssp + + ) + Text( + text = taskData.dataHora, + style = MaterialTheme.typography.titleMedium, + color = Color.Gray, + fontSize = 10.ssp + ) + + /** + * Vai receber n ids de pets e vai criar a grid com as imagens dos respectivos pets + * */ + if (expanded) { + LazyVerticalGrid( + modifier = Modifier.fillMaxWidth(), + columns = GridCells.Fixed(3), + horizontalArrangement = Arrangement.Start + ) { + items(taskData.pets.size) { index -> + Box(modifier = Modifier.aspectRatio(1f)) { + PetItem(modifier = Modifier, imageRes = "", name = "", onClick = {}) + } + } + } + } + } + + // Right side: Description + Column( + modifier = Modifier + .padding(horizontal = 8.sdp) + .weight(0.6f), + horizontalAlignment = Alignment.Start + ) { + val displayText = if (!expanded && taskData.descricaoResumida.length > 50) { + taskData.descricaoResumida.take(50) + "..." + } else { + taskData.descricaoResumida + } + + Text( + text = displayText, + style = MaterialTheme.typography.titleSmall, + modifier = Modifier + .fillMaxWidth(1f) + .padding(start = 8.sdp) + ) + + if (expanded) { + Text( + text = taskData.descricaoCompleta, + style = MaterialTheme.typography.titleSmall, + modifier = Modifier + .fillMaxWidth(1f) + .padding(start = 8.sdp, top = 8.sdp) + ) + } + } + } + + // Expanded content + if (expanded) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 8.sdp, top = 16.sdp), + ) { + Button( + onClick = {}, + modifier = Modifier + .width(100.sdp) + .height(25.sdp) + .align(Alignment.CenterHorizontally), + border = BorderStroke( + 1.sdp, Color(0xFF959EA6) + ), + shape = RoundedCornerShape(50.sdp), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.background) + + ) { + // TODO: AJUSTAR A COR DO BOTÃO PARA A COR DA TAREFA + Text( + text = "Editar Tarefa", + fontSize = 10.ssp, + color = taskData.tipo.cor, + style = MaterialTheme.typography.headlineLarge + ) + } + } + } + + // Bottom section: "Ver Mais" / "Ver Menos" + Box( + modifier = Modifier + .fillMaxWidth() + .background(taskData.tipo.cor) + .clickable { expanded = !expanded } // Toggles the expanded state + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 6.sdp), + horizontalArrangement = Arrangement.Center + ) { + Text( + text = if (expanded) "Ver Menos" else "Ver Mais", + fontSize = 10.ssp, + color = MaterialTheme.colorScheme.background, + style = MaterialTheme.typography.displaySmall + ) + } + } + } + } + + + } +} + +@Preview +@Composable +private fun TaskCardPreview() { + Column(Modifier.padding(8.sdp)) { + TaskCard( + taskData = TaskDummyData.sampleTasks[0] + ) +// TaskCard( +// taskData = TaskDummyData.sampleTasks[1] +// ) +// TaskCard( +// taskData = TaskDummyData.sampleTasks[2] +// ) + } +} diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TaskSuccessDialog.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TaskSuccessDialog.kt index e8f3f655..35736250 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TaskSuccessDialog.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TaskSuccessDialog.kt @@ -51,10 +51,13 @@ fun TaskSuccessDialog( modifier = modifier .shadow( elevation = 3.dp, - spotColor = ColorCustom.color_shadow_dialog, - ambientColor = ColorCustom.color_shadow_dialog + //todo: Corrigir ColorCustom.color_shadow_dialog, + spotColor = ColorCustom.error_color, + //todo: Corrigir ColorCustom.color_shadow_dialog, + ambientColor = ColorCustom.error_color ) - .border(2.dp, ColorCustom.color_border_dialog, RoundedCornerShape(16.dp)) + //todo: Corrigir ColorCustom.color_border_dialog, + .border(2.dp, ColorCustom.error_color, RoundedCornerShape(16.dp)) .width(330.dp) .height(338.dp) .background( @@ -90,7 +93,8 @@ fun TaskSuccessDialog( .fillMaxWidth() .padding(start = 16.dp, end = 16.dp), onClick = onNewTaskClick, - border = BorderStroke(1.dp, ColorCustom.color_background_button_dialog), + //todo: Corrigir ColorCustom.color_background_button_dialog, + border = BorderStroke(1.dp, ColorCustom.error_color), shape = RoundedCornerShape(12.dp) ) { Icon( @@ -99,14 +103,16 @@ fun TaskSuccessDialog( .height(24.dp), imageVector = Icons.Default.Add, contentDescription = null, - tint = ColorCustom.color_background_button_dialog + //todo: Corrigir ColorCustom.color_background_button_dialog, + tint = ColorCustom.error_color ) Spacer(modifier = Modifier.width(8.dp)) Text( text = stringResource(R.string.label_new_task), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight(600), - color = ColorCustom.color_border_dialog + //todo: Corrigir ColorCustom.color_border_dialog, + color = ColorCustom.error_color ) } @@ -115,7 +121,8 @@ fun TaskSuccessDialog( .fillMaxWidth() .padding(start = 16.dp, end = 16.dp, top = 6.dp), onClick = onGoToHomeClick, - colors = ButtonDefaults.buttonColors(containerColor = ColorCustom.color_border_dialog), + //todo: Corrigir ColorCustom.color_border_dialog, + colors = ButtonDefaults.buttonColors(containerColor = ColorCustom.error_color), shape = RoundedCornerShape(12.dp) ) { Text( diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DescriptionTextField.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TextFieldCustom.kt similarity index 82% rename from petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DescriptionTextField.kt rename to petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TextFieldCustom.kt index e018df07..d7ce79f6 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/DescriptionTextField.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TextFieldCustom.kt @@ -13,26 +13,26 @@ import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.soujunior.petjournal.R import com.soujunior.petjournal.ui.theme.ColorCustom @Composable -fun DescriptionTextField( +fun TextFieldCustom( + title:String, + placeholder:String, value: String, onValueChange: (String) -> Unit, modifier: Modifier = Modifier ) { Column( modifier = modifier - .padding(16.dp) ) { Text( - text = stringResource(R.string.label_description), - fontWeight = FontWeight.Bold, + text = title, + color = MaterialTheme.colorScheme.scrim, + fontWeight = FontWeight(500), style = MaterialTheme.typography.titleMedium, ) @@ -43,9 +43,9 @@ fun DescriptionTextField( onValueChange = onValueChange, placeholder = { Text( - text = stringResource(R.string.enter_the_task_description_here), + text = placeholder, color = ColorCustom.color_placeholder, - style = MaterialTheme.typography.bodySmall + style = MaterialTheme.typography.bodyMedium ) }, modifier = Modifier @@ -64,7 +64,9 @@ fun DescriptionTextField( @Preview @Composable fun DescriptionTextFieldPreview() { - DescriptionTextField( + TextFieldCustom( + title = "Título", + placeholder = "Descrição", value = "", onValueChange = {} ) diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TransactionTypeSelector.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TransactionTypeSelector.kt new file mode 100644 index 00000000..898ad828 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/TransactionTypeSelector.kt @@ -0,0 +1,147 @@ +package com.soujunior.petjournal.ui.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +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.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +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 com.soujunior.petjournal.R +import com.soujunior.petjournal.ui.theme.ColorCustom +import com.soujunior.petjournal.ui.util.TransactionType + +@Composable +fun TransactionTypeSelector( + onSelectionChanged: (TransactionType?) -> Unit +) { + var selectedType by remember { mutableStateOf(null) } + + val selectedColor = ColorCustom.color_background_month_disabled + val unselectedColor = MaterialTheme.colorScheme.background + val borderColor = ColorCustom.color_border_button_transaction_type + + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + ) { + ToggleButton( + text = stringResource(R.string.label_recurrent), + isSelected = selectedType == TransactionType.Recurrent, + onClick = { + val newType = TransactionType.Recurrent + selectedType = newType + onSelectionChanged(newType) + }, + selectedColor = selectedColor, + unselectedColor = unselectedColor, + borderColor = if (selectedType == TransactionType.Recurrent) selectedColor else borderColor + ) + + ToggleButton( + text = stringResource(R.string.label_one_off), + isSelected = selectedType == TransactionType.OneOff, + onClick = { + val newType = TransactionType.OneOff + selectedType = newType + onSelectionChanged(newType) + }, + selectedColor = selectedColor, + unselectedColor = unselectedColor, + borderColor = if (selectedType == TransactionType.OneOff) selectedColor else borderColor + ) + } + + if (selectedType == TransactionType.Recurrent) { + onSelectionChanged(selectedType) + } else { + onSelectionChanged(selectedType) + } + } +} + +@Composable +fun ToggleButton( + text: String, + isSelected: Boolean, + onClick: () -> Unit, + selectedColor: Color, + unselectedColor: Color, + borderColor: Color +) { + val backgroundColor = if (isSelected) selectedColor else unselectedColor + + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .width(130.dp).height(50.dp) + .clip(RoundedCornerShape(50)) + .border(1.dp, borderColor, RoundedCornerShape(50)) + .background(backgroundColor) + .clickable { onClick() } + .padding(horizontal = 24.dp, vertical = 12.dp) + ) { + Text( + text = text, + color = ColorCustom.color_text_button_transaction_type, + style = MaterialTheme.typography.titleMedium, + ) + } +} + +@Preview(showBackground = true) +@Composable +fun TransactionTypeSelectorPreview() { + TransactionTypeSelector( + onSelectionChanged = {} + ) +} + +@Preview(showBackground = true) +@Composable +fun ToggleButtonPreview() { + Column(modifier = Modifier.padding(16.dp)) { + ToggleButton( + text = stringResource(R.string.label_recurrent), + isSelected = true, + onClick = {}, + selectedColor = ColorCustom.color_background_month_disabled, + unselectedColor = MaterialTheme.colorScheme.background, + borderColor = ColorCustom.color_border_button_transaction_type + ) + + ToggleButton( + text = stringResource(R.string.label_one_off), + isSelected = false, + onClick = {}, + selectedColor = ColorCustom.color_background_month_disabled, + unselectedColor = MaterialTheme.colorScheme.background, + borderColor = ColorCustom.color_border_button_transaction_type + ) + } + +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/clock/TimePickerWithPeriodSelector.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/clock/TimePickerWithPeriodSelector.kt new file mode 100644 index 00000000..32ead607 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/clock/TimePickerWithPeriodSelector.kt @@ -0,0 +1,47 @@ +package com.soujunior.petjournal.ui.components.clock + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.soujunior.petjournal.ui.components.AmPmSelector + +@Composable +fun TimePickerWithPeriodSelector( + onAmPmSelector: (String) -> Unit, + onTime: (Int, Int) -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + AmPmSelector( + onPeriodSelected = { periodSelected -> + onAmPmSelector(periodSelected) + } + ) + Box( + modifier = Modifier + .padding(start = 8.dp) + .height(150.dp) + .width(100.dp), + contentAlignment = Alignment.Center + ) { + WheelTimePicker( + onTimeChanged = { hour, minute -> + onTime(hour, minute) + } + ) + } + } +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/clock/WheelTimePicker.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/clock/WheelTimePicker.kt index ab19cec4..4745640c 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/clock/WheelTimePicker.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/clock/WheelTimePicker.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.soujunior.petjournal.ui.theme.ColorCustom import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filter import kotlin.math.abs @@ -59,7 +60,7 @@ fun WheelTimePicker( initialMinute: Int = 0, textStyle: TextStyle = MaterialTheme.typography.titleLarge, focusedColor: Color = Color.Black, - unfocusedColor: Color = Color.Gray, + unfocusedColor: Color = ColorCustom.color_unfocused_wheelTimePicker, onTimeChanged: (hour: Int, minute: Int) -> Unit ) { require(visibleItemsCount % 2 != 0) { "visibleItemsCount must be an odd number." } @@ -162,8 +163,10 @@ private fun PickerColumn( if (layoutInfo.visibleItemsInfo.isEmpty()) { -1 } else { - val viewportCenter = (layoutInfo.viewportStartOffset + layoutInfo.viewportEndOffset) / 2 - layoutInfo.visibleItemsInfo.minByOrNull { abs((it.offset + it.size / 2) - viewportCenter) }?.index ?: -1 + val viewportCenter = + (layoutInfo.viewportStartOffset + layoutInfo.viewportEndOffset) / 2 + layoutInfo.visibleItemsInfo.minByOrNull { abs((it.offset + it.size / 2) - viewportCenter) }?.index + ?: -1 } } } @@ -176,12 +179,14 @@ private fun PickerColumn( val layoutInfo = listState.layoutInfo if (layoutInfo.visibleItemsInfo.isEmpty()) return@collect - val viewportCenter = (layoutInfo.viewportStartOffset + layoutInfo.viewportEndOffset) / 2 + val viewportCenter = + (layoutInfo.viewportStartOffset + layoutInfo.viewportEndOffset) / 2 val centralItem = layoutInfo.visibleItemsInfo.minByOrNull { abs((it.offset + it.size / 2) - viewportCenter) } ?: return@collect - val itemDataIndex = (centralItem.index - halfVisibleItems).coerceIn(0, items.size - 1) + val itemDataIndex = + (centralItem.index - halfVisibleItems).coerceIn(0, items.size - 1) val delta = (centralItem.offset + centralItem.size / 2) - viewportCenter listState.animateScrollBy(delta.toFloat()) @@ -204,8 +209,14 @@ private fun PickerColumn( items(items.size) { dataIndex -> val lazyColumnIndex = dataIndex + halfVisibleItems val isFocused = (lazyColumnIndex == centralLazyColumnIndex) - val scale by animateFloatAsState(targetValue = if (isFocused) 1.2f else 1.0f, label = "scale") - val alpha by animateFloatAsState(targetValue = if (isFocused) 1.0f else 0.5f, label = "alpha") + val scale by animateFloatAsState( + targetValue = if (isFocused) 1.2f else 1.0f, + label = "scale" + ) + val alpha by animateFloatAsState( + targetValue = if (isFocused) 1.0f else 0.5f, + label = "alpha" + ) Box( modifier = Modifier.height(itemHeight), @@ -215,9 +226,9 @@ private fun PickerColumn( text = items[dataIndex], style = textStyle.copy( color = if (isFocused) focusedColor else unfocusedColor, - fontSize = textStyle.fontSize * scale + fontSize = 34.sp ), - modifier = Modifier.alpha(alpha) + modifier = Modifier//.alpha(alpha) ) } } diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/data/DayPicker.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/data/DayPicker.kt new file mode 100644 index 00000000..a5e3d4a4 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/data/DayPicker.kt @@ -0,0 +1,98 @@ +package com.soujunior.petjournal.ui.components.data + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +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.snapshotFlow +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import kotlinx.coroutines.flow.distinctUntilChanged +import java.time.LocalDate + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun DayPicker( + onDaySelected: (Int) -> Unit +) { + val currentDate = remember { LocalDate.now() } + val totalDays = remember { currentDate.lengthOfMonth() } + + val days = remember { (1..totalDays).toList() } + + val listState = rememberLazyListState(initialFirstVisibleItemIndex = currentDate.dayOfMonth - 1) + + val flingBehavior = rememberSnapFlingBehavior(lazyListState = listState) + + LaunchedEffect(listState) { + snapshotFlow { listState.firstVisibleItemIndex } + .distinctUntilChanged() + .collect { index -> + onDaySelected(days.getOrNull(index + 1) ?: days.last()) + } + } + + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = "DIA", style = MaterialTheme.typography.bodySmall) + + Box( + modifier = Modifier + .height(120.dp) + .width(60.dp), + contentAlignment = Alignment.Center + ) { + LazyColumn( + state = listState, + flingBehavior = flingBehavior, + contentPadding = PaddingValues(vertical = 40.dp), + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.fillMaxHeight() + ) { + itemsIndexed(days) { index, day -> + val isSelected = listState.firstVisibleItemIndex == index + Text( + text = day.toString(), + fontSize = if (isSelected) 26.sp else 20.sp, + color = if (isSelected) Color.Black else Color.LightGray, + fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal, + modifier = Modifier.padding(vertical = 4.dp) + ) + } + } + } + } +} + + +@Preview +@Composable +fun DayPickerPreview(){ + var selectedDay by remember { mutableStateOf(LocalDate.now().dayOfMonth) } + + DayPicker( + onDaySelected = { selectedDay = it } + ) +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/data/TaskTypes.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/data/TaskTypes.kt new file mode 100644 index 00000000..9e8cfe48 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/data/TaskTypes.kt @@ -0,0 +1,153 @@ +package com.soujunior.petjournal.ui.components.data + +import androidx.annotation.DrawableRes +import androidx.compose.ui.graphics.Color +import com.soujunior.petjournal.R + +data class TaskType( + val id: String, + val nome: String, + val cor: Color, + @DrawableRes val icone: Int? = null, // Recebe um vetor drawable + @DrawableRes val iconeVector: Int? = null // Recebe um drawable vector +) + +object TaskTypes { + val VACINA = TaskType( + id = "vacina", + nome = "Vacina", + cor = Color(0xFFFA680E), + icone = R.drawable.icone_vacinas, + iconeVector = R.drawable.icone_vacinas_vector + ) + + val CONSULTAS = TaskType( + id = "consultas", + nome = "Consultas", + cor = Color(0xFF20955E), + icone = R.drawable.icone_consulta, + iconeVector = R.drawable.icone_consultas_vector + + ) + + val RACAO = TaskType( + id = "racao", + nome = "Ração", + cor = Color(0xFF881803), + icone = R.drawable.icone_racao, + iconeVector = R.drawable.icone_racao_vector + ) + + val MEDICAMENTOS = TaskType( + id = "medicamentos", + nome = "Medicamentos", + cor = Color(0xFF2F99E5), + icone = R.drawable.icone_medicamento, + iconeVector = R.drawable.icone_medicamentos_vector + + ) + + val BANHOS = TaskType( + id = "banhos", + nome = "Banhos", + cor = Color(0xFFD03A94), + icone = R.drawable.icone_banho, + iconeVector = R.drawable.icone_banhos_vector + + ) + + val PASSEIO = TaskType( + id = "passeio", + nome = "Passeio", + cor = Color(0xFFB78AF7), + icone = R.drawable.icone_passeio, + iconeVector = R.drawable.icone_passeios_vector + + ) + + // Lista com todos os tipos para facilitar iteração + val ALL_TYPES = listOf( + VACINA, + CONSULTAS, + RACAO, + MEDICAMENTOS, + BANHOS, + PASSEIO + ) + + // Função para buscar tipo por ID + fun getTypeById(id: String): TaskType? { + return ALL_TYPES.find { it.id == id } + } + + // Função para buscar tipo por nome + fun getTypeByName(nome: String): TaskType? { + return ALL_TYPES.find { it.nome.equals(nome, ignoreCase = true) } + } +} + +data class PetData( + val id: String, + val imageRes: String = "" // String vazia por enquanto +) + +data class TaskData( + val id: String, + val titulo: String, + val descricaoResumida: String, + val descricaoCompleta: String, + val dataHora: String, + val tipo: TaskType, + val pets: List = emptyList() +) + +// Dados dummy para exemplo/preview +object TaskDummyData { + private val samplePets = listOf( + PetData(id = "pet_001"), + PetData(id = "pet_002"), + PetData(id = "pet_003"), + PetData(id = "pet_004"), + PetData(id = "pet_005"), + PetData(id = "pet_006") + ) + + val sampleTasks = listOf( + TaskData( + id = "1", + titulo = "Carprofeno", + descricaoResumida = "Anti-inflamatorio não esteroide para alivio da dor e inflamação", + descricaoCompleta = "Medicamento anti-inflamatório não esteroide para alívio da dor e inflamação. Deve ser administrado com cuidado e seguindo as instruções veterinárias. Dosagem recomendada conforme peso do animal.", + dataHora = "12/08/2025 - 10:30", + tipo = TaskTypes.MEDICAMENTOS, + pets = listOf(samplePets[0], samplePets[1], samplePets[2]) + ), + TaskData( + id = "2", + titulo = "Vacina Antirrábica", + descricaoResumida = "Vacina obrigatória contra raiva para proteção do pet", + descricaoCompleta = "Vacina antirrábica anual obrigatória. Essencial para proteção contra a raiva e exigida por lei. Deve ser aplicada por veterinário e gera certificado de vacinação.", + dataHora = "15/08/2025 - 14:00", + tipo = TaskTypes.VACINA, + pets = listOf(samplePets[0]) + ), + TaskData( + id = "3", + titulo = "Consulta de Rotina", + descricaoResumida = "Check-up geral para avaliação da saúde do pet", + descricaoCompleta = "Consulta veterinária de rotina para avaliação geral da saúde, verificação de peso, exame físico completo e orientações sobre cuidados preventivos.", + dataHora = "20/08/2025 - 09:15", + tipo = TaskTypes.CONSULTAS, + pets = listOf(samplePets[1], samplePets[3]) + ), + TaskData( + id = "4", + titulo = "Ração Premium", + descricaoResumida = "Trocar para ração premium conforme orientação veterinária", + descricaoCompleta = "Mudança gradual para ração premium de alta qualidade. Fazer transição lenta misturando com a ração atual por 7 dias. Quantidade: 200g por dia dividida em 2 refeições.", + dataHora = "18/08/2025 - 18:00", + tipo = TaskTypes.RACAO, + pets = listOf(samplePets[0], samplePets[2], samplePets[4], samplePets[5]) + ) + ) +} diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/task/OneOffTask.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/task/OneOffTask.kt new file mode 100644 index 00000000..90fd3575 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/task/OneOffTask.kt @@ -0,0 +1,51 @@ +package com.soujunior.petjournal.ui.components.task + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.soujunior.petjournal.ui.components.clock.TimePickerWithPeriodSelector +import com.soujunior.petjournal.ui.components.data.CustomDatePicker + +@Composable +fun OneOffTask( + onDateSelected: (Long?) -> Unit = {}, + onAmPmSelector: (String?) -> Unit = {}, + onTime: (Int, Int) -> Unit = { _, _ -> } +) { + var selectedTimestamp by remember { mutableStateOf(null) } + + Column(modifier = Modifier) { + CustomDatePicker( + label = "Data", + value = selectedTimestamp, + onValueChange = { + selectedTimestamp = it + onDateSelected(selectedTimestamp) + }, + modifier = Modifier.fillMaxWidth() + ) + + TimePickerWithPeriodSelector( + onAmPmSelector = { amPmSelector -> + onAmPmSelector(amPmSelector) + }, + onTime = { hour, minute -> + onTime(hour, minute) + } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun OneOffTaskPreview() { + OneOffTask() +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/task/RecurrentTask.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/task/RecurrentTask.kt new file mode 100644 index 00000000..06a2e449 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/components/task/RecurrentTask.kt @@ -0,0 +1,137 @@ +package com.soujunior.petjournal.ui.components.task + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.soujunior.petjournal.ui.components.ActiveMonthsComponent +import com.soujunior.petjournal.ui.components.AmPmSelector +import com.soujunior.petjournal.ui.components.PeriodSelector +import com.soujunior.petjournal.ui.components.WeekDaySelector +import com.soujunior.petjournal.ui.components.clock.TimePickerWithPeriodSelector +import com.soujunior.petjournal.ui.components.clock.WheelTimePicker +import com.soujunior.petjournal.ui.components.data.DayPicker +import com.soujunior.petjournal.ui.util.SelectedPeriodType + +@Composable +fun RecurringTask( + activeMonths: Set = setOf(), + onAmPmSelector: (String?) -> Unit = {}, + onTime: (Int?, Int?) -> Unit = { _, _ -> }, + onWeekDaySelected: (String?) -> Unit = {}, + onDaySelected: (Int?) -> Unit = {}, +) { + var selectedPeriod by remember { mutableStateOf(SelectedPeriodType.Diária) } + PeriodSelector( + selected = selectedPeriod, + onSelectionChanged = { selectedPeriod = it } + ) + + when (selectedPeriod) { + SelectedPeriodType.Diária -> { + TimePickerWithPeriodSelector( + onAmPmSelector = { amPmSelector -> + onAmPmSelector(amPmSelector) + }, + onTime = { hour, minute -> + onTime(hour, minute) + } + ) + } + + SelectedPeriodType.Semanal -> { + Row( + modifier = Modifier + .fillMaxWidth() +// .padding(top = 16.dp) +, + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + + WeekDaySelector( + onDaySelected = { weekDaySelected -> + onWeekDaySelected(weekDaySelected) + } + ) + + AmPmSelector( + onPeriodSelected = { amPmSelector -> + onAmPmSelector(amPmSelector) + } + ) + Box( + modifier = Modifier +// .padding(start = 8.dp) + .height(150.dp) + .width(100.dp), + contentAlignment = Alignment.Center + ) { + WheelTimePicker( + onTimeChanged = { hour, minute -> + onTime(hour, minute) + } + ) + } + } + } + + SelectedPeriodType.Mensal -> { + Column { + Row( + modifier = Modifier + .fillMaxWidth() +// .padding(top = 16.dp) + , + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + + DayPicker( + onDaySelected = { daySelected -> + onDaySelected(daySelected) + } + ) + AmPmSelector( + onPeriodSelected = { amPmSelector -> + onAmPmSelector(amPmSelector) + } + ) + Box( + modifier = Modifier + .height(150.dp) + .width(100.dp), + contentAlignment = Alignment.Center + ) { + WheelTimePicker( + onTimeChanged = { hour, minute -> + onTime(hour, minute) + } + ) + } + } + ActiveMonthsComponent(activeMonths = activeMonths) + } + + } + } +} + +@Preview(showBackground = true) +@Composable +fun RecurringTaskPreview() { + RecurringTask() +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/petListScreen/PetListScreen.kt.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/petListScreen/PetListScreen.kt similarity index 100% rename from petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/petListScreen/PetListScreen.kt.kt rename to petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/petListScreen/PetListScreen.kt diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/petListScreen/components/Screen.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/petListScreen/components/Screen.kt index 4f1221b5..64061903 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/petListScreen/components/Screen.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/petListScreen/components/Screen.kt @@ -141,7 +141,11 @@ fun Screen(navController: NavController) { ) } item { - PetItemMore(onClick = {}) + PetItemMore( + onClick = { + navController.navigate("pets/registerPet") + } + ) } } diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerPetScreen/components/Screen.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerPetScreen/components/Screen.kt index 14208cc3..3cc0bb74 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerPetScreen/components/Screen.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerPetScreen/components/Screen.kt @@ -4,14 +4,20 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.AbsoluteAlignment import androidx.compose.ui.Alignment @@ -20,6 +26,8 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController @@ -39,7 +47,9 @@ import ir.kaaveh.sdpcompose.sdp fun Screen(navController: NavController) { Column(modifier = Modifier) { ScaffoldCustom( - modifier = Modifier, + modifier = Modifier + .navigationBarsPadding() + .fillMaxSize(), navigationUp = navController, showTopBar = true, titleTopBar = stringResource(R.string.edit_pet_data), @@ -54,31 +64,25 @@ fun Screen(navController: NavController) { .offset(y = 300.sdp) .align(AbsoluteAlignment.Left) ) + LazyColumn( horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Top, + verticalArrangement = Arrangement.spacedBy(12.sdp), modifier = Modifier .fillMaxSize() .fillMaxHeight() - .padding( - top = it.calculateTopPadding() + 12.sdp, - bottom = it.calculateBottomPadding() + 2.sdp - ) + .padding(it) .background(Color.Transparent), + contentPadding = PaddingValues(horizontal = 24.sdp), content = { item { ImagePet() } item { InputText( - textInputModifier = Modifier - .testTag("inputField_test") - .padding( - start = 24.sdp, - end = 24.sdp, - bottom = 12.sdp, - top = 4.sdp - ), + modifier = Modifier, + textTitleModifier = Modifier.padding(bottom = 4.sdp), + textInputModifier = Modifier.testTag("inputField_test"), placeholderText = stringResource(R.string.placeholder_name_pet), titleText = stringResource(R.string.pet_name), textValue = "", @@ -87,12 +91,8 @@ fun Screen(navController: NavController) { } item { DropDown( - textInputModifier = Modifier.padding( - start = 24.sdp, - end = 24.sdp, - bottom = 12.sdp, - top = 4.sdp - ), + textInputModifier = Modifier, + textTitleModifier = Modifier.padding(bottom = 4.sdp), placeholderText = stringResource(R.string.placeholder_breed), titleText = stringResource(R.string.breed), textValue = "", @@ -101,12 +101,8 @@ fun Screen(navController: NavController) { } item { DropDown( - textInputModifier = Modifier.padding( - start = 24.sdp, - end = 24.sdp, - bottom = 12.sdp, - top = 4.sdp - ), + textInputModifier = Modifier, + textTitleModifier = Modifier.padding(bottom = 4.sdp), placeholderText = stringResource(R.string.placeholder_size), titleText = stringResource(R.string.size), textValue = "", @@ -115,44 +111,29 @@ fun Screen(navController: NavController) { } item { DateInputText( - textInputModifier = Modifier.padding( - start = 24.sdp, - end = 24.sdp, - bottom = 12.sdp, - top = 4.sdp - ), + textInputModifier = Modifier, + textTitleModifier = Modifier.padding(bottom = 4.sdp), titleText = stringResource(R.string.pet_birth_date), placeholderText = stringResource(R.string.placeholder_text_DD_MM_YYYY), textValue = "", onEvent = { }, - // Será necessário criar uma função para formatar a data -// visualTransformation = { date -> -// formatDate(date) -// } + // visualTransformation = { date -> + // formatDate(date) + // } ) } item { DropDown( - textInputModifier = Modifier.padding( - start = 24.sdp, - end = 24.sdp, - bottom = 12.sdp, - top = 4.sdp - ), - placeholderText = stringResource(R.string.placeholder_weight), - titleText = stringResource(R.string.weight), + textTitleModifier = Modifier.padding(bottom = 4.sdp), + placeholderText = stringResource(id = R.string.placeholder_weight), + titleText = stringResource(id = R.string.weight), textValue = "", onEvent = { } ) } item { DropDown( - textInputModifier = Modifier.padding( - start = 24.sdp, - end = 24.sdp, - bottom = 12.sdp, - top = 4.sdp - ), + textInputModifier = Modifier.padding(top = 4.sdp), placeholderText = stringResource(R.string.placeholder_type), titleText = stringResource(R.string.type), textValue = "", @@ -160,40 +141,58 @@ fun Screen(navController: NavController) { ) } item { - DualActionButton( - buttonModifier = Modifier.padding( - start = 32.sdp, - end = 24.sdp, - bottom = 32.sdp, - top = 8.sdp - ), - titleText = stringResource(R.string.pet_sex), - rightButtonSubmit = {}, - leftButtonSubmit = {}, - enableButton = true, - leftButtonText = stringResource(R.string.male), - rightButtonText = stringResource(R.string.female) - ) + Column{ + Row { + Text( + text = stringResource(R.string.pet_sex), + textAlign = TextAlign.Start, + color = MaterialTheme.colorScheme.scrim, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight(500), + modifier = Modifier + .padding(bottom = 8.sdp) + .fillMaxWidth() + ) + } + DualActionButton( + buttonModifier = Modifier, + titleText = stringResource(R.string.pet_sex), + rightButtonSubmit = {}, + leftButtonSubmit = {}, + enableButton = true, + leftButtonText = stringResource(R.string.male), + rightButtonText = stringResource(R.string.female) + ) + } } item { - DualActionButton( - buttonModifier = Modifier.padding( - start = 32.sdp, - end = 24.sdp, - bottom = 32.sdp, - top = 8.sdp - ), - titleText = stringResource(R.string.castrated), - rightButtonSubmit = {}, - leftButtonSubmit = {}, - enableButton = true, - leftButtonText = stringResource(R.string.yes), - rightButtonText = stringResource(R.string.no), - leftButtonColor = ButtonDefaults.buttonColors(androidx.compose.material3.MaterialTheme.colorScheme.background), - rightButtonColor = ButtonDefaults.buttonColors(androidx.compose.material3.MaterialTheme.colorScheme.primary), - leftButtonTextColor = androidx.compose.material3.MaterialTheme.colorScheme.primary, - rightButtonTextColor = androidx.compose.material3.MaterialTheme.colorScheme.onPrimary, - ) + Column{ + Row { + Text( + text = stringResource(R.string.pet_registration), + textAlign = TextAlign.Start, + color = MaterialTheme.colorScheme.scrim, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight(500), + modifier = Modifier + .padding(bottom = 8.sdp) + .fillMaxWidth() + ) + } + DualActionButton( + buttonModifier = Modifier, + titleText = stringResource(R.string.castrated), + rightButtonSubmit = {}, + leftButtonSubmit = {}, + enableButton = true, + leftButtonText = stringResource(R.string.yes), + rightButtonText = stringResource(R.string.no), + leftButtonColor = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.background), + rightButtonColor = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.primary), + leftButtonTextColor = MaterialTheme.colorScheme.primary, + rightButtonTextColor = MaterialTheme.colorScheme.onPrimary, + ) + } } item { Spacer(modifier = Modifier.height(20.sdp)) @@ -222,4 +221,172 @@ fun ScreenPreview() { Screen(nav) } ) +} + +@Preview(showBackground = true) +@Composable +fun InputTextPreview() { + PetJournalTheme { + InputText( + modifier = Modifier, + textTitleModifier = Modifier.padding(bottom = 4.sdp), + textInputModifier = Modifier.testTag("inputField_test"), + placeholderText = stringResource(R.string.placeholder_name_pet), + titleText = stringResource(R.string.pet_name), + textValue = "", + onEvent = { } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun DropDownBreedPreview() { + PetJournalTheme { + DropDown( + textInputModifier = Modifier, + textTitleModifier = Modifier.padding(bottom = 4.sdp), + placeholderText = stringResource(R.string.placeholder_breed), + titleText = stringResource(R.string.breed), + textValue = "", + onEvent = { } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun DropDownSizePreview() { + PetJournalTheme { + DropDown( + textInputModifier = Modifier, + textTitleModifier = Modifier.padding(bottom = 4.sdp), + placeholderText = stringResource(R.string.placeholder_size), + titleText = stringResource(R.string.size), + textValue = "", + onEvent = { } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun DateInputTextPreview() { + PetJournalTheme { + DateInputText( + textInputModifier = Modifier, + textTitleModifier = Modifier.padding(bottom = 4.sdp), + titleText = stringResource(R.string.pet_birth_date), + placeholderText = stringResource(R.string.placeholder_text_DD_MM_YYYY), + textValue = "", + onEvent = { }, + // visualTransformation = { date -> + // formatDate(date) + // } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun DropDownWeightPreview() { + PetJournalTheme { + DropDown( + textTitleModifier = Modifier.padding(bottom = 4.sdp), + placeholderText = stringResource(id = R.string.placeholder_weight), + titleText = stringResource(id = R.string.weight), + textValue = "", + onEvent = { } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun DropDownTypePreview() { + PetJournalTheme { + DropDown( + textInputModifier = Modifier.padding(top = 4.sdp), + placeholderText = stringResource(R.string.placeholder_type), + titleText = stringResource(R.string.type), + textValue = "", + onEvent = { } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun DualActionSexPreview() { + PetJournalTheme { + Column{ + Row { + Text( + text = stringResource(R.string.pet_sex), + textAlign = TextAlign.Start, + color = MaterialTheme.colorScheme.scrim, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight(500), + modifier = Modifier + .padding(bottom = 8.sdp) + .fillMaxWidth() + ) + } + DualActionButton( + buttonModifier = Modifier, + titleText = stringResource(R.string.pet_sex), + rightButtonSubmit = {}, + leftButtonSubmit = {}, + enableButton = true, + leftButtonText = stringResource(R.string.male), + rightButtonText = stringResource(R.string.female) + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun DualActionCastratedPreview() { + PetJournalTheme { + Column{ + Row { + Text( + text = stringResource(R.string.pet_registration), + textAlign = TextAlign.Start, + color = MaterialTheme.colorScheme.scrim, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight(500), + modifier = Modifier + .padding(bottom = 8.sdp) + .fillMaxWidth() + ) + } + DualActionButton( + buttonModifier = Modifier, + titleText = stringResource(R.string.castrated), + rightButtonSubmit = {}, + leftButtonSubmit = {}, + enableButton = true, + leftButtonText = stringResource(R.string.yes), + rightButtonText = stringResource(R.string.no), + leftButtonColor = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.background), + rightButtonColor = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.primary), + leftButtonTextColor = MaterialTheme.colorScheme.primary, + rightButtonTextColor = MaterialTheme.colorScheme.onPrimary, + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun Button3SavePreview() { + PetJournalTheme { + Button3( + submit = {}, + enableButton = true, + text = stringResource(R.string.save) + ) + } } \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerTaskScreen/RegisterTaskScreen.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerTaskScreen/RegisterTaskScreen.kt new file mode 100644 index 00000000..f5987a1b --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerTaskScreen/RegisterTaskScreen.kt @@ -0,0 +1,10 @@ +package com.soujunior.petjournal.ui.screens_app.screens_pets.registerTaskScreen + +import androidx.compose.runtime.Composable +import androidx.navigation.NavController +import com.soujunior.petjournal.ui.screens_app.screens_pets.registerTaskScreen.components.ScreenRegisterTask + +@Composable +fun RegisterTaskScreen(navController: NavController) { + ScreenRegisterTask(navController) +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerTaskScreen/components/ScreenRegisterTask.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerTaskScreen/components/ScreenRegisterTask.kt new file mode 100644 index 00000000..bb3dd269 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/registerTaskScreen/components/ScreenRegisterTask.kt @@ -0,0 +1,439 @@ +package com.soujunior.petjournal.ui.screens_app.screens_pets.registerTaskScreen.components + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.ModalDrawer +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import com.soujunior.petjournal.R +import com.soujunior.petjournal.ui.components.Button3 +import com.soujunior.petjournal.ui.components.GroupSelectableButton +import com.soujunior.petjournal.ui.components.InputText +import com.soujunior.petjournal.ui.components.PetFilterList +import com.soujunior.petjournal.ui.components.Pets +import com.soujunior.petjournal.ui.components.ScaffoldCustom +import com.soujunior.petjournal.ui.components.SelectableButtonInfo +import com.soujunior.petjournal.ui.components.TextFieldCustom +import com.soujunior.petjournal.ui.components.TransactionTypeSelector +import com.soujunior.petjournal.ui.components.task.OneOffTask +import com.soujunior.petjournal.ui.components.task.RecurringTask +import com.soujunior.petjournal.ui.theme.ColorCustom +import com.soujunior.petjournal.ui.theme.PetJournalTheme +import com.soujunior.petjournal.ui.util.TransactionType +import ir.kaaveh.sdpcompose.sdp + +@Composable +fun ScreenRegisterTask(navController: NavController) { + + val listOfTasks = listOf( + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_vaccines), + ColorCustom.color_selectable_button_1 + ), + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_consultations), + ColorCustom.color_selectable_button_2 + ), + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_medicine), + ColorCustom.color_selectable_button_3 + ), + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_bath), + ColorCustom.color_selectable_button_4 + ), + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_food), + ColorCustom.color_selectable_button_5 + ), + SelectableButtonInfo( + stringResource(R.string.label_selectable_button_pet_walk), + ColorCustom.color_selectable_button_6 + ), + ) + + val listPet = listOf( + Pets( + id = 1, + imageRes = painterResource(R.drawable.image_jujuba), + name = "Jujuba" + ), + Pets( + id = 2, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ), + Pets( + id = 3, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ), + Pets( + id = 4, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ), + Pets( + id = 5, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ), + Pets( + id = 6, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ), + Pets( + id = 7, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ), + Pets( + id = 8, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ), + Pets( + id = 9, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ) + ) + + val nameTask = remember { mutableStateOf("") } + val desc = remember { mutableStateOf("") } + val ob = remember { mutableStateOf("") } + var selectedType by remember { mutableStateOf(null) } + + ScaffoldCustom( + modifier = Modifier, + navigationUp = navController, + showTopBar = true, + //todo: o valor desse Title bar precisa ser passado por parametro, + // assim ele se comportara tanto como "Nova tarefa" quanto "Editar tarefa". + titleTopBar = stringResource(R.string.label_new_task), + showBottomBarNavigation = true, + contentToUse = { paddingValues -> + Image( + painter = painterResource(R.drawable.rastro), + contentDescription = null, + modifier = Modifier + .fillMaxSize() + .offset(y = 300.sdp) + ) + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues), + verticalArrangement = Arrangement.spacedBy(12.sdp), + contentPadding = PaddingValues(horizontal = 14.sdp), + content = { + item { + GroupSelectableButton(listOfTasks) + } + item { + InputText( + modifier = Modifier.testTag("inputFieldTag"), + placeholderText = stringResource(R.string.enter_task_name_here), + titleText = stringResource(R.string.task_name), + textValue = nameTask.value, + onEvent = { t -> + nameTask.value = t + + }, + ) + } + item { + TextFieldCustom( + title = stringResource(R.string.label_description), + placeholder = stringResource(R.string.enter_the_task_description_here), + value = desc.value, + onValueChange = { d -> + desc.value = d + } + ) + } + item { + PetFilterList( + listPet, + onSelectedPet = { + + } + ) + } + item { + Column { + TransactionTypeSelector( + onSelectionChanged = { type -> + selectedType = type + } + ) + + when (selectedType) { + TransactionType.Recurrent -> { + RecurringTask( + setOf(), + onAmPmSelector = { + + }, + onTime = { hour, minute -> + + }, + onWeekDaySelected = { + + }, + onDaySelected = { + + } + ) + } + + TransactionType.OneOff -> { + OneOffTask( + onDateSelected = { + + }, + onAmPmSelector = { + + }, + onTime = { hour, minute -> + + } + ) + } + + null -> {} + } + } + } + item { + TextFieldCustom( + title = stringResource(R.string.label_observation), + placeholder = stringResource(R.string.enter_your_observation_here), + value = ob.value, + onValueChange = { o -> + ob.value = o + } + ) + } + item { + Button3(submit = { /*TODO*/ }, enableButton = true, text = stringResource(R.string.label_save_task)) + } + } + ) + } + ) +} + +@Preview(showBackground = true, showSystemUi = true, device = "id:pixel_4_xl") +@Composable +fun ScreenRegisterTaskPreview() { + val nav = rememberNavController() + ScreenRegisterTask(nav) +} + + +private val listOfTasks = listOf( + SelectableButtonInfo( + "Vacinas", + ColorCustom.color_selectable_button_1 + ), + SelectableButtonInfo( + "Consultas", + ColorCustom.color_selectable_button_2 + ), + SelectableButtonInfo( + "Remédios", + ColorCustom.color_selectable_button_3 + ), + SelectableButtonInfo( + "Banho", + ColorCustom.color_selectable_button_4 + ), + SelectableButtonInfo( + "Comida", + ColorCustom.color_selectable_button_5 + ), + SelectableButtonInfo( + "Passeio", + ColorCustom.color_selectable_button_6 + ), +) + +@Preview(showBackground = true) +@Composable +fun GroupSelectableButtonPreview() { + PetJournalTheme { + GroupSelectableButton( + listOfTasks, + onSelection = { + + } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun InputTextTaskNamePreview() { + val nameTask = remember { mutableStateOf("") } + PetJournalTheme { + InputText( + modifier = Modifier.testTag("inputFieldTag"), + placeholderText = stringResource(R.string.enter_task_name_here), + titleText = stringResource(R.string.task_name), + textValue = nameTask.value, + onEvent = { t -> + nameTask.value = t + }, + ) + } +} + +@Preview(showBackground = true) +@Composable +fun TextFieldCustomDescriptionPreview() { + val desc = remember { mutableStateOf("") } + PetJournalTheme { + TextFieldCustom( + title = stringResource(R.string.label_description), + placeholder = stringResource(R.string.enter_the_task_description_here), + value = desc.value, + onValueChange = { d -> + desc.value = d + } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun PetFilterListPreview() { + val listPet = listOf( + Pets( + id = 1, + imageRes = painterResource(R.drawable.image_jujuba), + name = "Jujuba" + ), + Pets( + id = 2, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ), + Pets( + id = 3, + imageRes = painterResource(R.drawable.image_alfredo), + name = "Alfredo" + ) + ) + PetJournalTheme { + PetFilterList( + listPet, + onSelectedPet = { + + } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun TransactionTypeSelectorPreview() { + var selectedType by remember { mutableStateOf(null) } + PetJournalTheme { + TransactionTypeSelector( + onSelectionChanged = { type -> + selectedType = type + } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun RecurringTaskPreview() { + PetJournalTheme { + RecurringTask( + setOf(), + onAmPmSelector = { + + }, + onTime = { hour, minute -> + + }, + onWeekDaySelected = { + + }, + onDaySelected = { + + } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun OneOffTaskPreview() { + PetJournalTheme { + OneOffTask( + onDateSelected = { + + }, + onAmPmSelector = { + + }, + onTime = { hour, minute -> + + } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun TextFieldCustomObservationPreview() { + val ob = remember { mutableStateOf("") } + PetJournalTheme { + TextFieldCustom( + title = stringResource(R.string.label_observation), + placeholder = stringResource(R.string.enter_your_observation_here), + value = ob.value, + onValueChange = { o -> + ob.value = o + } + ) + } +} + +@Preview(showBackground = true) +@Composable +fun Button3SaveTaskPreview() { + PetJournalTheme { + Button3( + submit = { /*TODO*/ }, + enableButton = true, + text = stringResource(R.string.label_save_task) + ) + } +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/TaskListScreen.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/TaskListScreen.kt new file mode 100644 index 00000000..f402e532 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/TaskListScreen.kt @@ -0,0 +1,10 @@ +package com.soujunior.petjournal.ui.screens_app.screens_pets.taskListScreen + +import androidx.compose.runtime.Composable +import androidx.navigation.NavController +import com.soujunior.petjournal.ui.screens_app.screens_pets.taskListScreen.components.Screen + +@Composable +fun TaskListScreen(navController: NavController) { + Screen(navController) +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/TaskListViewModel.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/TaskListViewModel.kt new file mode 100644 index 00000000..2cc1ec08 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/TaskListViewModel.kt @@ -0,0 +1,2 @@ +package com.soujunior.petjournal.ui.screens_app.screens_pets.taskListScreen + diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/TaskListViewModelImpl.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/TaskListViewModelImpl.kt new file mode 100644 index 00000000..b3cbcbd5 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/TaskListViewModelImpl.kt @@ -0,0 +1,4 @@ +package com.soujunior.petjournal.ui.screens_app.screens_pets.taskListScreen + +class TaskListViewModelImpl { +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/components/Screen.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/components/Screen.kt new file mode 100644 index 00000000..34cce820 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/screens_app/screens_pets/taskListScreen/components/Screen.kt @@ -0,0 +1,9 @@ +package com.soujunior.petjournal.ui.screens_app.screens_pets.taskListScreen.components + +import androidx.compose.runtime.Composable +import androidx.navigation.NavController + +@Composable +fun Screen(navController: NavController){ + +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/theme/Color.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/theme/Color.kt index 8fcf6daa..dff0a3be 100644 --- a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/theme/Color.kt +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/theme/Color.kt @@ -95,7 +95,7 @@ object ColorCustom { val color_border_pet_icon = Color(0xFF9C4DCC) val color_title_pet_icon = Color(0xFF222222) val color_placeholder = Color(0xFFCCCCCC) - val color_shadow_dialog = Color(0x4D000000) - val color_border_dialog = Color(0xFF8D4CD2) - val color_background_button_dialog = Color(0xFF9C4DFF) + val color_text_button_transaction_type = Color(0xFF8dD4CD2) + val color_border_button_transaction_type = Color(0xFFA2A9B1) + val color_unfocused_wheelTimePicker = Color(0xFFDADADA) } \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/util/SelectedPeriodType.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/util/SelectedPeriodType.kt new file mode 100644 index 00000000..3fa0a40e --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/util/SelectedPeriodType.kt @@ -0,0 +1,5 @@ +package com.soujunior.petjournal.ui.util + +enum class SelectedPeriodType { + Diária, Semanal, Mensal +} \ No newline at end of file diff --git a/petJournal/app/src/main/java/com/soujunior/petjournal/ui/util/TransactionType.kt b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/util/TransactionType.kt new file mode 100644 index 00000000..0a632ab5 --- /dev/null +++ b/petJournal/app/src/main/java/com/soujunior/petjournal/ui/util/TransactionType.kt @@ -0,0 +1,5 @@ +package com.soujunior.petjournal.ui.util + +enum class TransactionType { + Recurrent, OneOff +} \ No newline at end of file diff --git a/petJournal/app/src/main/res/drawable/icone_banho.png b/petJournal/app/src/main/res/drawable/icone_banho.png new file mode 100644 index 00000000..85b6e0b8 Binary files /dev/null and b/petJournal/app/src/main/res/drawable/icone_banho.png differ diff --git a/petJournal/app/src/main/res/drawable/icone_banhos_vector.xml b/petJournal/app/src/main/res/drawable/icone_banhos_vector.xml new file mode 100644 index 00000000..16052616 --- /dev/null +++ b/petJournal/app/src/main/res/drawable/icone_banhos_vector.xml @@ -0,0 +1,9 @@ + + + diff --git a/petJournal/app/src/main/res/drawable/icone_consulta.png b/petJournal/app/src/main/res/drawable/icone_consulta.png new file mode 100644 index 00000000..a8cb8b9c Binary files /dev/null and b/petJournal/app/src/main/res/drawable/icone_consulta.png differ diff --git a/petJournal/app/src/main/res/drawable/icone_consultas_vector.xml b/petJournal/app/src/main/res/drawable/icone_consultas_vector.xml new file mode 100644 index 00000000..d26b9e7a --- /dev/null +++ b/petJournal/app/src/main/res/drawable/icone_consultas_vector.xml @@ -0,0 +1,13 @@ + + + diff --git a/petJournal/app/src/main/res/drawable/icone_medicamento.png b/petJournal/app/src/main/res/drawable/icone_medicamento.png new file mode 100644 index 00000000..325fa4f7 Binary files /dev/null and b/petJournal/app/src/main/res/drawable/icone_medicamento.png differ diff --git a/petJournal/app/src/main/res/drawable/icone_medicamentos_vector.xml b/petJournal/app/src/main/res/drawable/icone_medicamentos_vector.xml new file mode 100644 index 00000000..9f136be3 --- /dev/null +++ b/petJournal/app/src/main/res/drawable/icone_medicamentos_vector.xml @@ -0,0 +1,24 @@ + + + + + diff --git a/petJournal/app/src/main/res/drawable/icone_passeio.png b/petJournal/app/src/main/res/drawable/icone_passeio.png new file mode 100644 index 00000000..32e3ae1c Binary files /dev/null and b/petJournal/app/src/main/res/drawable/icone_passeio.png differ diff --git a/petJournal/app/src/main/res/drawable/icone_passeios_vector.xml b/petJournal/app/src/main/res/drawable/icone_passeios_vector.xml new file mode 100644 index 00000000..c8c5cd02 --- /dev/null +++ b/petJournal/app/src/main/res/drawable/icone_passeios_vector.xml @@ -0,0 +1,11 @@ + + + diff --git a/petJournal/app/src/main/res/drawable/icone_racao.png b/petJournal/app/src/main/res/drawable/icone_racao.png new file mode 100644 index 00000000..a58289f1 Binary files /dev/null and b/petJournal/app/src/main/res/drawable/icone_racao.png differ diff --git a/petJournal/app/src/main/res/drawable/icone_racao_vector.xml b/petJournal/app/src/main/res/drawable/icone_racao_vector.xml new file mode 100644 index 00000000..3b46755b --- /dev/null +++ b/petJournal/app/src/main/res/drawable/icone_racao_vector.xml @@ -0,0 +1,9 @@ + + + diff --git a/petJournal/app/src/main/res/drawable/icone_vacinas.png b/petJournal/app/src/main/res/drawable/icone_vacinas.png new file mode 100644 index 00000000..df84cfdf Binary files /dev/null and b/petJournal/app/src/main/res/drawable/icone_vacinas.png differ diff --git a/petJournal/app/src/main/res/drawable/icone_vacinas_vector.xml b/petJournal/app/src/main/res/drawable/icone_vacinas_vector.xml new file mode 100644 index 00000000..f1e11706 --- /dev/null +++ b/petJournal/app/src/main/res/drawable/icone_vacinas_vector.xml @@ -0,0 +1,13 @@ + + + diff --git a/petJournal/app/src/main/res/values/strings.xml b/petJournal/app/src/main/res/values/strings.xml index be1d9d82..c85b4cf4 100644 --- a/petJournal/app/src/main/res/values/strings.xml +++ b/petJournal/app/src/main/res/values/strings.xml @@ -1,6 +1,6 @@ PetJournal - Cadastro Pet + Cadastro Raças Nome Pequeno (6kg a 14kg) @@ -145,6 +145,8 @@ Ração Passeio Essa tarefa é... + Tarefa adicionada\ncom sucesso! + Nova tarefa Ativo nos meses Todos Descrição @@ -154,9 +156,16 @@ Abrir Calendário 00/00/0000 dd/MM/yyyy - Tarefa adicionada\ncom sucesso! - Nova tarefa Ir para a HomePage AM PM + Recorrente + Pontual + Data + Digite aqui o nome da tarefa + Nome da tarefa + Observação + Digite aqui a sua observação + Salvar + Quais pets precisam dessa tarefa? \ No newline at end of file