Skip to content

Commit d03db42

Browse files
committed
#257 adapt layouts for screens with a small height
1 parent f1420d6 commit d03db42

File tree

4 files changed

+360
-154
lines changed

4 files changed

+360
-154
lines changed

.idea/codeStyles/Project.xml

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/src/main/java/io/github/sds100/keymapper/actions/uielement/ChooseUiElementScreen.kt

Lines changed: 194 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import androidx.compose.foundation.layout.padding
1717
import androidx.compose.foundation.layout.width
1818
import androidx.compose.foundation.lazy.LazyColumn
1919
import androidx.compose.foundation.lazy.items
20+
import androidx.compose.foundation.rememberScrollState
21+
import androidx.compose.foundation.verticalScroll
2022
import androidx.compose.material.icons.Icons
2123
import androidx.compose.material.icons.rounded.ErrorOutline
2224
import androidx.compose.material3.BottomAppBar
@@ -27,6 +29,7 @@ import androidx.compose.material3.OutlinedCard
2729
import androidx.compose.material3.Scaffold
2830
import androidx.compose.material3.Surface
2931
import androidx.compose.material3.Text
32+
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
3033
import androidx.compose.runtime.Composable
3134
import androidx.compose.runtime.getValue
3235
import androidx.compose.runtime.mutableStateOf
@@ -41,14 +44,18 @@ import androidx.compose.ui.text.font.FontWeight
4144
import androidx.compose.ui.text.style.TextAlign
4245
import androidx.compose.ui.text.style.TextOverflow
4346
import androidx.compose.ui.text.withStyle
47+
import androidx.compose.ui.tooling.preview.Devices
4448
import androidx.compose.ui.tooling.preview.Preview
4549
import androidx.compose.ui.unit.dp
50+
import androidx.window.core.layout.WindowHeightSizeClass
51+
import androidx.window.core.layout.WindowWidthSizeClass
4652
import io.github.sds100.keymapper.R
4753
import io.github.sds100.keymapper.compose.KeyMapperTheme
4854
import io.github.sds100.keymapper.util.State
4955
import io.github.sds100.keymapper.util.ui.compose.CheckBoxText
5056
import io.github.sds100.keymapper.util.ui.compose.KeyMapperDropdownMenu
5157
import io.github.sds100.keymapper.util.ui.compose.SearchAppBarActions
58+
import io.github.sds100.keymapper.util.ui.compose.WindowSizeClassExt.compareTo
5259

5360
@Composable
5461
fun ChooseElementScreen(
@@ -62,7 +69,9 @@ fun ChooseElementScreen(
6269
onSelectInteractionType: (NodeInteractionType?) -> Unit = {},
6370
onAdditionalElementsCheckedChange: (Boolean) -> Unit = {},
6471
) {
65-
var interactionTypeExpanded by rememberSaveable { mutableStateOf(false) }
72+
val windowAdaptiveInfo = currentWindowAdaptiveInfo()
73+
val widthSizeClass = windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass
74+
val heightSizeClass = windowAdaptiveInfo.windowSizeClass.windowHeightSizeClass
6675

6776
Scaffold(
6877
modifier.displayCutoutPadding(),
@@ -107,82 +116,137 @@ fun ChooseElementScreen(
107116
style = MaterialTheme.typography.titleLarge,
108117
)
109118

110-
Text(
111-
modifier = Modifier.padding(horizontal = 16.dp),
112-
text = stringResource(R.string.action_interact_ui_element_choose_element_text),
113-
style = MaterialTheme.typography.bodyMedium,
114-
)
115-
116-
Spacer(modifier = Modifier.height(8.dp))
119+
if (heightSizeClass == WindowHeightSizeClass.COMPACT || widthSizeClass >= WindowWidthSizeClass.EXPANDED) {
120+
Row {
121+
InfoSection(
122+
modifier = Modifier
123+
.verticalScroll(rememberScrollState())
124+
.weight(1f),
125+
state = state,
126+
onSelectInteractionType = onSelectInteractionType,
127+
onAdditionalElementsCheckedChange = onAdditionalElementsCheckedChange,
128+
)
117129

118-
Row(
119-
modifier = Modifier.padding(horizontal = 16.dp),
120-
verticalAlignment = Alignment.CenterVertically,
121-
) {
122-
Icon(
123-
imageVector = Icons.Rounded.ErrorOutline,
124-
contentDescription = null,
125-
tint = MaterialTheme.colorScheme.error,
130+
ListSection(
131+
modifier = Modifier.weight(1f),
132+
state = state,
133+
onClickElement = onClickElement,
134+
)
135+
}
136+
} else {
137+
InfoSection(
138+
state = state,
139+
onSelectInteractionType = onSelectInteractionType,
140+
onAdditionalElementsCheckedChange = onAdditionalElementsCheckedChange,
126141
)
127-
Spacer(modifier = Modifier.width(8.dp))
128-
Text(
129-
text = stringResource(R.string.action_interact_ui_element_choose_element_not_found_subtitle),
130-
color = MaterialTheme.colorScheme.error,
131-
style = MaterialTheme.typography.titleSmall,
142+
143+
ListSection(
144+
modifier = Modifier.fillMaxSize(),
145+
state = state,
146+
onClickElement = onClickElement,
132147
)
133148
}
149+
}
150+
}
151+
}
152+
}
134153

135-
Spacer(modifier = Modifier.height(8.dp))
154+
@Composable
155+
private fun InfoSection(
156+
modifier: Modifier = Modifier,
157+
state: State<SelectUiElementState>,
158+
onSelectInteractionType: (NodeInteractionType?) -> Unit,
159+
onAdditionalElementsCheckedChange: (Boolean) -> Unit,
160+
) {
161+
Column(modifier = modifier) {
162+
Text(
163+
modifier = Modifier.padding(horizontal = 16.dp),
164+
text = stringResource(R.string.action_interact_ui_element_choose_element_text),
165+
style = MaterialTheme.typography.bodyMedium,
166+
)
136167

137-
Text(
138-
modifier = Modifier.padding(horizontal = 16.dp),
139-
text = stringResource(R.string.action_interact_ui_element_choose_element_not_found_text),
140-
style = MaterialTheme.typography.bodyMedium,
141-
)
142-
Spacer(modifier = Modifier.height(8.dp))
168+
Spacer(modifier = Modifier.height(8.dp))
143169

144-
when (state) {
145-
State.Loading -> LoadingList(modifier = Modifier.fillMaxSize())
146-
is State.Data -> {
147-
val listItems = state.data.listItems
170+
Row(
171+
modifier = Modifier.padding(horizontal = 16.dp),
172+
verticalAlignment = Alignment.CenterVertically,
173+
) {
174+
Icon(
175+
imageVector = Icons.Rounded.ErrorOutline,
176+
contentDescription = null,
177+
tint = MaterialTheme.colorScheme.error,
178+
)
179+
Spacer(modifier = Modifier.width(8.dp))
180+
Text(
181+
text = stringResource(R.string.action_interact_ui_element_choose_element_not_found_subtitle),
182+
color = MaterialTheme.colorScheme.error,
183+
style = MaterialTheme.typography.titleSmall,
184+
)
185+
}
148186

149-
CheckBoxText(
150-
modifier = Modifier
151-
.fillMaxWidth()
152-
.padding(horizontal = 8.dp),
153-
text = stringResource(R.string.action_interact_ui_element_checkbox_additional_elements),
154-
isChecked = state.data.showAdditionalElements,
155-
onCheckedChange = onAdditionalElementsCheckedChange,
156-
)
187+
Spacer(modifier = Modifier.height(8.dp))
157188

158-
Spacer(modifier = Modifier.height(8.dp))
159-
160-
if (listItems.isEmpty()) {
161-
EmptyList(
162-
modifier = Modifier
163-
.fillMaxSize()
164-
.padding(16.dp),
165-
)
166-
} else {
167-
KeyMapperDropdownMenu(
168-
modifier = Modifier.padding(horizontal = 16.dp),
169-
expanded = interactionTypeExpanded,
170-
onExpandedChange = { interactionTypeExpanded = it },
171-
label = { Text(stringResource(R.string.action_interact_ui_element_filter_interaction_type_dropdown)) },
172-
values = state.data.interactionTypes,
173-
selectedValue = state.data.selectedInteractionType,
174-
onValueChanged = onSelectInteractionType,
175-
)
176-
177-
Spacer(modifier = Modifier.height(8.dp))
178-
179-
LoadedList(
180-
modifier = Modifier.fillMaxSize(),
181-
listItems = listItems,
182-
onClick = onClickElement,
183-
)
184-
}
185-
}
189+
Text(
190+
modifier = Modifier.padding(horizontal = 16.dp),
191+
text = stringResource(R.string.action_interact_ui_element_choose_element_not_found_text),
192+
style = MaterialTheme.typography.bodyMedium,
193+
)
194+
195+
Spacer(modifier = Modifier.height(8.dp))
196+
197+
if (state is State.Data) {
198+
var interactionTypeExpanded by rememberSaveable { mutableStateOf(false) }
199+
200+
CheckBoxText(
201+
modifier = Modifier
202+
.fillMaxWidth()
203+
.padding(horizontal = 8.dp),
204+
text = stringResource(R.string.action_interact_ui_element_checkbox_additional_elements),
205+
isChecked = state.data.showAdditionalElements,
206+
onCheckedChange = onAdditionalElementsCheckedChange,
207+
)
208+
209+
Spacer(modifier = Modifier.height(8.dp))
210+
211+
KeyMapperDropdownMenu(
212+
modifier = Modifier.padding(horizontal = 16.dp),
213+
expanded = interactionTypeExpanded,
214+
onExpandedChange = { interactionTypeExpanded = it },
215+
label = { Text(stringResource(R.string.action_interact_ui_element_filter_interaction_type_dropdown)) },
216+
values = state.data.interactionTypes,
217+
selectedValue = state.data.selectedInteractionType,
218+
onValueChanged = onSelectInteractionType,
219+
)
220+
221+
Spacer(modifier = Modifier.height(8.dp))
222+
}
223+
}
224+
}
225+
226+
@Composable
227+
private fun ListSection(
228+
modifier: Modifier = Modifier,
229+
state: State<SelectUiElementState>,
230+
onClickElement: (Long) -> Unit,
231+
) {
232+
when (state) {
233+
State.Loading -> LoadingList(modifier = modifier.fillMaxSize())
234+
is State.Data -> {
235+
val listItems = state.data.listItems
236+
237+
Column(modifier = modifier) {
238+
if (listItems.isEmpty()) {
239+
EmptyList(
240+
modifier = Modifier
241+
.fillMaxSize()
242+
.padding(16.dp),
243+
)
244+
} else {
245+
LoadedList(
246+
modifier = Modifier.fillMaxSize(),
247+
listItems = listItems,
248+
onClick = onClickElement,
249+
)
186250
}
187251
}
188252
}
@@ -352,41 +416,74 @@ private fun Loading() {
352416
}
353417
}
354418

419+
private val listItems = listOf(
420+
UiElementListItemModel(
421+
id = 1L,
422+
nodeText = "Open Settings",
423+
nodeClassName = "android.widget.ImageButton",
424+
nodeViewResourceId = "menu_button",
425+
nodeUniqueId = "123456789",
426+
nodeTooltipHint = "Open menu",
427+
interactionTypesText = "Tap, Tap and hold, Scroll forward",
428+
interactionTypes = setOf(
429+
NodeInteractionType.CLICK,
430+
NodeInteractionType.LONG_CLICK,
431+
NodeInteractionType.SCROLL_FORWARD,
432+
),
433+
interacted = true,
434+
),
435+
)
436+
437+
private val loadedState = SelectUiElementState(
438+
listItems = listItems,
439+
interactionTypes = listOf(
440+
null to "Any",
441+
NodeInteractionType.CLICK to "Tap",
442+
NodeInteractionType.LONG_CLICK to "Tap and hold",
443+
),
444+
selectedInteractionType = null,
445+
showAdditionalElements = true,
446+
)
447+
355448
@Preview
356449
@Composable
357-
private fun Loaded() {
358-
val listItems = listOf(
359-
UiElementListItemModel(
360-
id = 1L,
361-
nodeText = "Open Settings",
362-
nodeClassName = "android.widget.ImageButton",
363-
nodeViewResourceId = "menu_button",
364-
nodeUniqueId = "123456789",
365-
nodeTooltipHint = "Open menu",
366-
interactionTypesText = "Tap, Tap and hold, Scroll forward",
367-
interactionTypes = setOf(
368-
NodeInteractionType.CLICK,
369-
NodeInteractionType.LONG_CLICK,
370-
NodeInteractionType.SCROLL_FORWARD,
371-
),
372-
interacted = true,
373-
),
374-
)
450+
private fun LoadedPortrait() {
451+
KeyMapperTheme {
452+
ChooseElementScreen(
453+
state = State.Data(loadedState),
454+
query = "Key Mapper",
455+
)
456+
}
457+
}
375458

376-
val state = SelectUiElementState(
377-
listItems = listItems,
378-
interactionTypes = listOf(
379-
null to "Any",
380-
NodeInteractionType.CLICK to "Tap",
381-
NodeInteractionType.LONG_CLICK to "Tap and hold",
382-
),
383-
selectedInteractionType = null,
384-
showAdditionalElements = true,
385-
)
459+
@Preview(widthDp = 800, heightDp = 300)
460+
@Composable
461+
private fun LoadedPhoneLandscape() {
462+
KeyMapperTheme {
463+
ChooseElementScreen(
464+
state = State.Data(loadedState),
465+
query = "Key Mapper",
466+
)
467+
}
468+
}
386469

470+
@Preview(device = Devices.TABLET)
471+
@Composable
472+
private fun LoadedTablet() {
473+
KeyMapperTheme {
474+
ChooseElementScreen(
475+
state = State.Data(loadedState),
476+
query = "Key Mapper",
477+
)
478+
}
479+
}
480+
481+
@Preview(device = Devices.NEXUS_7)
482+
@Composable
483+
private fun LoadedTabletVertical() {
387484
KeyMapperTheme {
388485
ChooseElementScreen(
389-
state = State.Data(state),
486+
state = State.Data(loadedState),
390487
query = "Key Mapper",
391488
)
392489
}

0 commit comments

Comments
 (0)