Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,24 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedIconButton
import androidx.compose.material3.Text
Expand All @@ -57,6 +62,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
Expand All @@ -74,13 +80,23 @@ import io.github.chrisimx.scanbridge.uicomponents.settings.MoreInformationButton
import io.github.chrisimx.scanbridge.uicomponents.settings.UIntSetting
import io.github.chrisimx.scanbridge.uicomponents.settings.VersionComposable
import java.io.File
import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.koinInject
import scanbridge.composeui.generated.resources.Res
import scanbridge.composeui.generated.resources.debug_log_explanation
import scanbridge.composeui.generated.resources.disable_cert_checks_desc
import scanbridge.composeui.generated.resources.initial_scan_settings
import scanbridge.composeui.generated.resources.pdf_export_setting_info
import scanbridge.composeui.generated.resources.preferred_initial_scan_settings_setting_desc
import scanbridge.composeui.generated.resources.remember_scan_settings_desc
import scanbridge.composeui.generated.resources.timeout_info

@Composable
fun DisableCertChecksSetting(onInformationRequested: (Int) -> Unit, checked: Boolean, setChecked: (Boolean) -> Unit) {
fun DisableCertChecksSetting(onInformationRequested: (StringResource) -> Unit, checked: Boolean, setChecked: (Boolean) -> Unit) {
CheckboxSetting(
stringResource(R.string.disable_cert_checks),
R.string.disable_cert_checks_desc,
Res.string.disable_cert_checks_desc,
checked,
setChecked
) {
Expand All @@ -105,7 +121,7 @@ fun exportDebugLog(context: Context, debugLogService: DebugLogService, saveDebug
}

@Composable
fun DebugOptions(debugLog: Boolean, onInformationRequested: (Int) -> Unit, setWriteDebugLog: (Boolean) -> Unit) {
fun DebugOptions(debugLog: Boolean, onInformationRequested: (StringResource) -> Unit, setWriteDebugLog: (Boolean) -> Unit) {
val context = LocalContext.current
val debugLogService: DebugLogService = koinInject()

Expand Down Expand Up @@ -165,7 +181,7 @@ fun DebugOptions(debugLog: Boolean, onInformationRequested: (Int) -> Unit, setWr
}
) {
MoreInformationButton {
onInformationRequested(R.string.debug_log_explanation)
onInformationRequested(Res.string.debug_log_explanation)
}
}
}
Expand All @@ -182,22 +198,76 @@ fun DebugOptions(debugLog: Boolean, onInformationRequested: (Int) -> Unit, setWr
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun InitialScanSettingsAppSetting(
preferredInitialScanSettingsPanelVisible: Boolean,
setMenuVis: (Boolean) -> Unit,
scanSettingsUIStateHolder: ScanSettingsComposableStateHolder,
setHelpText: (StringResource) -> Unit
) {
Row(
modifier = Modifier
.padding(vertical = 10.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
OutlinedButton(
modifier = Modifier
.weight(1f, fill = false)
.padding(horizontal = 10.dp),
onClick = {
setMenuVis(true)
}
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Icon(
imageVector = Icons.Default.Edit,
contentDescription = "Edit"
)
Text(
text = stringResource(Res.string.initial_scan_settings)
)
}
}

MoreInformationButton {
setHelpText(Res.string.preferred_initial_scan_settings_setting_desc)
}
}

if (preferredInitialScanSettingsPanelVisible) {
val screenHeight = LocalWindowInfo.current.containerDpSize.height
ModalBottomSheet({ setMenuVis(false) }) {
ScanSettingsUI(
Modifier.heightIn(max = screenHeight * 0.8f),
scanSettingsUIStateHolder
)
}
}
}

@ExperimentalMaterial3Api
@Composable
fun AppSettingsScreen(innerPadding: PaddingValues) {
val vm = koinInject<AppSettingsViewModel>()

var information: Int? by remember {
var information: StringResource? by remember {
mutableStateOf(null)
}
val setInformationRequested = { it: Int -> information = it }
val setInformationRequested = { it: StringResource -> information = it }

val scrollState = rememberScrollState()

val disableCertChecks by vm.disableCertChecks.collectAsState()
val rememberScanSettings by vm.rememberScanSettings.collectAsState()
val writeDebugLogs by vm.writeDebugLogs.collectAsState()

val preferredInitialScanSettingsPanelVisible by vm.isPreferredInitialScanSettingsMenuVisible.collectAsState()

val defaultPdfExportChunkSize = vm.getDefaultPdfExportChunkSize()
val defaultScanningResponseTimeout = vm.getDefaultScanningResponseTimeout()

Expand Down Expand Up @@ -264,7 +334,7 @@ fun AppSettingsScreen(innerPadding: PaddingValues) {

CheckboxSetting(
stringResource(R.string.remember_scan_settings),
R.string.remember_scan_settings_desc,
Res.string.remember_scan_settings_desc,
rememberScanSettings,
vm::setRememberScanSettings
) {
Expand All @@ -276,7 +346,7 @@ fun AppSettingsScreen(innerPadding: PaddingValues) {
{ vm.getScanningResponseTimeout() },
defaultScanningResponseTimeout,
stringResource(R.string.timeout),
R.string.timeout_info,
Res.string.timeout_info,
setInformationRequested,
vm::setScanningResponseTimeout
)
Expand All @@ -286,12 +356,20 @@ fun AppSettingsScreen(innerPadding: PaddingValues) {
{ vm.getPdfExportChunkSize() },
defaultPdfExportChunkSize,
stringResource(R.string.pdf_export_max_pages_per_pdf),
R.string.pdf_export_setting_info,
Res.string.pdf_export_setting_info,
setInformationRequested,
vm::setPdfExportChunkSize,
min = 1u,
max = UInt.MAX_VALUE
)

// Preferred initial scan settings
InitialScanSettingsAppSetting(
preferredInitialScanSettingsPanelVisible,
vm::setPreferredInitialScanSettingsMenuVisibility,
vm.prefInitialScanSettingsUIStateHolder,
setInformationRequested
)
}

TitledCard(
Expand All @@ -308,7 +386,7 @@ fun AppSettingsScreen(innerPadding: PaddingValues) {
val currentInfo = information
if (currentInfo != null) {
SimpleTextDialog(
stringResource(currentInfo),
org.jetbrains.compose.resources.stringResource(currentInfo),
{ information = null }
)
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,30 @@ import android.app.Application
import android.content.Context
import coil3.ImageLoader
import coil3.network.ktor3.KtorNetworkFetcherFactory
import io.github.chrisimx.localization.JvmNumberFormatter
import io.github.chrisimx.scanbridge.adapters.KoinBasedScanningProtocolManager
import io.github.chrisimx.scanbridge.adapters.RoomBackedCustomScannerRepository
import io.github.chrisimx.scanbridge.appsettings.AppSettingsRepository
import io.github.chrisimx.scanbridge.appsettings.AppSettingsViewModel
import io.github.chrisimx.scanbridge.appsettings.RoomAppSettingsRepository
import io.github.chrisimx.scanbridge.buildinfo.BuildInfoProvider
import io.github.chrisimx.scanbridge.data.ui.ScanSettingsComposableStateHolder
import io.github.chrisimx.scanbridge.data.ui.ScanningScreenViewModel
import io.github.chrisimx.scanbridge.db.DefaultScanBridgeDbFactory
import io.github.chrisimx.scanbridge.db.ScanBridgeDb
import io.github.chrisimx.scanbridge.db.ScanBridgeDbBuilderFactory
import io.github.chrisimx.scanbridge.db.ScanBridgeDbFactory
import io.github.chrisimx.scanbridge.db.migrations.ROOM_MIGRATIONS
import io.github.chrisimx.scanbridge.infrastructure.KmLogScanBridgeLoggerFactory
import io.github.chrisimx.scanbridge.initialscansettings.DefaultInitialScanSettingsProvider
import io.github.chrisimx.scanbridge.initialscansettings.InitialScanSettingsProvider
import io.github.chrisimx.scanbridge.localization.NumberFormatter
import io.github.chrisimx.scanbridge.migrations.MigrationExecutor
import io.github.chrisimx.scanbridge.migrations.RoomBackedMigrationExecutor
import io.github.chrisimx.scanbridge.migrations.ds2room.DATASTORE_TO_ROOM_MIGRATION_DATA_SOURCES
import io.github.chrisimx.scanbridge.migrations.migrationsModule
import io.github.chrisimx.scanbridge.model.HttpClientConfig
import io.github.chrisimx.scanbridge.ports.CustomScannerRepository
import io.github.chrisimx.scanbridge.ports.HttpClientFactory
import io.github.chrisimx.scanbridge.ports.InitialScanSettingsProvider
import io.github.chrisimx.scanbridge.ports.LocaleProvider
import io.github.chrisimx.scanbridge.ports.MdnsDiscoverService
import io.github.chrisimx.scanbridge.ports.ScanBridgeLoggerFactory
Expand Down Expand Up @@ -133,6 +135,8 @@ val appModule = module {

viewModel<AppSettingsViewModel>()

single<JvmNumberFormatter>() bind NumberFormatter::class

includes(SCAN_PROTOCOLS, ROOM_MIGRATIONS, DATASTORE_TO_ROOM_MIGRATION_DATA_SOURCES)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,22 @@ import io.github.chrisimx.anyscan.CommonScanSettings
import io.github.chrisimx.anyscan.LengthUnit
import io.github.chrisimx.anyscan.ScanSettingParam
import io.github.chrisimx.anyscan.ScannerConcept
import io.github.chrisimx.scanbridge.data.ui.ScanSettingsComposableStateHolder
import io.github.chrisimx.scanbridge.data.ui.ScanSettingsLengthUnit
import io.github.chrisimx.scanbridge.model.UIInputSourceType
import io.github.chrisimx.scanbridge.uicomponents.SelectionButtonRow
import io.github.chrisimx.scanbridge.uicomponents.SelectionCard
import io.github.chrisimx.scanbridge.uicomponents.SizeBasedConditionalView
import io.github.chrisimx.scanbridge.uicomponents.ValidatedDimensionsTextEdit
import io.github.chrisimx.scanbridge.util.UIInputSourceType
import io.github.chrisimx.scanbridge.util.toLocalizedName
import io.github.chrisimx.scanbridge.util.toReadableString

@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ScanSettingsUI(modifier: Modifier, scanSettingsStateHolder: ScanSettingsComposableStateHolder) {
val vmData by scanSettingsStateHolder.uiState.collectAsState()

val duplexCurrentlyAvailable by scanSettingsStateHolder.duplexSettingAvailable.collectAsState()

val inputSourceOptions by scanSettingsStateHolder.inputSourceOptions.collectAsState()

val userUnitEnum by scanSettingsStateHolder.lengthUnit.collectAsState(ScanSettingsLengthUnit.MILLIMETER)
val userUnitEnum by scanSettingsStateHolder.userLengthUnit.collectAsState(ScanSettingsLengthUnit.MILLIMETER)

val userUnitString = when (userUnitEnum) {
ScanSettingsLengthUnit.INCH -> stringResource(R.string.inches)
Expand Down Expand Up @@ -146,6 +142,8 @@ private fun RegionParameterDisplay(
val widthValidationResult by scanSettingsStateHolder.validationResultWidth.collectAsState()
val heightValidationResult by scanSettingsStateHolder.validationResultHeight.collectAsState()

val currentVmData = vmData ?: return

OutlinedCard(
modifier = Modifier
.fillMaxWidth()
Expand All @@ -168,7 +166,7 @@ private fun RegionParameterDisplay(
scanSettingsStateHolder.setFormat(paperFormat)
},
label = { Text(paperFormat.name) },
selected = !vmData.customMenuEnabled && !vmData.maximumSize &&
selected = !currentVmData.customMenuEnabled && !currentVmData.maximumSize &&
currentScanRegion?.value?.width?.equalsLength(paperFormat.width) == true &&
currentScanRegion?.value?.height?.equalsLength(paperFormat.height) == true
)
Expand All @@ -179,18 +177,18 @@ private fun RegionParameterDisplay(
},
label = { Text(stringResource(R.string.maximum_size)) },
selected =
vmData.maximumSize && !vmData.customMenuEnabled
currentVmData.maximumSize && !currentVmData.customMenuEnabled
)
InputChip(
selected = vmData.customMenuEnabled,
selected = currentVmData.customMenuEnabled,
onClick = { scanSettingsStateHolder.setCustomMenuEnabled(true) },
label = { Text(stringResource(R.string.custom)) }
)
}
AnimatedVisibility(vmData.customMenuEnabled) {
AnimatedVisibility(currentVmData.customMenuEnabled) {
Row(horizontalArrangement = Arrangement.SpaceEvenly) {
ValidatedDimensionsTextEdit(
vmData.widthString,
currentVmData.widthString,
modifier = Modifier
.weight(1f)
.padding(end = 10.dp),
Expand All @@ -203,7 +201,7 @@ private fun RegionParameterDisplay(
widthValidationResult
)
ValidatedDimensionsTextEdit(
vmData.heightString,
currentVmData.heightString,
modifier = Modifier
.weight(1f)
.padding(start = 10.dp),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ import coil3.compose.AsyncImage
import io.github.chrisimx.scanbridge.data.ui.ScanningScreenViewModel
import io.github.chrisimx.scanbridge.db.entities.ScannedPage
import io.github.chrisimx.scanbridge.model.ScannerHandle
import io.github.chrisimx.scanbridge.model.toUIInputSourceType
import io.github.chrisimx.scanbridge.services.ScanJobEvent
import io.github.chrisimx.scanbridge.uicomponents.ExportSettingsPopup
import io.github.chrisimx.scanbridge.uicomponents.FullScreenError
Expand All @@ -108,7 +109,6 @@ import io.github.chrisimx.scanbridge.util.clearAndNavigateTo
import io.github.chrisimx.scanbridge.util.snackBarError
import io.github.chrisimx.scanbridge.util.snackbarErrorRetrievingPage
import io.github.chrisimx.scanbridge.util.toReadableString
import io.github.chrisimx.scanbridge.util.toUIInputSourceType
import java.io.File
import kotlin.uuid.Uuid
import kotlinx.coroutines.CoroutineScope
Expand Down
Loading
Loading