removed batchmode from personal usecase

update ticketing and events view
This commit is contained in:
Hadrian Burkhardt
2026-03-03 14:13:25 +01:00
parent fb94b7214a
commit 3d7620954f
12 changed files with 493 additions and 128 deletions
@@ -2,8 +2,10 @@ package com.clean.scanner.settings
import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.preferencesDataStore
import com.clean.scanner.ui.UseCaseView
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
@@ -14,6 +16,7 @@ class SettingsRepository(private val context: Context) {
val historyEnabled = booleanPreferencesKey("history_enabled")
val warningsEnabled = booleanPreferencesKey("warnings_enabled")
val scanFeedbackEnabled = booleanPreferencesKey("scan_feedback_enabled")
val useCaseView = stringPreferencesKey("use_case_view")
}
val historyEnabled: Flow<Boolean> = context.dataStore.data.map { prefs ->
@@ -28,6 +31,10 @@ class SettingsRepository(private val context: Context) {
prefs[Keys.scanFeedbackEnabled] ?: true
}
val useCaseView: Flow<UseCaseView> = context.dataStore.data.map { prefs ->
UseCaseView.fromStorageKey(prefs[Keys.useCaseView])
}
suspend fun setHistoryEnabled(enabled: Boolean) {
context.dataStore.edit { it[Keys.historyEnabled] = enabled }
}
@@ -39,4 +46,8 @@ class SettingsRepository(private val context: Context) {
suspend fun setScanFeedbackEnabled(enabled: Boolean) {
context.dataStore.edit { it[Keys.scanFeedbackEnabled] = enabled }
}
suspend fun setUseCaseView(useCaseView: UseCaseView) {
context.dataStore.edit { it[Keys.useCaseView] = useCaseView.storageKey }
}
}
@@ -16,6 +16,7 @@ data class AppUiState(
val historyEnabled: Boolean = false,
val warningsEnabled: Boolean = true,
val scanFeedbackEnabled: Boolean = true,
val useCaseView: UseCaseView = UseCaseView.default,
val history: List<ScanRecord> = emptyList(),
val searchQuery: String = ""
)
@@ -24,19 +25,39 @@ class AppViewModel(
private val container: AppContainer
) : ViewModel() {
private data class SettingsState(
val historyEnabled: Boolean,
val warningsEnabled: Boolean,
val scanFeedbackEnabled: Boolean,
val useCaseView: UseCaseView
)
private val query = MutableStateFlow("")
val uiState: StateFlow<AppUiState> = combine(
private val settingsState = combine(
container.settingsRepository.historyEnabled,
container.settingsRepository.warningsEnabled,
container.settingsRepository.scanFeedbackEnabled,
container.scanRepository.observeHistory(),
query
) { historyEnabled, warningsEnabled, scanFeedbackEnabled, history, q ->
AppUiState(
container.settingsRepository.useCaseView
) { historyEnabled, warningsEnabled, scanFeedbackEnabled, useCaseView ->
SettingsState(
historyEnabled = historyEnabled,
warningsEnabled = warningsEnabled,
scanFeedbackEnabled = scanFeedbackEnabled,
useCaseView = useCaseView
)
}
val uiState: StateFlow<AppUiState> = combine(
settingsState,
container.scanRepository.observeHistory(),
query
) { settings, history, q ->
AppUiState(
historyEnabled = settings.historyEnabled,
warningsEnabled = settings.warningsEnabled,
scanFeedbackEnabled = settings.scanFeedbackEnabled,
useCaseView = settings.useCaseView,
history = if (q.isBlank()) history else history.filter {
it.content.contains(q, ignoreCase = true) || it.type.contains(q, ignoreCase = true)
},
@@ -69,6 +90,12 @@ class AppViewModel(
}
}
fun setUseCaseView(useCaseView: UseCaseView) {
viewModelScope.launch {
container.settingsRepository.setUseCaseView(useCaseView)
}
}
fun deleteHistoryItem(id: Long) {
viewModelScope.launch {
container.scanRepository.deleteById(id)
@@ -74,6 +74,7 @@ fun CleanScannerAppRoot(container: AppContainer) {
scanFeedbackNonce = scannerState.scanFeedbackNonce,
warningsEnabled = appState.warningsEnabled,
scanFeedbackEnabled = appState.scanFeedbackEnabled,
useCaseView = appState.useCaseView,
onScan = scannerViewModel::onScan,
onScanAgain = scannerViewModel::resumeScanning,
onBatchModeChange = scannerViewModel::setBatchMode,
@@ -84,6 +85,7 @@ fun CleanScannerAppRoot(container: AppContainer) {
RootTab.History -> HistoryScreen(
query = appState.searchQuery,
history = appState.history,
useCaseView = appState.useCaseView,
onQueryChange = appViewModel::setQuery,
onDelete = appViewModel::deleteHistoryItem,
onClearAll = appViewModel::clearHistory
@@ -93,9 +95,11 @@ fun CleanScannerAppRoot(container: AppContainer) {
historyEnabled = appState.historyEnabled,
warningsEnabled = appState.warningsEnabled,
scanFeedbackEnabled = appState.scanFeedbackEnabled,
selectedUseCaseView = appState.useCaseView,
onHistoryToggle = appViewModel::setHistoryEnabled,
onWarningsToggle = appViewModel::setWarningsEnabled,
onScanFeedbackToggle = appViewModel::setScanFeedbackEnabled
onScanFeedbackToggle = appViewModel::setScanFeedbackEnabled,
onUseCaseViewSelected = appViewModel::setUseCaseView
)
}
}
@@ -0,0 +1,174 @@
package com.clean.scanner.ui
import com.clean.scanner.R
enum class UseCaseView(
val storageKey: String,
val titleRes: Int
) {
EverydayPersonal(
storageKey = "everyday_personal",
titleRes = R.string.use_case_everyday_personal
),
EventTicketing(
storageKey = "event_ticketing",
titleRes = R.string.use_case_event_ticketing
),
InventoryOperations(
storageKey = "inventory_operations",
titleRes = R.string.use_case_inventory_operations
),
FieldWorkServiceTeams(
storageKey = "field_work_service_teams",
titleRes = R.string.use_case_field_work
),
OfficeAdmin(
storageKey = "office_admin",
titleRes = R.string.use_case_office_admin
),
CommunicationShortcuts(
storageKey = "communication_shortcuts",
titleRes = R.string.use_case_communication_shortcuts
),
SecurityBrowsing(
storageKey = "security_browsing",
titleRes = R.string.use_case_security_browsing
),
OfflineLowConnectivity(
storageKey = "offline_low_connectivity",
titleRes = R.string.use_case_offline_low_connectivity
),
AccessibilitySpeed(
storageKey = "accessibility_speed",
titleRes = R.string.use_case_accessibility_speed
),
TeamHandoverTransfer(
storageKey = "team_handover_transfer",
titleRes = R.string.use_case_team_handover_transfer
);
companion object {
val default = EverydayPersonal
fun fromStorageKey(value: String?): UseCaseView {
return entries.firstOrNull { it.storageKey == value } ?: default
}
}
}
data class UseCaseCapabilities(
val allowScanFromImage: Boolean = true,
val allowBatchMode: Boolean = false,
val allowCopy: Boolean = true,
val allowShare: Boolean = true,
val allowOpenUrl: Boolean = true,
val allowAddContact: Boolean = false,
val allowDialPhone: Boolean = false,
val allowSendSms: Boolean = false,
val allowSendEmail: Boolean = false,
val allowOpenWifiSettings: Boolean = false,
val allowAddCalendarEvent: Boolean = false,
val allowHistoryExport: Boolean = false,
val allowBatchShare: Boolean = true
)
fun UseCaseView.capabilities(): UseCaseCapabilities {
return when (this) {
UseCaseView.EverydayPersonal -> UseCaseCapabilities(
allowScanFromImage = true,
allowBatchMode = false,
allowCopy = true,
allowShare = true,
allowOpenUrl = true
)
UseCaseView.EventTicketing -> UseCaseCapabilities(
allowScanFromImage = false,
allowBatchMode = true,
allowCopy = true,
allowShare = true,
allowOpenUrl = false,
allowBatchShare = true
)
UseCaseView.InventoryOperations -> UseCaseCapabilities(
allowScanFromImage = true,
allowBatchMode = true,
allowCopy = true,
allowShare = true,
allowOpenUrl = false,
allowHistoryExport = true,
allowBatchShare = true
)
UseCaseView.FieldWorkServiceTeams -> UseCaseCapabilities(
allowScanFromImage = true,
allowBatchMode = true,
allowCopy = true,
allowShare = true,
allowOpenUrl = true,
allowHistoryExport = true,
allowBatchShare = true
)
UseCaseView.OfficeAdmin -> UseCaseCapabilities(
allowScanFromImage = true,
allowBatchMode = false,
allowCopy = true,
allowShare = true,
allowOpenUrl = true,
allowAddContact = true,
allowDialPhone = true,
allowSendSms = true,
allowSendEmail = true,
allowOpenWifiSettings = true,
allowAddCalendarEvent = true
)
UseCaseView.CommunicationShortcuts -> UseCaseCapabilities(
allowScanFromImage = true,
allowBatchMode = false,
allowCopy = true,
allowShare = true,
allowOpenUrl = false,
allowDialPhone = true,
allowSendSms = true,
allowSendEmail = true
)
UseCaseView.SecurityBrowsing -> UseCaseCapabilities(
allowScanFromImage = true,
allowBatchMode = false,
allowCopy = true,
allowShare = true,
allowOpenUrl = true
)
UseCaseView.OfflineLowConnectivity -> UseCaseCapabilities(
allowScanFromImage = true,
allowBatchMode = true,
allowCopy = true,
allowShare = true,
allowOpenUrl = false,
allowBatchShare = true
)
UseCaseView.AccessibilitySpeed -> UseCaseCapabilities(
allowScanFromImage = true,
allowBatchMode = false,
allowCopy = true,
allowShare = true,
allowOpenUrl = true
)
UseCaseView.TeamHandoverTransfer -> UseCaseCapabilities(
allowScanFromImage = true,
allowBatchMode = true,
allowCopy = true,
allowShare = true,
allowOpenUrl = false,
allowHistoryExport = true,
allowBatchShare = true
)
}
}
@@ -26,6 +26,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.clean.scanner.R
import com.clean.scanner.domain.ScanRecord
import com.clean.scanner.ui.UseCaseView
import com.clean.scanner.ui.capabilities
import com.clean.scanner.util.HistoryExportFormatter
import com.clean.scanner.util.Intents
import java.text.DateFormat
@@ -35,11 +37,13 @@ import java.util.Date
fun HistoryScreen(
query: String,
history: List<ScanRecord>,
useCaseView: UseCaseView,
onQueryChange: (String) -> Unit,
onDelete: (Long) -> Unit,
onClearAll: () -> Unit
) {
val context = LocalContext.current
val capabilities = useCaseView.capabilities()
val showDeleteAll = remember { mutableStateOf(false) }
val selectedItem = remember { mutableStateOf<ScanRecord?>(null) }
@@ -90,32 +94,34 @@ fun HistoryScreen(
)
Row(modifier = Modifier.fillMaxWidth()) {
TextButton(
onClick = {
val exportText = HistoryExportFormatter.formatText(history)
Intents.shareContent(context, exportText, "text/plain")
},
enabled = history.isNotEmpty()
) {
Text(stringResource(R.string.share_txt))
}
TextButton(
onClick = {
val exportCsv = HistoryExportFormatter.formatCsv(history)
Intents.shareContent(context, exportCsv, "text/csv")
},
enabled = history.isNotEmpty()
) {
Text(stringResource(R.string.share_csv))
}
TextButton(
onClick = {
val exportJson = HistoryExportFormatter.formatJson(history)
Intents.shareContent(context, exportJson, "application/json")
},
enabled = history.isNotEmpty()
) {
Text(stringResource(R.string.share_json))
if (capabilities.allowHistoryExport) {
TextButton(
onClick = {
val exportText = HistoryExportFormatter.formatText(history)
Intents.shareContent(context, exportText, "text/plain")
},
enabled = history.isNotEmpty()
) {
Text(stringResource(R.string.share_txt))
}
TextButton(
onClick = {
val exportCsv = HistoryExportFormatter.formatCsv(history)
Intents.shareContent(context, exportCsv, "text/csv")
},
enabled = history.isNotEmpty()
) {
Text(stringResource(R.string.share_csv))
}
TextButton(
onClick = {
val exportJson = HistoryExportFormatter.formatJson(history)
Intents.shareContent(context, exportJson, "application/json")
},
enabled = history.isNotEmpty()
) {
Text(stringResource(R.string.share_json))
}
}
TextButton(onClick = { showDeleteAll.value = true }) {
Text(stringResource(R.string.delete_all))
@@ -75,7 +75,8 @@ internal fun OverlayIconToggle(
@Composable
internal fun BatchResultsPanel(
results: List<BatchScanRecord>,
onClear: () -> Unit
onClear: () -> Unit,
allowShare: Boolean
) {
val context = LocalContext.current
val timeFormat = remember { DateFormat.getTimeInstance(DateFormat.SHORT) }
@@ -125,12 +126,14 @@ internal fun BatchResultsPanel(
tint = Color.White
)
}
IconButton(onClick = { Intents.shareText(context, item.result.content) }) {
Icon(
imageVector = Icons.Default.Share,
contentDescription = stringResource(R.string.share),
tint = Color.White
)
if (allowShare) {
IconButton(onClick = { Intents.shareText(context, item.result.content) }) {
Icon(
imageVector = Icons.Default.Share,
contentDescription = stringResource(R.string.share),
tint = Color.White
)
}
}
}
}
@@ -139,11 +142,13 @@ internal fun BatchResultsPanel(
TextButton(onClick = onClear, enabled = results.isNotEmpty()) {
Text(stringResource(R.string.clear_batch))
}
TextButton(
onClick = { Intents.shareText(context, buildBatchExport(results)) },
enabled = results.isNotEmpty()
) {
Text(stringResource(R.string.share_batch))
if (allowShare) {
TextButton(
onClick = { Intents.shareText(context, buildBatchExport(results)) },
enabled = results.isNotEmpty()
) {
Text(stringResource(R.string.share_batch))
}
}
}
}
@@ -1,5 +1,6 @@
package com.clean.scanner.ui.screens
import androidx.compose.foundation.clickable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -21,6 +22,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.clean.scanner.domain.ScanResult
@@ -38,6 +40,7 @@ private data class ResultField(
@Composable
internal fun ResultVisualCard(
result: ScanResult,
onOpenUrl: ((String) -> Unit)? = null,
modifier: Modifier = Modifier
) {
val contact = remember(result.content) { ScanContentParsers.parseContact(result.content) }
@@ -94,9 +97,19 @@ internal fun ResultVisualCard(
style = MaterialTheme.typography.labelMedium,
color = Color(0xFF4F6277)
)
val isClickableUrl = result.type == "URL" &&
field.label == "Link" &&
onOpenUrl != null
Text(
text = field.value,
style = MaterialTheme.typography.bodyMedium,
color = if (isClickableUrl) Color(0xFF1D4ED8) else Color.Unspecified,
textDecoration = if (isClickableUrl) TextDecoration.Underline else null,
modifier = if (isClickableUrl) {
Modifier.clickable { onOpenUrl(field.value) }
} else {
Modifier
},
maxLines = 3,
overflow = TextOverflow.Ellipsis
)
@@ -75,7 +75,9 @@ import com.clean.scanner.data.scanner.DetectionBox
import com.clean.scanner.data.scanner.DetectionPoint
import com.clean.scanner.domain.ScanResult
import com.clean.scanner.ui.BatchScanRecord
import com.clean.scanner.ui.UseCaseView
import com.clean.scanner.ui.components.CameraPreview
import com.clean.scanner.ui.capabilities
import com.clean.scanner.util.ClipboardUtil
import com.clean.scanner.util.Intents
import com.clean.scanner.util.ScanContentParsers
@@ -103,6 +105,7 @@ fun ScannerScreen(
scanFeedbackNonce: Int,
warningsEnabled: Boolean,
scanFeedbackEnabled: Boolean,
useCaseView: UseCaseView,
onScan: (ScanResult) -> Unit,
onScanAgain: () -> Unit,
onBatchModeChange: (Boolean) -> Unit,
@@ -111,9 +114,26 @@ fun ScannerScreen(
) {
val context = LocalContext.current
val haptic = LocalHapticFeedback.current
val capabilities = remember(useCaseView) { useCaseView.capabilities() }
val showBatchModeToggle = remember(useCaseView) {
when (useCaseView) {
UseCaseView.EventTicketing,
UseCaseView.InventoryOperations,
UseCaseView.FieldWorkServiceTeams,
UseCaseView.OfflineLowConnectivity,
UseCaseView.TeamHandoverTransfer -> true
else -> false
}
}
val duplicateSnackbarHostState = remember { SnackbarHostState() }
val toneGenerator = remember { ToneGenerator(AudioManager.STREAM_NOTIFICATION, 70) }
LaunchedEffect(showBatchModeToggle, batchMode) {
if (!showBatchModeToggle && batchMode) {
onBatchModeChange(false)
}
}
var cameraGranted by remember {
mutableStateOf(
ContextCompat.checkSelfPermission(
@@ -382,22 +402,38 @@ fun ScannerScreen(
.padding(horizontal = 14.dp, vertical = 8.dp)
)
IconButton(
onClick = { imagePicker.launch("image/*") },
if (capabilities.allowScanFromImage) {
IconButton(
onClick = { imagePicker.launch("image/*") },
modifier = Modifier
.align(Alignment.TopEnd)
.padding(top = 12.dp, end = 12.dp)
.background(
color = Color.Black.copy(alpha = 0.35f),
shape = RoundedCornerShape(14.dp)
)
) {
Icon(
painter = painterResource(id = android.R.drawable.ic_menu_gallery),
contentDescription = stringResource(R.string.scan_from_image),
tint = Color.White
)
}
}
Text(
text = stringResource(useCaseView.titleRes),
color = Color.White,
textAlign = TextAlign.Center,
modifier = Modifier
.align(Alignment.TopEnd)
.padding(top = 12.dp, end = 12.dp)
.align(Alignment.TopCenter)
.padding(top = 16.dp, start = 64.dp, end = 64.dp)
.background(
color = Color.Black.copy(alpha = 0.35f),
color = Color.Black.copy(alpha = 0.4f),
shape = RoundedCornerShape(14.dp)
)
) {
Icon(
painter = painterResource(id = android.R.drawable.ic_menu_gallery),
contentDescription = stringResource(R.string.scan_from_image),
tint = Color.White
)
}
.padding(horizontal = 12.dp, vertical = 6.dp)
)
Column(
modifier = Modifier
@@ -415,20 +451,23 @@ fun ScannerScreen(
showLabel = false
)
}
OverlayIconToggle(
checked = batchMode,
onCheckedChange = onBatchModeChange,
label = stringResource(R.string.batch_mode),
checkedImageVector = Icons.Default.ViewModule,
uncheckedImageVector = Icons.AutoMirrored.Filled.ViewList
)
if (showBatchModeToggle) {
OverlayIconToggle(
checked = batchMode,
onCheckedChange = onBatchModeChange,
label = stringResource(R.string.batch_mode),
checkedImageVector = Icons.Default.ViewModule,
uncheckedImageVector = Icons.AutoMirrored.Filled.ViewList
)
}
}
if (batchMode) {
if (batchMode && showBatchModeToggle) {
Box(modifier = Modifier.align(Alignment.BottomCenter)) {
BatchResultsPanel(
results = batchResults,
onClear = onClearBatchResults
onClear = onClearBatchResults,
allowShare = capabilities.allowBatchShare
)
}
}
@@ -470,91 +509,106 @@ fun ScannerScreen(
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
if (parsedContact == null && lastResult.type != "WiFi") {
Text(text = "${stringResource(R.string.content_type)}: ${lastResult.type}")
}
ResultVisualCard(result = lastResult)
Row(
modifier = Modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState()),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
if (parsedContact != null) {
IconButton(onClick = {
Intents.addContact(context, parsedContact, lastResult.content)
}) {
Icon(
imageVector = Icons.Default.PersonAdd,
contentDescription = stringResource(R.string.add_contact)
)
ResultVisualCard(
result = lastResult,
onOpenUrl = { url ->
val risk = UrlRiskScorer.score(url)
val risky = warningsEnabled && risk.score >= 3
if (risky) {
pendingOpenUrl = url
showRiskWarning = true
} else {
Intents.openUrl(context, url)
}
}
IconButton(onClick = { ClipboardUtil.copy(context, lastResult.content) }) {
Icon(
imageVector = Icons.Default.ContentCopy,
contentDescription = stringResource(R.string.copy)
)
}
if (lastResult.type == "URL") {
Button(onClick = {
val risk = UrlRiskScorer.score(lastResult.content)
val risky = warningsEnabled && risk.score >= 3
if (risky) {
pendingOpenUrl = lastResult.content
showRiskWarning = true
} else {
Intents.openUrl(context, lastResult.content)
)
val hasQuickActions = capabilities.allowCopy ||
capabilities.allowShare ||
(capabilities.allowAddContact && parsedContact != null)
if (hasQuickActions) {
Row(
modifier = Modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState()),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
if (capabilities.allowAddContact && parsedContact != null) {
IconButton(onClick = {
Intents.addContact(context, parsedContact, lastResult.content)
}) {
Icon(
imageVector = Icons.Default.PersonAdd,
contentDescription = stringResource(R.string.add_contact)
)
}
}
if (capabilities.allowCopy) {
IconButton(onClick = { ClipboardUtil.copy(context, lastResult.content) }) {
Icon(
imageVector = Icons.Default.ContentCopy,
contentDescription = stringResource(R.string.copy)
)
}
}
if (capabilities.allowShare) {
IconButton(onClick = { Intents.shareText(context, lastResult.content) }) {
Icon(
imageVector = Icons.Default.Share,
contentDescription = stringResource(R.string.share)
)
}
}) {
Text(stringResource(R.string.open))
}
}
IconButton(onClick = { Intents.shareText(context, lastResult.content) }) {
Icon(
imageVector = Icons.Default.Share,
contentDescription = stringResource(R.string.share)
)
}
}
when (lastResult.type) {
"Phone" -> {
Button(onClick = {
Intents.dialPhone(context, ScanContentParsers.extractPhoneNumber(lastResult.content))
}) {
Text(stringResource(R.string.call_number))
if (capabilities.allowDialPhone) {
Button(onClick = {
Intents.dialPhone(context, ScanContentParsers.extractPhoneNumber(lastResult.content))
}) {
Text(stringResource(R.string.call_number))
}
}
}
"SMS" -> {
Button(onClick = {
val smsData = ScanContentParsers.parseSms(lastResult.content)
Intents.sendSms(context, smsData.first, smsData.second)
}) {
Text(stringResource(R.string.send_sms))
if (capabilities.allowSendSms) {
Button(onClick = {
val smsData = ScanContentParsers.parseSms(lastResult.content)
Intents.sendSms(context, smsData.first, smsData.second)
}) {
Text(stringResource(R.string.send_sms))
}
}
}
"Email" -> {
Button(onClick = {
Intents.sendEmail(context, ScanContentParsers.extractEmail(lastResult.content), null)
}) {
Text(stringResource(R.string.send_email))
if (capabilities.allowSendEmail) {
Button(onClick = {
Intents.sendEmail(context, ScanContentParsers.extractEmail(lastResult.content), null)
}) {
Text(stringResource(R.string.send_email))
}
}
}
"WiFi" -> {
Button(onClick = { Intents.openWifiSettings(context) }) {
Text(stringResource(R.string.open_wifi_settings))
if (capabilities.allowOpenWifiSettings) {
Button(onClick = { Intents.openWifiSettings(context) }) {
Text(stringResource(R.string.open_wifi_settings))
}
}
}
"Calendar" -> {
Button(onClick = {
Intents.addCalendarEvent(context, parsedEvent, lastResult.content)
}) {
Text(stringResource(R.string.add_calendar_event))
if (capabilities.allowAddCalendarEvent) {
Button(onClick = {
Intents.addCalendarEvent(context, parsedEvent, lastResult.content)
}) {
Text(stringResource(R.string.add_calendar_event))
}
}
}
}
@@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog
@@ -20,6 +21,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.clean.scanner.R
import com.clean.scanner.ui.UseCaseView
import com.clean.scanner.util.Intents
@Composable
@@ -27,13 +29,16 @@ fun SettingsScreen(
historyEnabled: Boolean,
warningsEnabled: Boolean,
scanFeedbackEnabled: Boolean,
selectedUseCaseView: UseCaseView,
onHistoryToggle: (Boolean, Boolean) -> Unit,
onWarningsToggle: (Boolean) -> Unit,
onScanFeedbackToggle: (Boolean) -> Unit
onScanFeedbackToggle: (Boolean) -> Unit,
onUseCaseViewSelected: (UseCaseView) -> Unit
) {
val context = LocalContext.current
val showDeleteConfirm = remember { mutableStateOf(false) }
val showFeatureRequestForm = remember { mutableStateOf(false) }
val showUseCasePicker = remember { mutableStateOf(false) }
val requesterNeed = remember { mutableStateOf("") }
if (showDeleteConfirm.value) {
@@ -101,6 +106,34 @@ fun SettingsScreen(
)
}
if (showUseCasePicker.value) {
AlertDialog(
onDismissRequest = { showUseCasePicker.value = false },
title = { Text(stringResource(R.string.select_use_case_view)) },
text = {
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
UseCaseView.entries.forEach { candidate ->
TextButton(
onClick = {
onUseCaseViewSelected(candidate)
showUseCasePicker.value = false
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = stringResource(candidate.titleRes))
}
}
}
},
confirmButton = {},
dismissButton = {
TextButton(onClick = { showUseCasePicker.value = false }) {
Text(stringResource(R.string.cancel))
}
}
)
}
Column(
modifier = Modifier
.fillMaxSize()
@@ -129,6 +162,14 @@ fun SettingsScreen(
Text(text = stringResource(R.string.scan_feedback))
Switch(checked = scanFeedbackEnabled, onCheckedChange = onScanFeedbackToggle)
Spacer(modifier = Modifier.height(16.dp))
Text(text = stringResource(R.string.active_use_case_view))
Text(text = stringResource(selectedUseCaseView.titleRes))
TextButton(onClick = { showUseCasePicker.value = true }) {
Text(stringResource(R.string.select_use_case_view))
}
Spacer(modifier = Modifier.height(24.dp))
Text(text = stringResource(R.string.about))
Text(text = stringResource(R.string.version))