Skip to content

Commit 5aedbbf

Browse files
kkostovpc-coholic
andauthored
App preferences migration (#93)
* adopt DataStore for preference storage, create migration utility for V1 to V2 settings migrations * orchestrate cleaning up v1 settings during migration, roll the device token * enable installer creation for vnext-kmp PRs * introduce file based logging to detect migration issues * make it possible to access logs and data folders in Settings * change package name to "pretixSCAN Desktop" for Windows * Update publish pipeline to new package names --------- Co-authored-by: Martin Gross <[email protected]>
1 parent 97809ac commit 5aedbbf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2148
-306
lines changed

.github/workflows/publish.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77
- master
88
- main
99
- update-tornadofx
10+
- vnext-kmp
1011

1112
# prevent duplicate runs on the same branch
1213
concurrency:
@@ -36,7 +37,8 @@ jobs:
3637

3738
- name: Package App
3839
working-directory: ./pretixscan
39-
run: ./gradlew packageDistributionForCurrentOS
40+
shell: bash
41+
run: ./gradlew packageDistributionForCurrentOS -PappPackageName="${{ runner.os == 'Windows' && 'pretixSCAN Desktop' || 'pretixSCAN' }}"
4042

4143
- name: Read version
4244
working-directory: ./pretixscan
@@ -55,7 +57,7 @@ jobs:
5557
uses: actions/upload-artifact@v4
5658
with:
5759
name: pretixSCAN-${{ env.pretixVersion }}-win-x86_64.msi
58-
path: ./pretixscan/composeApp/build/compose/binaries/main/msi/pretixSCAN-${{ env.pretixVersion }}.msi
60+
path: ./pretixscan/composeApp/build/compose/binaries/main/msi/pretixSCAN Desktop-${{ env.pretixVersion }}.msi
5961

6062
- name: Upload Linux amd64
6163
if: matrix.os == 'ubuntu-latest'

pretixscan/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
composeApp/*.preferences_pb

pretixscan/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ KMP provides for various native distributions to be created, please refer to the
3535
For example, create a distribution package for the current OS:
3636

3737
```bash
38-
./gradlew packageDistributionForCurrentOS
38+
./gradlew packageDistributionForCurrentOS -PappPackageName="pretixSCAN"
3939
```
4040

4141
By default, packages are created under `pretixscan/composeApp/build/compose/binaries`.

pretixscan/composeApp/build.gradle.kts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ kotlin {
3737
implementation(libs.vanniktech.multiplatform.locale)
3838
implementation(libs.kotlinx.serialization.json)
3939

40+
api(libs.datastore.core)
41+
api(libs.datastore.preferences)
42+
4043
// play short audio files
4144
implementation(libs.gadulka)
4245

@@ -150,8 +153,12 @@ compose.desktop {
150153
mainClass = "eu.pretix.desktop.MainKt"
151154

152155
nativeDistributions {
156+
// On Windows, we need the packageName to be set as 'pretixSCAN Desktop' in order to avoid a conflict with v1
157+
158+
val packageNameValue = findProperty("appPackageName")?.toString() ?: "pretixSCAN-default"
159+
153160
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
154-
packageName = "pretixSCAN"
161+
packageName = packageNameValue
155162
packageVersion = version
156163
vendor = "pretix GmbH"
157164
copyright = "pretix.eu, Raphael Michel"
@@ -164,23 +171,34 @@ compose.desktop {
164171
macOS {
165172
iconFile.set(File("logo/pretix_app_icon.icns"))
166173
}
174+
167175
windows {
168176
iconFile.set(File("logo/pretix_app_icon.ico"))
169177

170178
// MSI specific configuration
171179
console = false
172180
dirChooser = true
173181
perUserInstall = false
174-
menuGroup = "pretixSCAN"
182+
menuGroup = "pretixSCAN Desktop"
175183
shortcut = true
176184

177185
// Upgrade settings - consistent UUID for upgrade support
178186
upgradeUuid = "550e8400-e29b-41d4-a716-446655440000"
179187

180188
}
189+
181190
linux {
182191
iconFile.set(File("logo/pretix_app_icon.png"))
183192
}
184193
}
185194
}
195+
}
196+
197+
// Validate packageName is provided for packaging tasks
198+
tasks.matching { it.name.contains("package", ignoreCase = true) }.configureEach {
199+
doFirst {
200+
if (findProperty("appPackageName") == null) {
201+
throw GradleException("Package name must be provided via -PappPackageName=<name> for packaging tasks")
202+
}
203+
}
186204
}

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
<string name="progress_registering">Registering device with server…</string>
1010
<string name="error_access_revoked">Device access has been revoked, you need to register the device with the server again.</string>
1111
<string name="error_unknown_exception">An unknown error has occurred</string>
12+
<string name="error_connecting_token">Connection Error</string>
1213
<string name="error_not_synchronized">Your device has not been properly synchronized with the server</string>
1314
<string name="action_label_ok">OK</string>
15+
<string name="action_label_back">Back</string>
1416
<string name="action_label_settings">Settings</string>
1517
<string name="action_label_statistics">Statistics</string>
1618
<string name="action_label_scantype_entry">Switch to entry scanning</string>
@@ -47,12 +49,12 @@
4749
<string name="settings_label_auto_switch">Automatic event selection</string>
4850
<string name="settings_summary_auto_switch">With this option, pretixSCAN will ask the server during synchronization if the server suggests switching the app to a different event and check-in list and then switches automatically.</string>
4951
<plurals name="sync_status_time_minutes">
50-
<item quantity="one">synchronized %d minute ago</item>
51-
<item quantity="other">synchronized %d minutes ago</item>
52+
<item quantity="one">synchronized %1$d minute ago</item>
53+
<item quantity="other">synchronized %1$d minutes ago</item>
5254
</plurals>
5355
<plurals name="sync_status_time_hours">
54-
<item quantity="one">synchronized %d hour ago</item>
55-
<item quantity="other">synchronized %d hours ago</item>
56+
<item quantity="one">synchronized %1$d hour ago</item>
57+
<item quantity="other">synchronized %1$d hours ago</item>
5658
</plurals>
5759
<plurals name="sync_status_time_days">
5860
<item quantity="one">synchronized %1$d day ago</item>
@@ -95,6 +97,7 @@
9597
<string name="settings_label_sync">Synchronization</string>
9698
<string name="settings_label_ui">User interface</string>
9799
<string name="settings_label_about">About this app</string>
100+
<string name="settings_label_diagnostics">Diagnostics</string>
98101
<string name="settings_label_licenses">Author and licenses</string>
99102
<string name="settings_label_device_camera">Use device camera</string>
100103
<string name="settings_label_scan_offline">Offline scanning</string>
@@ -169,6 +172,8 @@
169172
<string name="full_delete">Delete all local data and reset device</string>
170173
<string name="full_delete_confirm">Do you really want to reset the device? You will need to pair it with the online system again.</string>
171174
<string name="full_delete_action">Logout and reset</string>
175+
<string name="open_data_folder_action">Open data folder</string>
176+
<string name="open_logs_folder_action">Open logs folder</string>
172177
<string name="label_shop_active">Active</string>
173178
<string name="label_shop_inactive">Shop deactivated</string>
174179
<string name="settings_label_search_disable">Disable search</string>

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/KoinModules.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package eu.pretix
33
import di.platformModules
44
import eu.pretix.desktop.app.sync.syncModule
55
import eu.pretix.desktop.cache.di.cacheModules
6+
import eu.pretix.desktop.migration.di.migrationModule
67
import eu.pretix.desktop.webcam.webCamModule
78
import eu.pretix.scan.main.mainModule
89
import eu.pretix.scan.settings.settingsModule
@@ -14,6 +15,7 @@ import org.koin.core.KoinApplication
1415
fun KoinApplication.initModules() {
1516
modules(platformModules)
1617
modules(cacheModules)
18+
modules(migrationModule)
1719
modules(pretixModules)
1820
modules(ticketsModule)
1921
modules(syncModule)

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/PretixModules.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package eu.pretix
22

33
import eu.pretix.desktop.app.DesktopSentryImpl
44
import eu.pretix.desktop.cache.AppCache
5-
import eu.pretix.desktop.cache.AppConfig
5+
import eu.pretix.desktop.cache.DataStoreConfigStore
66
import eu.pretix.libpretixsync.SentryInterface
77
import eu.pretix.libpretixsync.api.HttpClientFactory
88
import eu.pretix.libpretixsync.api.PretixApi
@@ -15,6 +15,9 @@ import eu.pretix.libpretixsync.sync.FileStorage
1515
import eu.pretix.scan.tickets.data.PrintLayoutFetcher
1616
import org.koin.core.module.Module
1717
import org.koin.dsl.module
18+
import java.util.logging.Logger
19+
20+
private val log = Logger.getLogger("PretixModules")
1821

1922

2023
val pretixModules: List<Module>
@@ -24,10 +27,10 @@ val pretixModules: List<Module>
2427
DesktopSentryImpl()
2528
}
2629
factory<EventManager> {
27-
EventManager(get<PretixApi>(), get<AppConfig>(), false)
30+
EventManager(get<PretixApi>(), get<DataStoreConfigStore>(), false)
2831
}
2932
factory<PretixApi> {
30-
val config = get<AppConfig>()
33+
val config = get<DataStoreConfigStore>()
3134
if (!config.isConfigured) {
3235
throw UnsupportedOperationException("Invalid operation: PretixApi can only be used once the device has been initialised using SetupManager.")
3336
}
@@ -40,21 +43,21 @@ val pretixModules: List<Module>
4043
)
4144
}
4245
factory<TicketCheckProvider> {
43-
val config = get<AppConfig>()
46+
val config = get<DataStoreConfigStore>()
4447
if (!config.isConfigured) {
4548
throw UnsupportedOperationException("Invalid operation: TicketCheckProvider can only be used once the device has been initialised.")
4649
}
4750

4851
val appCache = get<AppCache>()
4952

5053
if (config.proxyMode) {
51-
println("Resolving TicketCheckProvider in proxy mode")
54+
log.info("Resolving TicketCheckProvider in proxy mode")
5255
ProxyCheckProvider(config, get<HttpClientFactory>())
5356
} else if (config.offlineMode) {
54-
println("Resolving TicketCheckProvider in offline mode")
57+
log.info("Resolving TicketCheckProvider in offline mode")
5558
AsyncCheckProvider(config, appCache.db)
5659
} else {
57-
println("Resolving TicketCheckProvider in online mode")
60+
log.info("Resolving TicketCheckProvider in online mode")
5861
OnlineCheckProvider(
5962
config,
6063
get<HttpClientFactory>(),

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/desktop/app/navigation/Navigation.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ package eu.pretix.desktop.app.navigation
33
import androidx.compose.animation.fadeIn
44
import androidx.compose.animation.fadeOut
55
import androidx.compose.foundation.layout.fillMaxSize
6-
import androidx.compose.runtime.Composable
6+
import androidx.compose.runtime.*
77
import androidx.compose.ui.Modifier
88
import androidx.navigation.NavHostController
99
import androidx.navigation.compose.NavHost
1010
import androidx.navigation.compose.composable
1111
import eu.pretix.desktop.app.sync.SyncRoot
1212
import eu.pretix.desktop.app.ui.ScreenRoot
13-
import eu.pretix.desktop.cache.AppConfig
13+
import eu.pretix.desktop.cache.DataStoreConfigStore
1414
import eu.pretix.scan.main.presentation.MainScreen
1515
import eu.pretix.scan.settings.presentation.SettingsScreen
1616
import eu.pretix.scan.setup.SetupScreen
@@ -23,12 +23,10 @@ fun Navigation(
2323
navHostController: NavHostController,
2424
modifier: Modifier = Modifier,
2525
) {
26-
// determine the starting screen based on whether the app is configured or not
27-
val appConfig = koinInject<AppConfig>()
26+
val appConfig = koinInject<DataStoreConfigStore>()
2827
val startDestination: String = if (appConfig.isConfigured) Route.Main.route else Route.Welcome.route
2928

3029
SyncRoot(navHostController) {
31-
// setup navigation graph
3230
NavHost(
3331
navController = navHostController,
3432
startDestination = startDestination,
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ fun SyncedTimeAgo(never: Boolean, daysAgo: Int, hoursAgo: Int, minutesAgo: Int)
8383
}
8484

8585
statusHelper.isDaysAgo() -> {
86-
println("days ago ${statusHelper.daysAgo()}")
8786
Text(
8887
pluralStringResource(
8988
Res.plurals.sync_status_time_days,

pretixscan/composeApp/src/commonMain/kotlin/eu/pretix/desktop/app/sync/SyncRoot.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ fun SyncRoot(
3636
}
3737

3838
val showMainSyncProgress by viewModel.showMainSyncProgress.collectAsState()
39-
println("Current sync state: $syncState")
4039

4140
Box(Modifier.fillMaxSize()) {
4241
// render child content

0 commit comments

Comments
 (0)