Skip to content

Commit 2f91be0

Browse files
committed
feat: multiple choice questions have clickable labels, added horizontal divider between questions (and all dividers in the app are now the same), add camera choice in settings
1 parent 9da19ad commit 2f91be0

File tree

9 files changed

+107
-19
lines changed

9 files changed

+107
-19
lines changed

pretixscan/composeApp/src/commonMain/composeResources/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,7 @@
224224
<string name="badge_printing_selected_printer_not_available">The selected printer is currently unavailable. Please
225225
check that the device is online and connected to the system.
226226
</string>
227+
<string name="settings_section_camera">Camera</string>
228+
<string name="settings_preferred_camera_label">Preferred camera</string>
229+
<string name="settings_camera_auto">Auto</string>
227230
</resources>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package eu.pretix.desktop.app.ui
2+
3+
import androidx.compose.material3.HorizontalDivider
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.ui.Modifier
6+
import androidx.compose.ui.graphics.Color
7+
import androidx.compose.ui.unit.dp
8+
9+
@Composable
10+
fun ListDivider(currentIndex: Int? = null, lastIndex: Int? = null) {
11+
if (lastIndex != null && currentIndex != null && currentIndex < lastIndex) {
12+
// show divider between rows except the last row
13+
HorizontalDivider(Modifier, thickness = 1.dp, color = Color.Gray)
14+
} else if (lastIndex == null && currentIndex == null) {
15+
// always show when no index is set
16+
HorizontalDivider(Modifier, thickness = 1.dp, color = Color.Gray)
17+
}
18+
}

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/scan/main/presentation/selectevent/SelectEventList.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import androidx.compose.foundation.lazy.rememberLazyListState
1010
import androidx.compose.foundation.rememberScrollbarAdapter
1111
import androidx.compose.foundation.selection.selectable
1212
import androidx.compose.foundation.selection.selectableGroup
13-
import androidx.compose.material.Divider
13+
import androidx.compose.material3.Divider
1414
import androidx.compose.material3.Checkbox
1515
import androidx.compose.material3.CircularProgressIndicator
16+
import androidx.compose.material3.HorizontalDivider
1617
import androidx.compose.material3.Text
1718
import androidx.compose.runtime.Composable
1819
import androidx.compose.runtime.LaunchedEffect
@@ -24,6 +25,7 @@ import androidx.compose.ui.graphics.Color
2425
import androidx.compose.ui.semantics.Role
2526
import androidx.compose.ui.text.font.FontWeight
2627
import androidx.compose.ui.unit.dp
28+
import eu.pretix.desktop.app.ui.ListDivider
2729
import eu.pretix.desktop.app.ui.SelectListRow
2830
import eu.pretix.libpretixsync.setup.RemoteEvent
2931
import eu.pretix.scan.tickets.presentation.formatDateForDisplay
@@ -137,9 +139,7 @@ fun SelectEventList(
137139
Text(dateText)
138140
}
139141
}
140-
if (index < list.lastIndex) {
141-
Divider(color = Color.Gray, thickness = 1.dp)
142-
}
142+
ListDivider(index, list.lastIndex)
143143
}
144144
}
145145

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/scan/main/presentation/selectlist/SelectCheckInList.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import androidx.compose.foundation.lazy.rememberLazyListState
1111
import androidx.compose.foundation.rememberScrollbarAdapter
1212
import androidx.compose.foundation.selection.selectable
1313
import androidx.compose.foundation.selection.selectableGroup
14-
import androidx.compose.material.Divider
14+
import androidx.compose.material3.Divider
1515
import androidx.compose.material3.Checkbox
1616
import androidx.compose.material3.CircularProgressIndicator
17+
import androidx.compose.material3.HorizontalDivider
1718
import androidx.compose.material3.Text
1819
import androidx.compose.runtime.Composable
1920
import androidx.compose.runtime.collectAsState
@@ -24,6 +25,7 @@ import androidx.compose.ui.graphics.Color
2425
import androidx.compose.ui.semantics.Role
2526
import androidx.compose.ui.text.font.FontWeight
2627
import androidx.compose.ui.unit.dp
28+
import eu.pretix.desktop.app.ui.ListDivider
2729
import eu.pretix.desktop.app.ui.SelectListRow
2830
import eu.pretix.libpretixsync.sqldelight.CheckInList
2931
import org.jetbrains.compose.resources.stringResource
@@ -105,9 +107,7 @@ fun SelectCheckInList(
105107
Text(item.name ?: "", fontWeight = FontWeight.Bold)
106108
}
107109
}
108-
if (index < list.lastIndex) {
109-
Divider(color = Color.Gray, thickness = 1.dp)
110-
}
110+
ListDivider(index, list.lastIndex)
111111
}
112112
}
113113

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/scan/settings/data/ConfigurableSettings.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ data class ConfigurableSettings(
1414
val offlineMode: Boolean = false,
1515
val uiReduceMotion: Boolean = false,
1616
val uiHideNames: Boolean = false,
17+
val cameras: List<String> = emptyList(),
18+
val preferredCamera: String? = null,
1719
)

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/scan/settings/presentation/SettingsScreen.kt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,29 @@ fun SettingsScreen(
240240
}
241241
}
242242

243+
item {
244+
Section(stringResource(Res.string.settings_section_camera)) {
245+
Setting {
246+
Column(
247+
horizontalAlignment = Alignment.Start
248+
) {
249+
Text(
250+
stringResource(Res.string.settings_preferred_camera_label)
251+
)
252+
FieldSpinner(
253+
selectedValue = form.preferredCamera,
254+
availableOptions = listOf(SelectableValue("-", stringResource(Res.string.settings_camera_auto))) + form.cameras.map { SelectableValue(it, it) },
255+
onSelect = {
256+
coroutineScope.launch {
257+
viewModel.setPreferredCamera(it?.value)
258+
}
259+
},
260+
)
261+
}
262+
}
263+
}
264+
}
265+
243266
item {
244267
Section(stringResource(Res.string.settings_label_about)) {
245268
Setting {
@@ -337,7 +360,7 @@ fun Section(heading: String, content: @Composable () -> Unit) {
337360
fontWeight = FontWeight.Medium
338361
)
339362
content()
340-
HorizontalDivider()
363+
ListDivider()
341364
}
342365
}
343366

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/scan/settings/presentation/SettingsViewModel.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,28 @@ package eu.pretix.scan.settings.presentation
22

33

44
import androidx.lifecycle.ViewModel
5+
import androidx.lifecycle.viewModelScope
56
import eu.pretix.desktop.app.sync.SyncRootService
67
import eu.pretix.desktop.app.ui.SelectableValue
78
import eu.pretix.desktop.cache.AppCache
89
import eu.pretix.desktop.cache.DataStoreConfigStore
910
import eu.pretix.desktop.cache.Version
11+
import eu.pretix.desktop.webcam.data.VideoSource
1012
import eu.pretix.scan.settings.data.ConfigurableSettings
1113
import eu.pretix.scan.settings.data.PrinterSource
14+
import kotlinx.coroutines.Dispatchers
1215
import kotlinx.coroutines.flow.MutableStateFlow
1316
import kotlinx.coroutines.flow.StateFlow
1417
import kotlinx.coroutines.flow.asStateFlow
18+
import kotlinx.coroutines.flow.collectLatest
1519
import kotlinx.coroutines.flow.update
20+
import kotlinx.coroutines.launch
1621

1722

1823
class SettingsViewModel(
1924
private val appConfig: DataStoreConfigStore,
2025
private val printerSource: PrinterSource,
26+
private val videoSource: VideoSource,
2127
private val appCache: AppCache,
2228
private val syncRootService: SyncRootService
2329
) : ViewModel() {
@@ -32,6 +38,15 @@ class SettingsViewModel(
3238
_uiState.update { SettingsUiState.Start }
3339
}
3440

41+
private fun loadCameras() {
42+
viewModelScope.launch(Dispatchers.IO) {
43+
videoSource.getAvailableWebcam().collectLatest { webcams ->
44+
val cameraNames = webcams.map { it.name }
45+
_form.update { it.copy(cameras = cameraNames) }
46+
}
47+
}
48+
}
49+
3550
suspend fun loadSettings() {
3651
val badgePrinterWasSelected = appConfig.printBadges && appConfig.badgePrinterName != null
3752
_form.value = _form.value.copy(
@@ -46,9 +61,10 @@ class SettingsViewModel(
4661
offlineMode = appConfig.offlineMode,
4762
uiReduceMotion = appConfig.uiReduceMotion,
4863
uiHideNames = appConfig.uiHideNames,
64+
preferredCamera = appConfig.preferredCameraName.takeIf { it != "-" },
4965
)
66+
loadCameras()
5067

51-
// check if printer setup is correct
5268
if (_form.value.printBadges && badgePrinterWasSelected && _form.value.badgePrinter == null) {
5369
_uiState.update { SettingsUiState.ErrorSelectedPrinterNotAvailable }
5470
}
@@ -119,6 +135,11 @@ class SettingsViewModel(
119135
loadSettings()
120136
}
121137

138+
suspend fun setPreferredCamera(name: String?) {
139+
appConfig.preferredCameraName = name ?: "-"
140+
loadSettings()
141+
}
142+
122143
fun logout() {
123144
syncRootService.skipFutureSyncs()
124145
appCache.reset()

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/scan/tickets/presentation/QuestionCheckbox.kt

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package eu.pretix.scan.tickets.presentation
22

33

4+
import androidx.compose.foundation.LocalIndication
45
import androidx.compose.foundation.layout.Row
6+
import androidx.compose.foundation.layout.padding
7+
import androidx.compose.foundation.selection.selectable
58
import androidx.compose.material3.Checkbox
69
import androidx.compose.material3.Text
710
import androidx.compose.runtime.Composable
811
import androidx.compose.ui.Alignment
912
import androidx.compose.ui.Modifier
13+
import androidx.compose.ui.semantics.Role
14+
import androidx.compose.ui.unit.dp
1015

1116

1217
@Composable
@@ -17,17 +22,27 @@ fun QuestionCheckbox(
1722
onSelect: (String?) -> Unit
1823
) {
1924
Row(
25+
modifier = modifier
26+
.padding(vertical = 4.dp)
27+
.selectable(
28+
selected = checked,
29+
onClick = {
30+
if (checked) {
31+
onSelect("False")
32+
} else {
33+
onSelect("True")
34+
}
35+
},
36+
indication = LocalIndication.current,
37+
interactionSource = null,
38+
role = Role.Checkbox
39+
),
2040
verticalAlignment = Alignment.CenterVertically,
2141
) {
2242
Checkbox(
2343
checked = checked,
24-
onCheckedChange = { updatedChecked ->
25-
if (updatedChecked) {
26-
onSelect("True")
27-
} else {
28-
onSelect("False")
29-
}
30-
}
44+
onCheckedChange = null,
45+
modifier = Modifier.padding(end = 4.dp)
3146
)
3247
Text(
3348
label

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/scan/tickets/presentation/QuestionsDialogView.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ import androidx.compose.foundation.focusable
66
import androidx.compose.foundation.layout.*
77
import androidx.compose.foundation.lazy.LazyColumn
88
import androidx.compose.foundation.lazy.items
9+
import androidx.compose.foundation.lazy.itemsIndexed
910
import androidx.compose.foundation.lazy.rememberLazyListState
1011
import androidx.compose.foundation.rememberScrollbarAdapter
1112
import androidx.compose.foundation.text.selection.SelectionContainer
1213
import androidx.compose.material.icons.Icons
1314
import androidx.compose.material.icons.filled.Person
15+
import androidx.compose.material3.Divider
16+
import androidx.compose.material3.HorizontalDivider
1417
import androidx.compose.material3.Icon
1518
import androidx.compose.material3.MaterialTheme
1619
import androidx.compose.material3.Text
@@ -19,6 +22,7 @@ import androidx.compose.ui.Alignment
1922
import androidx.compose.ui.Modifier
2023
import androidx.compose.ui.focus.FocusRequester
2124
import androidx.compose.ui.focus.focusRequester
25+
import androidx.compose.ui.graphics.BlendMode.Companion.Color
2226
import androidx.compose.ui.text.font.FontWeight
2327
import androidx.compose.ui.unit.dp
2428
import eu.pretix.desktop.app.ui.*
@@ -27,14 +31,14 @@ import eu.pretix.libpretixsync.db.Answer
2731
import eu.pretix.scan.tickets.data.ResultStateData
2832
import org.jetbrains.compose.resources.stringResource
2933
import org.jetbrains.compose.ui.tooling.preview.Preview
34+
import org.jetbrains.compose.ui.tooling.preview.PreviewParameter
3035
import org.koin.compose.viewmodel.koinViewModel
3136
import pretixscan.composeapp.generated.resources.Res
3237
import pretixscan.composeapp.generated.resources.cancel
3338
import pretixscan.composeapp.generated.resources.cont
3439
import pretixscan.composeapp.generated.resources.yes
3540

3641

37-
@Preview
3842
@Composable
3943
fun QuestionsDialogView(
4044
data: ResultStateData,
@@ -109,7 +113,7 @@ fun QuestionsDialogView(
109113
}
110114
}
111115
}
112-
items(form) { field ->
116+
itemsIndexed(form) { index, field ->
113117
SelectListRow {
114118
when (field.fieldType) {
115119
QuestionType.N -> {
@@ -332,7 +336,9 @@ fun QuestionsDialogView(
332336
}
333337
}
334338
}
339+
ListDivider(index, form.lastIndex)
335340
}
341+
336342
}
337343

338344
VerticalScrollbar(

0 commit comments

Comments
 (0)