diff --git a/apps/wearos/build.gradle.kts b/apps/wearos/build.gradle.kts index 38c7afea..162fe24a 100644 --- a/apps/wearos/build.gradle.kts +++ b/apps/wearos/build.gradle.kts @@ -14,5 +14,6 @@ dependencies { implementation(project(":features:wearos:calculator-fees")) implementation(project(":features:wearos:calculator-input")) implementation(project(":features:wearos:calculator-output")) + implementation(project(":features:wearos:onboarding")) implementation(project(":features:wearos:ui")) } diff --git a/apps/wearos/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/ui/main/SmartwatchActivityTest.kt b/apps/wearos/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/ui/main/SmartwatchActivityTest.kt index db876764..aebad79e 100644 --- a/apps/wearos/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/ui/main/SmartwatchActivityTest.kt +++ b/apps/wearos/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/ui/main/SmartwatchActivityTest.kt @@ -28,6 +28,7 @@ internal class SmartwatchActivityTest { @Test fun shouldDisplayActivityContents() { with(androidComposeTestRule) { + onNodeWithTag("start_calculation_action_button").assertIsDisplayed().performClick() onNodeWithText("Money amount").assertIsDisplayed() } } @@ -35,6 +36,7 @@ internal class SmartwatchActivityTest { @Test fun shouldShowCalculationBelowRangeFailure() { with(androidComposeTestRule) { + onNodeWithTag("start_calculation_action_button").assertIsDisplayed().performClick() onNodeWithText("Money amount").assertIsDisplayed() onNodeWithTag("calculatorButton_9").performClick().performClick().performClick() onNodeWithText("✔").performClick() @@ -46,6 +48,7 @@ internal class SmartwatchActivityTest { @Test fun shouldShowCalculationAboveRangeFailure() { with(androidComposeTestRule) { + onNodeWithTag("start_calculation_action_button").assertIsDisplayed().performClick() onNodeWithText("Money amount").assertIsDisplayed() onNodeWithTag("calculatorButton_4").performClick() onNodeWithTag("calculatorButton_5").performClick() @@ -60,6 +63,7 @@ internal class SmartwatchActivityTest { @Test fun shouldShowCalculationSuccess() { with(androidComposeTestRule) { + onNodeWithTag("start_calculation_action_button").assertIsDisplayed().performClick() onNodeWithText("Money amount").assertIsDisplayed() onNodeWithTag("calculatorButton_4").performClick() onNodeWithTag("calculatorButton_5").performClick() @@ -76,6 +80,7 @@ internal class SmartwatchActivityTest { @Test fun shouldShowFailureThenSuccessMakingCalculation() { with(androidComposeTestRule) { + onNodeWithTag("start_calculation_action_button").assertIsDisplayed().performClick() onNodeWithText("Money amount").assertIsDisplayed() onNodeWithTag("calculatorButton_4").performClick() diff --git a/apps/wearos/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/main/WearAppContent.kt b/apps/wearos/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/main/WearAppContent.kt index 825ab9b0..daee342c 100644 --- a/apps/wearos/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/main/WearAppContent.kt +++ b/apps/wearos/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/main/WearAppContent.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.text.style.TextAlign import androidx.wear.compose.foundation.CurvedTextStyle +import androidx.wear.compose.foundation.lazy.ScalingLazyListState import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.AppScaffold import androidx.wear.compose.material3.MaterialTheme @@ -17,55 +18,72 @@ import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.TimeText import androidx.wear.compose.material3.TimeTextDefaults import androidx.wear.compose.material3.timeTextCurvedText +import dev.marlonlom.mocca.wearos.calculator.fees.CalculatorFeesListScreen import dev.marlonlom.mocca.wearos.calculator.input.CalculatorInputScreen import dev.marlonlom.mocca.wearos.calculator.output.CalculatorOutputScreen +import dev.marlonlom.mocca.wearos.onboarding.OnboardingScreen import dev.marlonlom.mocca.wearos.ui.navigation.NavigationHost /** - * Wear app main content composable. + * Root composable for Wear OS app content. * * @author marlonlom + * + * @param isRound Whether the device screen is round. + * @param scalingLazyListState State holder for ScalingLazyColumn scroll position. */ @Composable -fun WearAppContent() { - val isRound = LocalConfiguration.current.isScreenRound - val scalingLazyListState = rememberScalingLazyListState() - AppScaffold( - timeText = { - if (!scalingLazyListState.isScrollInProgress) { - val fontStyle = MaterialTheme.typography.bodySmall - if (isRound) { - TimeText { time -> - timeTextCurvedText( - time = time, - style = CurvedTextStyle( - fontSize = fontStyle.fontSize, - ), - ) - } - } else { - val time = TimeTextDefaults.rememberTimeSource(TimeTextDefaults.timeFormat()).currentTime() - Text( - modifier = Modifier.fillMaxWidth(), - text = time, - textAlign = TextAlign.Center, - style = fontStyle, +fun WearAppContent( + isRound: Boolean = LocalConfiguration.current.isScreenRound, + scalingLazyListState: ScalingLazyListState = rememberScalingLazyListState(), +) = AppScaffold( + timeText = { + if (!scalingLazyListState.isScrollInProgress) { + val fontStyle = MaterialTheme.typography.bodySmall + if (isRound) { + TimeText { time -> + timeTextCurvedText( + time = time, + style = CurvedTextStyle( + fontSize = fontStyle.fontSize, + ), ) } + } else { + val time = TimeTextDefaults.rememberTimeSource(TimeTextDefaults.timeFormat()).currentTime() + Text( + modifier = Modifier.fillMaxWidth(), + text = time, + textAlign = TextAlign.Center, + style = fontStyle, + ) } - }, - content = { - NavigationHost( - calculatorInput = { onCalculationReadyAction -> - CalculatorInputScreen(onCalculationReadyAction = onCalculationReadyAction) - }, - calculatorOutput = { amountText, onBackNavigationAction -> - CalculatorOutputScreen( - amountText = amountText, - onBackNavigationAction = onBackNavigationAction, - ) - }, - ) - }, - ) -} + } + }, + content = { + NavigationHost( + home = { onCalculateClick, onViewFeesClick -> + OnboardingScreen( + listState = scalingLazyListState, + onCalculateClick = onCalculateClick, + onViewFeesClick = onViewFeesClick, + ) + }, + viewFees = { onBackNavigationAction -> + CalculatorFeesListScreen( + listState = scalingLazyListState, + onBackNavigationAction = onBackNavigationAction, + ) + }, + calculatorInput = { onCalculationReadyAction -> + CalculatorInputScreen(onCalculationReadyAction = onCalculationReadyAction) + }, + calculatorOutput = { amountText, onBackNavigationAction -> + CalculatorOutputScreen( + amountText = amountText, + onBackNavigationAction = onBackNavigationAction, + ) + }, + ) + }, +) diff --git a/features/wearos/calculator-fees/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/calculator/fees/CalculatorFeesListScreenUiTest.kt b/features/wearos/calculator-fees/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/calculator/fees/CalculatorFeesListScreenUiTest.kt index a21835fe..2a98ceea 100644 --- a/features/wearos/calculator-fees/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/calculator/fees/CalculatorFeesListScreenUiTest.kt +++ b/features/wearos/calculator-fees/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/calculator/fees/CalculatorFeesListScreenUiTest.kt @@ -6,6 +6,7 @@ package dev.marlonlom.mocca.wearos.calculator.fees import androidx.compose.ui.test.junit4.v2.createComposeRule import androidx.compose.ui.test.onNodeWithText +import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import org.junit.Rule import org.junit.Test @@ -19,6 +20,7 @@ internal class CalculatorFeesListScreenUiTest { with(rule) { setContent { CalculatorFeesListScreen( + listState = rememberScalingLazyListState(), onBackNavigationAction = {}, ) } diff --git a/features/wearos/calculator-fees/src/main/kotlin/dev/marlonlom/mocca/wearos/calculator/fees/CalculatorFeesListScreen.kt b/features/wearos/calculator-fees/src/main/kotlin/dev/marlonlom/mocca/wearos/calculator/fees/CalculatorFeesListScreen.kt index 7a38c3a7..e09a210c 100644 --- a/features/wearos/calculator-fees/src/main/kotlin/dev/marlonlom/mocca/wearos/calculator/fees/CalculatorFeesListScreen.kt +++ b/features/wearos/calculator-fees/src/main/kotlin/dev/marlonlom/mocca/wearos/calculator/fees/CalculatorFeesListScreen.kt @@ -20,8 +20,8 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.wear.compose.foundation.lazy.ScalingLazyColumn +import androidx.wear.compose.foundation.lazy.ScalingLazyListState import androidx.wear.compose.foundation.lazy.itemsIndexed -import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.Text import dev.marlonlom.mocca.wearos.calculator.fees.component.CalculationFeeListItem @@ -33,18 +33,18 @@ import dev.marlonlom.mocca.wearos.calculator.fees.domain.CalculatorFeesProvider * * @author marlonlom * + * @param listState Lazy column state. * @param onBackNavigationAction Callback invoked when the user requests to navigate * back to the previous screen. */ @Composable -fun CalculatorFeesListScreen(onBackNavigationAction: () -> Unit) { +fun CalculatorFeesListScreen(listState: ScalingLazyListState, onBackNavigationAction: () -> Unit) { BackHandler { onBackNavigationAction() } val feesListingsState: List = remember { CalculatorFeesProvider.provideFees() } - val listState = rememberScalingLazyListState() ScalingLazyColumn( state = listState, modifier = Modifier diff --git a/features/wearos/onboarding/build.gradle.kts b/features/wearos/onboarding/build.gradle.kts new file mode 100644 index 00000000..01ae2d8b --- /dev/null +++ b/features/wearos/onboarding/build.gradle.kts @@ -0,0 +1,17 @@ +/* + * Copyright 2024 Marlonlom + * SPDX-License-Identifier: Apache-2.0 + */ + +plugins { + id("mocca.compose.lib") + id("mocca.android.lib.wearos") +} + +android { + namespace = "dev.marlonlom.mocca.wearos.onboarding" +} + +dependencies { + implementation(project(":features:wearos:ui")) +} diff --git a/features/wearos/onboarding/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/onboarding/OnboardingScreenUiTest.kt b/features/wearos/onboarding/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/onboarding/OnboardingScreenUiTest.kt new file mode 100644 index 00000000..0a1c516c --- /dev/null +++ b/features/wearos/onboarding/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/onboarding/OnboardingScreenUiTest.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Marlonlom + * SPDX-License-Identifier: Apache-2.0 + */ +package dev.marlonlom.mocca.wearos.onboarding + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.v2.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState +import com.google.common.truth.Truth.assertThat +import org.junit.FixMethodOrder +import org.junit.Rule +import org.junit.Test +import org.junit.runners.MethodSorters + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +internal class OnboardingScreenUiTest { + + @get:Rule + var rule = createComposeRule() + + @Test + fun shouldDisplayScreenThenClickedStartCalculationButton() { + with(rule) { + var clicked = false + setContent { + OnboardingScreen( + listState = rememberScalingLazyListState(), + onCalculateClick = { clicked = true }, + onViewFeesClick = { }, + ) + } + onNodeWithTag("start_calculation_action_button").assertIsDisplayed() + onNodeWithTag("view_fees_action_button").assertIsDisplayed() + onNodeWithText("Start calculation").assertIsDisplayed().performClick() + onNodeWithText("View fees").assertIsDisplayed() + assertThat(clicked).isTrue() + } + } + + @Test + fun shouldDisplayScreenThenClickedViewFeesButton() { + with(rule) { + var clicked = false + setContent { + OnboardingScreen( + listState = rememberScalingLazyListState(), + onCalculateClick = { }, + onViewFeesClick = { clicked = true }, + ) + } + onNodeWithText("Start calculation").assertIsDisplayed() + onNodeWithText("View fees").assertIsDisplayed().performClick() + assertThat(clicked).isTrue() + } + } +} diff --git a/features/wearos/onboarding/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/StartCalculationButtonUiTest.kt b/features/wearos/onboarding/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/StartCalculationButtonUiTest.kt new file mode 100644 index 00000000..f1f0b6a9 --- /dev/null +++ b/features/wearos/onboarding/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/StartCalculationButtonUiTest.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2024 Marlonlom + * SPDX-License-Identifier: Apache-2.0 + */ +package dev.marlonlom.mocca.wearos.onboarding.component + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.v2.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test + +internal class StartCalculationButtonUiTest { + + @get:Rule + var rule = createComposeRule() + + @Test + fun shouldDisplayButtonThenCheckClicked() { + with(rule) { + var clicked = false + setContent { + StartCalculationButton( + onClicked = { clicked = true }, + ) + } + onNodeWithTag("start_calculation_action_button").assertIsDisplayed() + onNodeWithText("Start calculation").assertIsDisplayed().performClick() + assertThat(clicked).isTrue() + } + } +} diff --git a/features/wearos/onboarding/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/ViewFeesButtonUiTest.kt b/features/wearos/onboarding/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/ViewFeesButtonUiTest.kt new file mode 100644 index 00000000..5a2ffd79 --- /dev/null +++ b/features/wearos/onboarding/src/androidTest/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/ViewFeesButtonUiTest.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2024 Marlonlom + * SPDX-License-Identifier: Apache-2.0 + */ +package dev.marlonlom.mocca.wearos.onboarding.component + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.v2.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test + +internal class ViewFeesButtonUiTest { + + @get:Rule + var rule = createComposeRule() + + @Test + fun shouldDisplayButtonThenCheckClicked() { + with(rule) { + var clicked = false + setContent { + ViewFeesButton( + onClicked = { clicked = true }, + ) + } + onNodeWithTag("view_fees_action_button").assertIsDisplayed() + onNodeWithText("View fees").assertIsDisplayed().performClick() + assertThat(clicked).isTrue() + } + } +} diff --git a/features/wearos/onboarding/src/main/kotlin/dev/marlonlom/mocca/wearos/onboarding/OnboardingScreen.kt b/features/wearos/onboarding/src/main/kotlin/dev/marlonlom/mocca/wearos/onboarding/OnboardingScreen.kt new file mode 100644 index 00000000..3a1929ea --- /dev/null +++ b/features/wearos/onboarding/src/main/kotlin/dev/marlonlom/mocca/wearos/onboarding/OnboardingScreen.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2024 Marlonlom + * SPDX-License-Identifier: Apache-2.0 + */ +package dev.marlonlom.mocca.wearos.onboarding + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.wear.compose.foundation.lazy.ScalingLazyColumn +import androidx.wear.compose.foundation.lazy.ScalingLazyListState +import androidx.wear.compose.material3.MaterialTheme +import dev.marlonlom.mocca.wearos.onboarding.component.StartCalculationButton +import dev.marlonlom.mocca.wearos.onboarding.component.ViewFeesButton + +/** + * Displays the onboarding screen with actions to proceed to calculation or view fees. + * + * @author marlonlom + * + * @param listState Lazy column state. + * @param onCalculateClick Invoked when the user selects the calculate action. + * @param onViewFeesClick Invoked when the user selects the view fees action. + */ +@Composable +fun OnboardingScreen(listState: ScalingLazyListState, onCalculateClick: () -> Unit, onViewFeesClick: () -> Unit) = + ScalingLazyColumn( + state = listState, + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + item { + Spacer(Modifier.height(20.dp)) + } + item { + StartCalculationButton(onClicked = onCalculateClick) + } + item { + ViewFeesButton(onClicked = onViewFeesClick) + } + } diff --git a/features/wearos/onboarding/src/main/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/StartCalculationButton.kt b/features/wearos/onboarding/src/main/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/StartCalculationButton.kt new file mode 100644 index 00000000..29b266e0 --- /dev/null +++ b/features/wearos/onboarding/src/main/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/StartCalculationButton.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Marlonlom + * SPDX-License-Identifier: Apache-2.0 + */ +package dev.marlonlom.mocca.wearos.onboarding.component + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.AttachMoney +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.wear.compose.material3.Button +import androidx.wear.compose.material3.ButtonDefaults +import androidx.wear.compose.material3.Icon +import androidx.wear.compose.material3.MaterialTheme +import androidx.wear.compose.material3.Text +import dev.marlonlom.mocca.wearos.onboarding.R + +/** + * Displays a button that navigates to the calculation screen. + * + * @author marlonlom + * + * @param onClicked Action invoked when the button is clicked. + */ +@Composable +internal fun StartCalculationButton(onClicked: () -> Unit) = Button( + modifier = Modifier.testTag("start_calculation_action_button") + .fillMaxWidth(), + onClick = onClicked, + colors = ButtonDefaults.buttonColors( + containerColor = Color.Transparent, + disabledContainerColor = Color.Transparent, + contentColor = MaterialTheme.colorScheme.primary, + ), + border = BorderStroke( + width = 1.dp, + color = MaterialTheme.colorScheme.primary, + ), + icon = { + Icon( + imageVector = Icons.Rounded.AttachMoney, + contentDescription = stringResource(R.string.text_start_calculation), + tint = MaterialTheme.colorScheme.primary, + ) + }, + label = { + Text( + text = stringResource(R.string.text_start_calculation), + color = MaterialTheme.colorScheme.primary, + maxLines = 1, + style = MaterialTheme.typography.bodySmall, + overflow = TextOverflow.Ellipsis, + ) + }, +) diff --git a/features/wearos/onboarding/src/main/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/ViewFeesButton.kt b/features/wearos/onboarding/src/main/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/ViewFeesButton.kt new file mode 100644 index 00000000..547fa074 --- /dev/null +++ b/features/wearos/onboarding/src/main/kotlin/dev/marlonlom/mocca/wearos/onboarding/component/ViewFeesButton.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2024 Marlonlom + * SPDX-License-Identifier: Apache-2.0 + */ +package dev.marlonlom.mocca.wearos.onboarding.component + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.TableChart +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.wear.compose.material3.ButtonDefaults +import androidx.wear.compose.material3.CompactButton +import androidx.wear.compose.material3.Icon +import androidx.wear.compose.material3.MaterialTheme +import androidx.wear.compose.material3.Text +import dev.marlonlom.mocca.wearos.onboarding.R + +/** + * Displays a compact button that navigates to the fees screen. + * + * @author marlonlom + * + * @param onClicked Action invoked when the button is clicked. + */ +@Composable +internal fun ViewFeesButton(onClicked: () -> Unit) = CompactButton( + modifier = Modifier + .testTag("view_fees_action_button") + .fillMaxWidth(), + onClick = onClicked, + colors = ButtonDefaults.buttonColors( + containerColor = Color.Transparent, + disabledContainerColor = Color.Transparent, + contentColor = MaterialTheme.colorScheme.onSurface, + ), + icon = { + Icon( + imageVector = Icons.Rounded.TableChart, + contentDescription = stringResource(R.string.text_view_fees), + tint = MaterialTheme.colorScheme.onSurface, + ) + }, + label = { + Text( + text = stringResource(R.string.text_view_fees), + maxLines = 1, + style = MaterialTheme.typography.bodySmall, + overflow = TextOverflow.Ellipsis, + ) + }, +) diff --git a/features/wearos/onboarding/src/main/res/values-es/strings.xml b/features/wearos/onboarding/src/main/res/values-es/strings.xml new file mode 100644 index 00000000..0478230d --- /dev/null +++ b/features/wearos/onboarding/src/main/res/values-es/strings.xml @@ -0,0 +1,10 @@ + + + + + Iniciar cálculo + Ver tarifas + diff --git a/features/wearos/onboarding/src/main/res/values/strings.xml b/features/wearos/onboarding/src/main/res/values/strings.xml new file mode 100644 index 00000000..668af454 --- /dev/null +++ b/features/wearos/onboarding/src/main/res/values/strings.xml @@ -0,0 +1,10 @@ + + + + + Start calculation + View fees + diff --git a/features/wearos/ui/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationHost.kt b/features/wearos/ui/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationHost.kt index 55e23fa4..b751683c 100644 --- a/features/wearos/ui/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationHost.kt +++ b/features/wearos/ui/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationHost.kt @@ -9,28 +9,49 @@ import androidx.navigation.NavHostController import androidx.wear.compose.navigation.SwipeDismissableNavHost import androidx.wear.compose.navigation.composable import androidx.wear.compose.navigation.rememberSwipeDismissableNavController +import dev.marlonlom.mocca.wearos.ui.navigation.NavigationRoutes.Calculator import dev.marlonlom.mocca.wearos.ui.navigation.NavigationRoutes.Home import dev.marlonlom.mocca.wearos.ui.navigation.NavigationRoutes.Result +import dev.marlonlom.mocca.wearos.ui.navigation.NavigationRoutes.ViewFees /** - * Application navigation host composable. + * Navigation host that wires together app screens using a NavHostController. * * @author marlonlom * - * @param calculatorInput Calculator input composable. - * @param calculatorOutput Calculator output composable. - * @param navController Navigation controller. + * @param home Home screen with primary and secondary navigation actions. + * @param calculatorInput Screen for entering calculation input. + * @param calculatorOutput Screen for displaying results and handling navigation. + * @param viewFees Screen showing fee information. + * @param navController Navigation controller (defaults to swipe-dismissable controller). */ @Composable fun NavigationHost( + home: @Composable (() -> Unit, () -> Unit) -> Unit, calculatorInput: @Composable ((String) -> Unit) -> Unit, calculatorOutput: @Composable (String, () -> Unit) -> Unit, + viewFees: @Composable (() -> Unit) -> Unit, navController: NavHostController = rememberSwipeDismissableNavController(), ) = SwipeDismissableNavHost( navController = navController, startDestination = Home.route, ) { composable(route = Home.route) { + home( + { + navController.navigate(Calculator.route) + }, + { + navController.navigate(ViewFees.route) + }, + ) + } + + composable(route = ViewFees.route) { + viewFees(navController::popBackStack) + } + + composable(route = Calculator.route) { calculatorInput { amountText -> navController.navigate(Result.makeRoute(amountText)) } diff --git a/features/wearos/ui/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationRoutes.kt b/features/wearos/ui/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationRoutes.kt index 390477d6..bc61386f 100644 --- a/features/wearos/ui/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationRoutes.kt +++ b/features/wearos/ui/src/main/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationRoutes.kt @@ -20,7 +20,21 @@ sealed class NavigationRoutes(val route: String) { * * @author marlonlom */ - data object Home : NavigationRoutes(route = "calculator_input") + data object Home : NavigationRoutes(route = "welcome") + + /** + * Calculation fees listing navigation route single object. + * + * @author marlonlom + */ + data object ViewFees : NavigationRoutes(route = "calculator_fees") + + /** + * Calculation input navigation route single object. + * + * @author marlonlom + */ + data object Calculator : NavigationRoutes(route = "calculator_input") /** * Calculation result navigation route single object. diff --git a/features/wearos/ui/src/test/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationRoutesTest.kt b/features/wearos/ui/src/test/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationRoutesTest.kt index 6e8af126..926081c3 100644 --- a/features/wearos/ui/src/test/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationRoutesTest.kt +++ b/features/wearos/ui/src/test/kotlin/dev/marlonlom/mocca/wearos/ui/navigation/NavigationRoutesTest.kt @@ -4,8 +4,10 @@ */ package dev.marlonlom.mocca.wearos.ui.navigation +import dev.marlonlom.mocca.wearos.ui.navigation.NavigationRoutes.Calculator import dev.marlonlom.mocca.wearos.ui.navigation.NavigationRoutes.Home import dev.marlonlom.mocca.wearos.ui.navigation.NavigationRoutes.Result +import dev.marlonlom.mocca.wearos.ui.navigation.NavigationRoutes.ViewFees import org.junit.Assert.assertEquals import org.junit.Test @@ -13,7 +15,17 @@ internal class NavigationRoutesTest { @Test fun `Should assert home destination route`() { - assertEquals("calculator_input", Home.route) + assertEquals("welcome", Home.route) + } + + @Test + fun `Should assert fees listing destination route`() { + assertEquals("calculator_fees", ViewFees.route) + } + + @Test + fun `Should assert calculator input destination route`() { + assertEquals("calculator_input", Calculator.route) } @Test diff --git a/settings.gradle.kts b/settings.gradle.kts index c44800d6..2e5b8a77 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -43,6 +43,7 @@ include( ":features:wearos:calculator-input", ":features:wearos:calculator-fees", ":features:wearos:calculator-output", + ":features:wearos:onboarding", ":features:wearos:ui" ) include(":benchmarks:macro:mobile")