diff --git a/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/Screen.kt b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/Screen.kt index e018df3591..d3935363bd 100644 --- a/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/Screen.kt +++ b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/Screen.kt @@ -16,6 +16,8 @@ package com.google.android.horologist.datalayer.sample +import com.google.android.horologist.datalayer.sample.screens.info.infoScreenRoute + sealed class Screen( val route: String, ) { @@ -26,4 +28,5 @@ sealed class Screen( data object AppHelperTrackingScreen : Screen("appHelperTrackingScreen") data object AppHelperNodesActionsScreen : Screen("appHelperNodesActionsScreen") + data object InfoScreen : Screen(infoScreenRoute) } diff --git a/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/WearApp.kt b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/WearApp.kt index 29705b9e40..5807b95e12 100644 --- a/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/WearApp.kt +++ b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/WearApp.kt @@ -25,6 +25,8 @@ import com.google.android.horologist.compose.navscaffold.WearNavScaffold import com.google.android.horologist.compose.navscaffold.scrollable import com.google.android.horologist.datalayer.sample.screens.MainScreen import com.google.android.horologist.datalayer.sample.screens.datalayer.DataLayerScreen +import com.google.android.horologist.datalayer.sample.screens.info.infoScreen +import com.google.android.horologist.datalayer.sample.screens.info.navigateToInfoScreen import com.google.android.horologist.datalayer.sample.screens.nodes.DataLayerNodesScreen import com.google.android.horologist.datalayer.sample.screens.nodesactions.NodesActionsScreen import com.google.android.horologist.datalayer.sample.screens.tracking.TrackingScreen @@ -53,12 +55,18 @@ fun WearApp( scrollable(route = Screen.ListNodesScreen.route) { DataLayerNodesScreen(columnState = it.columnState) } - scrollable(route = Screen.AppHelperTrackingScreen.route) { - TrackingScreen(columnState = it.columnState) + scrollable(route = Screen.AppHelperTrackingScreen.route) { scrolllableScaffoldContext -> + TrackingScreen( + onDisplayInfoClicked = navController::navigateToInfoScreen, + columnState = scrolllableScaffoldContext.columnState, + ) } scrollable(route = Screen.AppHelperNodesActionsScreen.route) { NodesActionsScreen(columnState = it.columnState) } + infoScreen( + onDismissClick = navController::popBackStack, + ) } } diff --git a/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/info/InfoScreen.kt b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/info/InfoScreen.kt new file mode 100644 index 0000000000..52b1c13fdc --- /dev/null +++ b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/info/InfoScreen.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.horologist.datalayer.sample.screens.info + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Done +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.wear.compose.material.Text +import androidx.wear.compose.ui.tooling.preview.WearPreviewDevices +import com.google.android.horologist.compose.layout.ScalingLazyColumn +import com.google.android.horologist.compose.layout.ScalingLazyColumnState +import com.google.android.horologist.compose.layout.belowTimeTextPreview +import com.google.android.horologist.compose.material.Button +import com.google.android.horologist.datalayer.sample.R + +@Composable +fun InfoScreen( + onDismissClick: () -> Unit, + columnState: ScalingLazyColumnState, + modifier: Modifier = Modifier, + infoScreenViewModel: InfoScreenViewModel = hiltViewModel(), +) { + InfoScreen( + message = infoScreenViewModel.message, + onDismissClick = onDismissClick, + columnState = columnState, + modifier = modifier, + ) +} + +@Composable +fun InfoScreen( + message: String, + onDismissClick: () -> Unit, + columnState: ScalingLazyColumnState, + modifier: Modifier = Modifier, +) { + ScalingLazyColumn( + columnState = columnState, + modifier = modifier + .fillMaxSize(), + ) { + item { + Text(text = message, modifier = Modifier.padding(top = 20.dp)) + } + item { + Button( + imageVector = Icons.Default.Done, + contentDescription = stringResource(id = R.string.info_done_button_content_description), + onClick = onDismissClick, + modifier = Modifier.padding(top = 10.dp), + ) + } + } +} + +@WearPreviewDevices +@Composable +fun InfoScreenPreview() { + InfoScreen( + message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " + + "incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud " + + "exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", + onDismissClick = { }, + columnState = belowTimeTextPreview(), + ) +} diff --git a/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/info/InfoScreenNavigation.kt b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/info/InfoScreenNavigation.kt new file mode 100644 index 0000000000..d75723e921 --- /dev/null +++ b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/info/InfoScreenNavigation.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.horologist.datalayer.sample.screens.info + +import androidx.lifecycle.SavedStateHandle +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.navArgument +import com.google.android.horologist.compose.navscaffold.scrollable +import com.google.android.horologist.datalayer.sample.Screen +import java.net.URLDecoder +import java.net.URLEncoder + +private const val messageArg = "message" +private const val routePrefix = "infoScreen" + +private val URL_CHARACTER_ENCODING = Charsets.UTF_8.name() + +const val infoScreenRoute = "$routePrefix/{$messageArg}" + +internal class InfoScreenArgs(val message: String) { + constructor(savedStateHandle: SavedStateHandle) : + this(URLDecoder.decode(checkNotNull(savedStateHandle[messageArg]), URL_CHARACTER_ENCODING)) +} + +fun NavController.navigateToInfoScreen(message: String) { + val encodedMessage = URLEncoder.encode(message, URL_CHARACTER_ENCODING) + this.navigate("$routePrefix/$encodedMessage") +} + +fun NavGraphBuilder.infoScreen( + onDismissClick: () -> Unit, +) { + scrollable( + route = Screen.InfoScreen.route, + arguments = listOf( + navArgument(messageArg) { type = NavType.StringType }, + ), + ) { + InfoScreen( + onDismissClick = onDismissClick, + columnState = it.columnState, + ) + } +} diff --git a/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/info/InfoScreenViewModel.kt b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/info/InfoScreenViewModel.kt new file mode 100644 index 0000000000..8d3eb51c85 --- /dev/null +++ b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/info/InfoScreenViewModel.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.horologist.datalayer.sample.screens.info + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel + +class InfoScreenViewModel( + savedStateHandle: SavedStateHandle, +) : ViewModel() { + + private val infoScreenArgs: InfoScreenArgs = InfoScreenArgs(savedStateHandle) + + val message: String + get() = infoScreenArgs.message +} diff --git a/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/tracking/TrackingScreen.kt b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/tracking/TrackingScreen.kt index 1cbb650f7f..493c4a1a55 100644 --- a/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/tracking/TrackingScreen.kt +++ b/datalayer/sample/wear/src/main/java/com/google/android/horologist/datalayer/sample/screens/tracking/TrackingScreen.kt @@ -38,6 +38,7 @@ import com.google.android.horologist.datalayer.sample.R @Composable fun TrackingScreen( + onDisplayInfoClicked: (info: String) -> Unit, columnState: ScalingLazyColumnState, modifier: Modifier = Modifier, viewModel: TrackingScreenViewModel = hiltViewModel(), @@ -54,7 +55,7 @@ fun TrackingScreen( onSetupCompletedCheckedChanged = viewModel::onSetupCompletedCheckedChanged, onTileCheckedChanged = viewModel::onTileCheckedChanged, onComplicationCheckedChanged = viewModel::onComplicationCheckedChanged, - onDisplayInfoClicked = { /* TODO */ }, + onDisplayInfoClicked = onDisplayInfoClicked, columnState = columnState, modifier = modifier, ) @@ -156,7 +157,7 @@ fun TrackingScreen( for (complicationEntry in state.complicationsInstalled) { item { val info = stringResource( - id = R.string.apphelper_tracking_tile_installation_info, + id = R.string.apphelper_tracking_complication_installation_info, complicationEntry.key, ) SplitToggleChip( diff --git a/datalayer/sample/wear/src/main/res/values/strings.xml b/datalayer/sample/wear/src/main/res/values/strings.xml index f393110785..839a40abc8 100644 --- a/datalayer/sample/wear/src/main/res/values/strings.xml +++ b/datalayer/sample/wear/src/main/res/values/strings.xml @@ -31,6 +31,8 @@ Error: %1$s Value: %1$s + Close + AppHelper Tracking Tap on an item to learn more about it. Activity launched once