Skip to content

Commit 2537ff4

Browse files
authored
Merge pull request #140 from devbridie/feature/xr/results-screen
Create a Spatial layout for ResultsScreen
2 parents 6c248cf + f7aa81a commit 2537ff4

File tree

19 files changed

+1226
-443
lines changed

19 files changed

+1226
-443
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.android.developers.androidify.theme.components
17+
18+
import androidx.compose.foundation.border
19+
import androidx.compose.foundation.layout.Spacer
20+
import androidx.compose.foundation.layout.width
21+
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
22+
import androidx.compose.material3.FloatingToolbarColors
23+
import androidx.compose.material3.HorizontalFloatingToolbar
24+
import androidx.compose.material3.MaterialTheme
25+
import androidx.compose.material3.Text
26+
import androidx.compose.material3.ToggleButton
27+
import androidx.compose.material3.ToggleButtonDefaults
28+
import androidx.compose.runtime.Composable
29+
import androidx.compose.ui.Modifier
30+
import androidx.compose.ui.unit.dp
31+
import kotlin.enums.enumEntries
32+
33+
@Composable
34+
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
35+
inline fun <reified T : Enum<T>> HorizontalToolbar(
36+
selectedOption: T,
37+
crossinline label: @Composable (T) -> String,
38+
crossinline onOptionSelected: (T) -> Unit,
39+
modifier: Modifier = Modifier,
40+
) {
41+
val options = enumEntries<T>()
42+
HorizontalFloatingToolbar(
43+
modifier = modifier.border(
44+
2.dp,
45+
color = MaterialTheme.colorScheme.outline,
46+
shape = MaterialTheme.shapes.large,
47+
),
48+
colors = FloatingToolbarColors(
49+
toolbarContainerColor = MaterialTheme.colorScheme.surface,
50+
toolbarContentColor = MaterialTheme.colorScheme.onSurfaceVariant,
51+
fabContainerColor = MaterialTheme.colorScheme.tertiary,
52+
fabContentColor = MaterialTheme.colorScheme.onTertiary,
53+
),
54+
expanded = true,
55+
) {
56+
options.forEachIndexed { index, item ->
57+
ToggleButton(
58+
modifier = Modifier,
59+
checked = selectedOption == item,
60+
onCheckedChange = { onOptionSelected(item) },
61+
shapes = ToggleButtonDefaults.shapes(checkedShape = MaterialTheme.shapes.large),
62+
colors = ToggleButtonDefaults.toggleButtonColors(
63+
checkedContainerColor = MaterialTheme.colorScheme.onSurface,
64+
containerColor = MaterialTheme.colorScheme.surface,
65+
),
66+
) {
67+
Text(label(options[index]), maxLines = 1)
68+
}
69+
if (index != options.size - 1) {
70+
Spacer(Modifier.width(8.dp))
71+
}
72+
}
73+
}
74+
}

core/xr/src/main/java/com/android/developers/androidify/xr/SpatialComponents.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import androidx.xr.compose.subspace.SpatialBox
3434
import androidx.xr.compose.subspace.SpatialBoxScope
3535
import androidx.xr.compose.subspace.SpatialPanel
3636
import androidx.xr.compose.subspace.SubspaceComposable
37+
import androidx.xr.compose.subspace.layout.MoveEvent
3738
import androidx.xr.compose.subspace.layout.SubspaceModifier
3839
import androidx.xr.compose.subspace.layout.aspectRatio
3940
import androidx.xr.compose.subspace.layout.fillMaxSize
@@ -52,13 +53,15 @@ import com.android.developers.androidify.theme.AndroidifyTheme
5253
@Composable
5354
fun SquiggleBackgroundSubspace(
5455
minimumHeight: Dp,
56+
onMove: ((MoveEvent) -> Boolean)? = null,
5557
content:
5658
@SubspaceComposable @Composable
5759
SpatialBoxScope.() -> Unit,
5860
) {
5961
BackgroundSubspace(
6062
aspectRatio = 1.7f,
6163
drawable = R.drawable.squiggle_full,
64+
onMove = onMove,
6265
minimumHeight = minimumHeight,
6366
content = content,
6467
)
@@ -69,14 +72,15 @@ fun BackgroundSubspace(
6972
aspectRatio: Float,
7073
@DrawableRes drawable: Int,
7174
minimumHeight: Dp,
75+
onMove: ((MoveEvent) -> Boolean)? = null,
7276
content:
7377
@SubspaceComposable @Composable
7478
SpatialBoxScope.() -> Unit,
7579
) {
7680
Subspace {
7781
SpatialPanel(
7882
SubspaceModifier
79-
.movable()
83+
.movable(onMove = onMove)
8084
.resizable(
8185
minimumSize = DpVolumeSize(0.dp, minimumHeight, 0.dp),
8286
maintainAspectRatio = true,

core/xr/src/main/java/com/android/developers/androidify/xr/SpatialUiModes.kt

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import androidx.compose.ui.graphics.vector.ImageVector
2727
import androidx.compose.ui.res.stringResource
2828
import androidx.compose.ui.res.vectorResource
2929
import androidx.compose.ui.unit.dp
30-
import androidx.xr.compose.platform.SpatialCapabilities
3130
import androidx.xr.scenecore.scene
3231

3332
/** Check if the device is XR-enabled, but is not yet rendering spatial UI. */
@@ -38,9 +37,8 @@ fun couldRequestFullSpace(): Boolean {
3837

3938
/** Check if the device is XR-enabled and is rendering spatial UI. */
4039
@Composable
41-
fun SpatialCapabilities.couldRequestHomeSpace(): Boolean {
42-
if (!LocalSpatialConfiguration.current.hasXrSpatialFeature) return false
43-
return isSpatialUiEnabled
40+
fun couldRequestHomeSpace(): Boolean {
41+
return LocalSpatialConfiguration.current.hasXrSpatialFeature && LocalSpatialCapabilities.current.isSpatialUiEnabled
4442
}
4543

4644
/** Default styling for an IconButton with a home space button and behavior. */
@@ -68,19 +66,26 @@ fun RequestHomeSpaceIconButton(
6866
}
6967
}
7068

71-
/** Default styling for an TopAppBar Button with a full space button and behavior. */
69+
/** Default styling for an IconButton with a full space button and behavior. */
7270
@Composable
73-
fun RequestFullSpaceIconButton(modifier: Modifier = Modifier) {
71+
fun RequestFullSpaceIconButton(
72+
modifier: Modifier = Modifier,
73+
colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
74+
) {
7475
val session = LocalSession.current ?: return
7576

7677
IconButton(
7778
modifier = modifier,
79+
colors = colors,
7880
onClick = {
7981
session.scene.requestFullSpaceMode()
8082
},
8183
) {
8284
Icon(
83-
ImageVector.vectorResource(R.drawable.expand_content_24px),
85+
modifier = Modifier
86+
.fillMaxSize()
87+
.padding(8.dp),
88+
imageVector = ImageVector.vectorResource(R.drawable.expand_content_24px),
8489
contentDescription = stringResource(R.string.xr_to_full_space_mode),
8590
)
8691
}

feature/creation/src/main/java/com/android/developers/androidify/creation/PromptTypePager.kt

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import androidx.compose.ui.tooling.preview.Preview
5757
import androidx.compose.ui.unit.dp
5858
import com.android.developers.androidify.data.DropBehaviourFactory
5959
import com.android.developers.androidify.theme.AndroidifyTheme
60+
import com.android.developers.androidify.theme.components.HorizontalToolbar
6061
import kotlinx.coroutines.launch
6162

6263
@Composable
@@ -167,39 +168,12 @@ fun PromptTypeToolbar(
167168
modifier: Modifier = Modifier,
168169
onOptionSelected: (PromptType) -> Unit,
169170
) {
170-
val options = PromptType.entries
171-
HorizontalFloatingToolbar(
172-
modifier = modifier.border(
173-
2.dp,
174-
color = MaterialTheme.colorScheme.outline,
175-
shape = MaterialTheme.shapes.large,
176-
),
177-
colors = FloatingToolbarColors(
178-
toolbarContainerColor = MaterialTheme.colorScheme.surface,
179-
toolbarContentColor = MaterialTheme.colorScheme.onSurfaceVariant,
180-
fabContainerColor = MaterialTheme.colorScheme.tertiary,
181-
fabContentColor = MaterialTheme.colorScheme.onTertiary,
182-
),
183-
expanded = true,
184-
) {
185-
options.forEachIndexed { index, label ->
186-
ToggleButton(
187-
modifier = Modifier,
188-
checked = selectedOption == label,
189-
onCheckedChange = { onOptionSelected(label) },
190-
shapes = ToggleButtonDefaults.shapes(checkedShape = MaterialTheme.shapes.large),
191-
colors = ToggleButtonDefaults.toggleButtonColors(
192-
checkedContainerColor = MaterialTheme.colorScheme.onSurface,
193-
containerColor = MaterialTheme.colorScheme.surface,
194-
),
195-
) {
196-
Text(label.displayName, maxLines = 1)
197-
}
198-
if (index != options.size - 1) {
199-
Spacer(Modifier.width(8.dp))
200-
}
201-
}
202-
}
171+
HorizontalToolbar<PromptType>(
172+
selectedOption = selectedOption,
173+
modifier = modifier,
174+
label = { item -> item.displayName },
175+
onOptionSelected = onOptionSelected,
176+
)
203177
}
204178

205179
@Preview

feature/results/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ dependencies {
6666
implementation(libs.androidx.lifecycle.process)
6767
implementation(libs.mlkit.segmentation)
6868
implementation(libs.timber)
69+
implementation(libs.androidx.xr.compose)
6970
ksp(libs.hilt.compiler)
7071

7172
implementation(libs.androidx.ui.tooling)
@@ -78,6 +79,7 @@ dependencies {
7879

7980
implementation(projects.core.theme)
8081
implementation(projects.core.util)
82+
implementation(projects.core.xr)
8183
implementation(projects.data)
8284
implementation(projects.wear.common)
8385
implementation(projects.watchface)

0 commit comments

Comments
 (0)