@@ -43,11 +43,9 @@ import androidx.compose.material3.Text
4343import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
4444import androidx.compose.runtime.Composable
4545import androidx.compose.runtime.LaunchedEffect
46+ import androidx.compose.runtime.collectAsState
4647import androidx.compose.runtime.getValue
47- import androidx.compose.runtime.mutableStateOf
4848import androidx.compose.runtime.remember
49- import androidx.compose.runtime.saveable.rememberSaveable
50- import androidx.compose.runtime.setValue
5149import androidx.compose.ui.Alignment
5250import androidx.compose.ui.Modifier
5351import androidx.compose.ui.draw.alpha
@@ -59,9 +57,12 @@ import androidx.compose.ui.unit.dp
5957import androidx.window.core.layout.WindowSizeClass
6058import androidx.window.core.layout.WindowWidthSizeClass
6159import androidx.xr.compose.platform.LocalSpatialCapabilities
60+ import androidx.xr.compose.platform.LocalSpatialConfiguration
6261import androidx.xr.compose.spatial.ContentEdge
6362import androidx.xr.compose.spatial.Orbiter
6463import androidx.xr.compose.spatial.Subspace
64+ import androidx.xr.compose.subspace.MovePolicy
65+ import androidx.xr.compose.subspace.ResizePolicy
6566import androidx.xr.compose.subspace.SpatialColumn
6667import androidx.xr.compose.subspace.SpatialPanel
6768import androidx.xr.compose.subspace.SpatialRow
@@ -70,34 +71,87 @@ import androidx.xr.compose.subspace.layout.alpha
7071import androidx.xr.compose.subspace.layout.fillMaxSize
7172import androidx.xr.compose.subspace.layout.fillMaxWidth
7273import androidx.xr.compose.subspace.layout.height
73- import androidx.xr.compose.subspace.layout.movable
7474import androidx.xr.compose.subspace.layout.offset
7575import androidx.xr.compose.subspace.layout.padding
76- import androidx.xr.compose.subspace.layout.resizable
76+ import androidx.xr.compose.subspace.layout.rotate
7777import androidx.xr.compose.subspace.layout.size
7878import androidx.xr.compose.subspace.layout.width
79+ import androidx.xr.runtime.math.Quaternion
7980import com.example.helloandroidxr.R
81+ import com.example.helloandroidxr.ui.components.BugdroidControls
8082import com.example.helloandroidxr.ui.components.BugdroidModel
83+ import com.example.helloandroidxr.ui.components.BugdroidSliderControls
8184import com.example.helloandroidxr.ui.components.EnvironmentControls
8285import com.example.helloandroidxr.ui.components.SearchBar
86+ import com.example.helloandroidxr.ui.components.TextPane
8387import com.example.helloandroidxr.ui.theme.HelloAndroidXRTheme
88+ import com.example.helloandroidxr.viewmodel.BugdroidUiState
89+ import com.example.helloandroidxr.viewmodel.BugdroidViewModel
90+ import com.example.helloandroidxr.viewmodel.ModelMaterialColor
91+ import com.example.helloandroidxr.viewmodel.ModelMaterialProperties
92+ import com.example.helloandroidxr.viewmodel.ModelOffset
93+ import com.example.helloandroidxr.viewmodel.ModelRotation
94+ import com.example.helloandroidxr.viewmodel.SliderGroup
8495import kotlinx.coroutines.launch
8596
8697@Composable
8798fun HelloAndroidXRApp () {
99+ val viewModel = BugdroidViewModel ()
100+ val uiState by viewModel.uiState.collectAsState()
88101 if (LocalSpatialCapabilities .current.isSpatialUiEnabled) {
89102 SpatialLayout (
90- primaryContent = { PrimaryContent () },
91- firstSupportingContent = { BlockOfContentOne () },
92- secondSupportingContent = { BlockOfContentTwo () }
103+ primaryContent = {
104+ PrimaryContent (
105+ uiState = uiState,
106+ onShowBugdroidToggle = viewModel::updateShowBugdroid,
107+ onAnimateBugdroidToggle = viewModel::updateAnimateBugdroid
108+ )
109+ },
110+ firstSupportingContent = {
111+ BlockOfContentOne (
112+ showBugdroid = uiState.showBugdroid,
113+ onSliderGroupSelected = viewModel::updateShownSliderGroup,
114+ onResetModel = viewModel::resetModel
115+ )
116+ },
117+ secondSupportingContent = {
118+ BlockOfContentTwo (
119+ uiState = uiState,
120+ showBugdroid = uiState.showBugdroid,
121+ onScaleChange = viewModel::updateScale,
122+ onRotationChange = viewModel::updateRotation,
123+ onOffsetChange = viewModel::updateOffset,
124+ onMaterialColorChange = viewModel::updateMaterialColor,
125+ onMaterialPropertiesChange = viewModel::updateMaterialProperties
126+ )
127+ }
93128 )
94129 } else {
95130 NonSpatialTwoPaneLayout (
96131 secondaryPane = {
97- BlockOfContentOne ()
98- BlockOfContentTwo ()
132+ BlockOfContentOne (
133+ modifier = Modifier .height(240 .dp),
134+ showBugdroid = uiState.showBugdroid,
135+ onSliderGroupSelected = viewModel::updateShownSliderGroup,
136+ onResetModel = viewModel::resetModel
137+ )
138+ BlockOfContentTwo (
139+ uiState = uiState,
140+ showBugdroid = uiState.showBugdroid,
141+ onScaleChange = viewModel::updateScale,
142+ onRotationChange = viewModel::updateRotation,
143+ onOffsetChange = viewModel::updateOffset,
144+ onMaterialColorChange = viewModel::updateMaterialColor,
145+ onMaterialPropertiesChange = viewModel::updateMaterialProperties
146+ )
99147 },
100- primaryPane = { PrimaryContent () }
148+ primaryPane = {
149+ PrimaryContent (
150+ uiState = uiState,
151+ onShowBugdroidToggle = viewModel::updateShowBugdroid,
152+ onAnimateBugdroidToggle = viewModel::updateAnimateBugdroid
153+ )
154+ }
101155 )
102156 }
103157}
@@ -127,18 +181,18 @@ private fun SpatialLayout(
127181 SubspaceModifier
128182 .alpha(animatedAlpha.value)
129183 .size(400 .dp)
130- .padding(bottom = 16 .dp)
131- .movable()
132- .resizable( )
184+ .padding(bottom = 16 .dp),
185+ dragPolicy = MovePolicy (isEnabled = true ),
186+ resizePolicy = ResizePolicy (isEnabled = true )
133187 ) {
134188 firstSupportingContent()
135189 }
136190 SpatialPanel (
137191 SubspaceModifier
138192 .alpha(animatedAlpha.value)
139- .weight(1f )
140- .movable()
141- .resizable( )
193+ .weight(1f ),
194+ dragPolicy = MovePolicy (isEnabled = true ),
195+ resizePolicy = ResizePolicy (isEnabled = true )
142196 ) {
143197 secondSupportingContent()
144198 }
@@ -147,9 +201,9 @@ private fun SpatialLayout(
147201 modifier = SubspaceModifier
148202 .alpha(animatedAlpha.value)
149203 .fillMaxSize()
150- .padding(left = 16 .dp)
151- .movable()
152- .resizable( )
204+ .padding(left = 16 .dp),
205+ dragPolicy = MovePolicy (isEnabled = true ),
206+ resizePolicy = ResizePolicy (isEnabled = true )
153207 ) {
154208 Column {
155209 TopAppBar ()
@@ -279,29 +333,63 @@ private fun TopAppBar() {
279333}
280334
281335@Composable
282- private fun PrimaryContent (modifier : Modifier = Modifier ) {
283- var showBugdroid by rememberSaveable { mutableStateOf(false ) }
284- val stringResId = if (showBugdroid) R .string.hide_bugdroid else R .string.show_bugdroid
285-
336+ private fun PrimaryContent (
337+ uiState : BugdroidUiState ,
338+ onShowBugdroidToggle : () -> Unit ,
339+ onAnimateBugdroidToggle : () -> Unit ,
340+ modifier : Modifier = Modifier ,
341+ ) {
286342 if (LocalSpatialCapabilities .current.isSpatialUiEnabled) {
343+ val showStringResId =
344+ if (uiState.showBugdroid) R .string.hide_bugdroid else R .string.show_bugdroid
345+ val animateStringResId =
346+ if (uiState.animateBugdroid) R .string.stop_animation_bugdroid else R .string.animate_bugdroid
347+ val modelTransform = uiState.modelTransform
287348 Surface (modifier.fillMaxSize()) {
288- Box (modifier.padding(48 .dp), contentAlignment = Alignment .Center ) {
289- Button (
290- onClick = {
291- showBugdroid = ! showBugdroid
292- },
293- modifier = modifier
294- ) {
295- Text (
296- text = stringResource(id = stringResId),
297- style = MaterialTheme .typography.labelLarge
298- )
349+ Column (modifier.padding(48 .dp), horizontalAlignment = Alignment .CenterHorizontally ) {
350+ Box (modifier.padding(48 .dp), contentAlignment = Alignment .Center ) {
351+ Button (
352+ onClick = onShowBugdroidToggle,
353+ modifier = modifier
354+ ) {
355+ Text (
356+ text = stringResource(id = showStringResId),
357+ style = MaterialTheme .typography.labelLarge
358+ )
359+ }
360+ }
361+ Box (modifier.padding(48 .dp), contentAlignment = Alignment .Center ) {
362+ if (uiState.showBugdroid) {
363+ Button (
364+ onClick = onAnimateBugdroidToggle,
365+ modifier = modifier
366+ ) {
367+ Text (
368+ text = stringResource(id = animateStringResId),
369+ style = MaterialTheme .typography.labelLarge
370+ )
371+ }
372+ }
299373 }
300374 BugdroidModel (
301- showBugdroid = showBugdroid,
375+ modelTransform = modelTransform,
376+ showBugdroid = uiState.showBugdroid,
377+ animateBugdroid = uiState.animateBugdroid,
302378 modifier = SubspaceModifier
303379 .fillMaxSize()
304- .offset(z = 400 .dp) // Relative position from the panel
380+ .rotate(
381+ Quaternion (
382+ x = modelTransform.rotation.x,
383+ y = modelTransform.rotation.y,
384+ z = modelTransform.rotation.z,
385+ w = modelTransform.rotation.w
386+ )
387+ )
388+ .offset(
389+ x = modelTransform.offset.x.dp,
390+ y = modelTransform.offset.y.dp,
391+ z = modelTransform.offset.z.dp // Relative position from the panel
392+ )
305393 )
306394 }
307395 }
@@ -314,13 +402,51 @@ private fun PrimaryContent(modifier: Modifier = Modifier) {
314402}
315403
316404@Composable
317- private fun BlockOfContentOne (modifier : Modifier = Modifier ) {
318- TextPane (stringResource(R .string.block_of_content_1), modifier = modifier.height(240 .dp))
405+ private fun BlockOfContentOne (
406+ modifier : Modifier = Modifier ,
407+ showBugdroid : Boolean ,
408+ onSliderGroupSelected : (SliderGroup ) -> Unit ,
409+ onResetModel : () -> Unit
410+ ) {
411+ if (LocalSpatialConfiguration .current.hasXrSpatialFeature && showBugdroid) {
412+ BugdroidControls (
413+ onSliderGroupSelected = onSliderGroupSelected,
414+ onResetModel = {
415+ onResetModel()
416+ onSliderGroupSelected(SliderGroup .NONE )
417+ },
418+ modifier = modifier
419+ )
420+ } else {
421+ TextPane (stringResource(R .string.block_of_content_1), modifier = modifier.fillMaxHeight())
422+ }
319423}
320424
321425@Composable
322- private fun BlockOfContentTwo (modifier : Modifier = Modifier ) {
323- TextPane (stringResource(R .string.block_of_content_2), modifier = modifier.fillMaxHeight())
426+ private fun BlockOfContentTwo (
427+ modifier : Modifier = Modifier ,
428+ uiState : BugdroidUiState ,
429+ showBugdroid : Boolean ,
430+ onScaleChange : (Float ) -> Unit ,
431+ onRotationChange : (ModelRotation ) -> Unit ,
432+ onOffsetChange : (ModelOffset ) -> Unit ,
433+ onMaterialColorChange : (ModelMaterialColor ) -> Unit ,
434+ onMaterialPropertiesChange : (ModelMaterialProperties ) -> Unit ,
435+ ) {
436+ if (LocalSpatialConfiguration .current.hasXrSpatialFeature && showBugdroid) {
437+ BugdroidSliderControls (
438+ visibleSliderGroup = uiState.visibleSliderGroup,
439+ modelTransform = uiState.modelTransform,
440+ onScaleChange = onScaleChange,
441+ onRotationChange = onRotationChange,
442+ onOffsetChange = onOffsetChange,
443+ onMaterialColorChange = onMaterialColorChange,
444+ onMaterialPropertiesChange = onMaterialPropertiesChange,
445+ modifier = modifier
446+ )
447+ } else {
448+ TextPane (stringResource(R .string.block_of_content_2), modifier = modifier.fillMaxHeight())
449+ }
324450}
325451
326452@Composable
0 commit comments