diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 7f4f9dc2..7d48b923 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -31,7 +31,7 @@ jobs: uses: actions/upload-artifact@v4.5.0 with: name: unsigned-release-apk - path: app/build/outputs/apk/fdroid/release/app-fdroid-release-unsigned.apk + path: androidApp/build/outputs/apk/fdroid/release/androidApp-fdroid-release-unsigned.apk if-no-files-found: error - uses: noriban/sign-android-release@v5 name: Sign app APK @@ -39,7 +39,7 @@ jobs: # ID used to access action output id: sign_app with: - releaseDirectory: app/build/outputs/apk/fdroid/release + releaseDirectory: androidApp/build/outputs/apk/fdroid/release signingKeyBase64: ${{ secrets.CI_KEYSTORE_BASE64 }} alias: ${{ secrets.CI_ALIAS }} keyStorePassword: ${{ secrets.CI_KEY_STORE_PASSWORD }} diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index dcf11f97..cee607e2 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -85,18 +85,18 @@ jobs: # ID used to access action output id: sign_app with: - releaseDirectory: app/build/outputs/apk/fdroid/release + releaseDirectory: androidApp/build/outputs/apk/fdroid/release signingKeyBase64: ${{ secrets.RELEASE_KEY_STORE_BASE64 }} alias: ${{ secrets.RELEASE_ALIAS }} keyStorePassword: ${{ secrets.RELEASE_KEY_STORE_PASSWORD }} keyPassword: ${{ secrets.RELEASE_KEY_PASSWORD }} - name: Rename signed APK - run: mv ${{steps.sign_app.outputs.signedReleaseFile}} app/build/outputs/apk/fdroid/release/ScanBridge${{ needs.prepare.outputs.artifact_version_suffix }}.apk + run: mv ${{steps.sign_app.outputs.signedReleaseFile}} androidApp/build/outputs/apk/fdroid/release/ScanBridge${{ needs.prepare.outputs.artifact_version_suffix }}.apk - name: Upload signed APK uses: actions/upload-artifact@v4.5.0 with: name: signed-release-apk - path: app/build/outputs/apk/fdroid/release/ScanBridge${{ needs.prepare.outputs.artifact_version_suffix }}.apk + path: androidApp/build/outputs/apk/fdroid/release/ScanBridge${{ needs.prepare.outputs.artifact_version_suffix }}.apk if-no-files-found: error publish-result: diff --git a/.gitignore b/.gitignore index 802c8c92..91250319 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ app/src/androidTest/native-libs /app/debug /app/release /app/play -/fastlane/report.xml \ No newline at end of file +/fastlane/report.xml +/http-requests/http-client.private.env.json diff --git a/README.md b/README.md index a01bd621..679da54f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

- Get it on F-Droid - Get it on Google Play - Discover scanners in your network - Scan multiple pages - Use your scanner to the maximum of its abilities + Discover scanners in your network + Scan multiple pages + Use your scanner to the maximum of its abilities ## Features @@ -104,7 +104,7 @@ If you want to chat with me or other users, you can join the Matrix room ## Contributions Contributions are welcome, and it would be amazing if you want to help. Refer to -the [Contribution Guidelines](CONTRIBUTING.md) for more information. +the [Contribution Guidelines](androidApp/CONTRIBUTING.md) for more information. ## License diff --git a/app/.gitignore b/androidApp/.gitignore similarity index 100% rename from app/.gitignore rename to androidApp/.gitignore diff --git a/CHANGELOG.md b/androidApp/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to androidApp/CHANGELOG.md diff --git a/CONTRIBUTING.md b/androidApp/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to androidApp/CONTRIBUTING.md diff --git a/COPYING b/androidApp/COPYING similarity index 100% rename from COPYING rename to androidApp/COPYING diff --git a/Gemfile b/androidApp/Gemfile similarity index 100% rename from Gemfile rename to androidApp/Gemfile diff --git a/Gemfile.lock b/androidApp/Gemfile.lock similarity index 100% rename from Gemfile.lock rename to androidApp/Gemfile.lock diff --git a/adb+.sh b/androidApp/adb+.sh similarity index 100% rename from adb+.sh rename to androidApp/adb+.sh diff --git a/assets/GetItOnGooglePlay_Badge_Web_color_English.svg b/androidApp/assets/GetItOnGooglePlay_Badge_Web_color_English.svg similarity index 100% rename from assets/GetItOnGooglePlay_Badge_Web_color_English.svg rename to androidApp/assets/GetItOnGooglePlay_Badge_Web_color_English.svg diff --git a/assets/get-it-on-fdroid.svg b/androidApp/assets/get-it-on-fdroid.svg similarity index 100% rename from assets/get-it-on-fdroid.svg rename to androidApp/assets/get-it-on-fdroid.svg diff --git a/assets/icon.svg b/androidApp/assets/icon.svg similarity index 100% rename from assets/icon.svg rename to androidApp/assets/icon.svg diff --git a/app/build.gradle.kts b/androidApp/build.gradle.kts similarity index 77% rename from app/build.gradle.kts rename to androidApp/build.gradle.kts index 01f50bcc..3aa83677 100644 --- a/app/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -14,30 +14,14 @@ plugins { alias(libs.plugins.koin) alias(libs.plugins.protobuf) alias(libs.plugins.room) - id("com.google.devtools.ksp") version "2.3.6" - id("app.cash.paraphrase") version "0.4.1" + alias(libs.plugins.ksp) + alias(libs.plugins.paraphrase) } -fun getGitCommitHash(): String { - return try { - val command = "git rev-parse --short HEAD" - val process = ProcessBuilder() - .command(command.split(" ")) - .directory(rootProject.projectDir) - .redirectError(ProcessBuilder.Redirect.INHERIT) - .start() - val wait = process.waitFor(60, TimeUnit.SECONDS) - if (!wait) { - return "unknown" - } - - val result = process.inputStream.bufferedReader().readText() - - result.trim() - } catch (_: Exception) { - "unknown" // Fallback - } -} +val gitHashProvider = providers.exec { + commandLine("git", "rev-parse", "--short", "HEAD") + isIgnoreExitValue = true +}.standardOutput.asText.map { it.trim() } tasks.withType().all { compilerOptions { @@ -53,10 +37,6 @@ android { generateLocaleConfig = true } - room { - schemaDirectory("$projectDir/schemas") - } - defaultConfig { applicationId = "io.github.chrisimx.scanbridge" minSdk = 28 @@ -76,10 +56,10 @@ android { getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) - buildConfigField("String", "GIT_COMMIT_HASH", "\"${getGitCommitHash()}\"") + buildConfigField("String", "GIT_COMMIT_HASH", "\"${gitHashProvider.get()}\"") } debug { - buildConfigField("String", "GIT_COMMIT_HASH", "\"${getGitCommitHash()}\"") + buildConfigField("String", "GIT_COMMIT_HASH", "\"${gitHashProvider.get()}\"") } } flavorDimensions += "edition" @@ -96,8 +76,8 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } buildFeatures { compose = true @@ -107,11 +87,16 @@ android { kotlin { compilerOptions { - jvmTarget = JvmTarget.JVM_11 + jvmTarget = JvmTarget.JVM_17 optIn.add("kotlin.uuid.ExperimentalUuidApi") + freeCompilerArgs.add("-Xnon-local-break-continue") } } +room { + schemaDirectory("$projectDir/schemas") +} + dependencies { implementation(libs.koin.core) implementation(libs.koin.android) @@ -119,17 +104,19 @@ dependencies { implementation(libs.koin.annotations) implementation(libs.koin.compose.viewmodel) implementation(libs.koin.androix.navigation) - implementation(libs.esclkt) implementation(libs.zoomable) implementation(libs.kotlin.reflect) implementation(libs.coil.compose) implementation(libs.timber) implementation(libs.androidx.navigation.compose) implementation(libs.kotlinx.serialization.json) + implementation(project(":core")) + implementation(project(":composeUI")) + implementation(libs.androidx.concurrent.futures) ksp(libs.androidx.room.compiler) implementation(libs.androidx.room.runtime) - implementation(libs.androidx.room.ktx) + implementation(libs.androidx.sqlite.bundled) implementation(libs.androidx.datastore) implementation(libs.protobuf.kotlin.lite) @@ -146,12 +133,12 @@ dependencies { implementation(libs.androidx.material.icons.core) implementation(libs.androidx.constraintlayout.compose) implementation(libs.itext7.core) - implementation(libs.ktor.okhttp) + implementation(libs.ktor.client.okhttp) implementation(libs.ktor.logging) "playImplementation"(project(":lvl_library")) - "playImplementation"("com.squareup.retrofit2:retrofit:3.0.0") - "playImplementation"("com.squareup.retrofit2:converter-gson:2.9.0") - "playImplementation"("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") + "playImplementation"(libs.retrofit) + "playImplementation"(libs.retrofit.converter.gson) + "playImplementation"(libs.kotlinx.coroutines.android) testImplementation(libs.junit) @@ -168,7 +155,9 @@ dependencies { protobuf { protoc { - artifact = "com.google.protobuf:protoc:4.33.5" + val protoc = libs.protoc.get() + + artifact = "${protoc.module}:${protoc.version}" } generateProtoTasks { all().forEach { task -> @@ -182,6 +171,10 @@ protobuf { } } +koinCompiler { + compileSafety = true +} + afterEvaluate { tasks.named("clean") { doLast { diff --git a/fastlane/Appfile b/androidApp/fastlane/Appfile similarity index 100% rename from fastlane/Appfile rename to androidApp/fastlane/Appfile diff --git a/fastlane/Fastfile b/androidApp/fastlane/Fastfile similarity index 91% rename from fastlane/Fastfile rename to androidApp/fastlane/Fastfile index 9d68fe38..eb1f6e5e 100644 --- a/fastlane/Fastfile +++ b/androidApp/fastlane/Fastfile @@ -100,8 +100,8 @@ platform :android do sh("adb shell wm user-rotation lock #{rotation}") screengrab( - tests_apk_path: "app/build/outputs/apk/androidTest/play/debug/app-play-debug-androidTest.apk", - app_apk_path: "app/build/outputs/apk/play/debug/app-play-debug.apk", + tests_apk_path: "androidApp/build/outputs/apk/androidTest/play/debug/androidApp-play-debug-androidTest.apk", + app_apk_path: "androidApp/build/outputs/apk/play/debug/androidApp-play-debug.apk", output_directory: $playMetadata, device_type: device_type, tests_package_name: "io.github.chrisimx.scanbridge.play.test", @@ -111,8 +111,8 @@ platform :android do ) screengrab( - tests_apk_path: "app/build/outputs/apk/androidTest/fdroid/debug/app-fdroid-debug-androidTest.apk", - app_apk_path: "app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk", + tests_apk_path: "androidApp/build/outputs/apk/androidTest/fdroid/debug/androidApp-fdroid-debug-androidTest.apk", + app_apk_path: "androidApp/build/outputs/apk/fdroid/debug/androidApp-fdroid-debug.apk", output_directory: "fastlane/metadata/android", device_type: device_type, tests_package_name: "io.github.chrisimx.scanbridge.test", diff --git a/fastlane/README.md b/androidApp/fastlane/README.md similarity index 100% rename from fastlane/README.md rename to androidApp/fastlane/README.md diff --git a/fastlane/Screengrabfile b/androidApp/fastlane/Screengrabfile similarity index 100% rename from fastlane/Screengrabfile rename to androidApp/fastlane/Screengrabfile diff --git a/fastlane/metadata/android/de-DE/changelogs/1000000.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/1000000.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/1000000.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/1000000.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/1000001.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/1000001.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/1000001.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/1000001.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/1001000.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/1001000.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/1001000.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/1001000.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/1002000.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/1002000.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/1002000.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/1002000.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/1003000.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/1003000.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/1003000.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/1003000.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/1004000.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/1004000.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/1004000.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/1004000.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/1005000.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/1005000.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/1005000.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/1005000.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/1006001.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/1006001.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/1006001.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/1006001.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/1006002.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/1006002.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/1006002.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/1006002.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/2000000.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/2000000.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/2000000.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/2000000.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/2000001.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/2000001.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/2000001.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/2000001.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/2001002.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/2001002.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/2001002.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/2001002.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/2001003.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/2001003.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/2001003.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/2001003.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/2001004.txt b/androidApp/fastlane/metadata/android/de-DE/changelogs/2001004.txt similarity index 100% rename from fastlane/metadata/android/de-DE/changelogs/2001004.txt rename to androidApp/fastlane/metadata/android/de-DE/changelogs/2001004.txt diff --git a/fastlane/metadata/android/de-DE/full_description.txt b/androidApp/fastlane/metadata/android/de-DE/full_description.txt similarity index 100% rename from fastlane/metadata/android/de-DE/full_description.txt rename to androidApp/fastlane/metadata/android/de-DE/full_description.txt diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/01-scannedPageScreen_1773391883115.png b/androidApp/fastlane/metadata/android/de-DE/images/phoneScreenshots/01-scannedPageScreen_1773391883115.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/phoneScreenshots/01-scannedPageScreen_1773391883115.png rename to androidApp/fastlane/metadata/android/de-DE/images/phoneScreenshots/01-scannedPageScreen_1773391883115.png diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/02-scanSettings_1773391879801.png b/androidApp/fastlane/metadata/android/de-DE/images/phoneScreenshots/02-scanSettings_1773391879801.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/phoneScreenshots/02-scanSettings_1773391879801.png rename to androidApp/fastlane/metadata/android/de-DE/images/phoneScreenshots/02-scanSettings_1773391879801.png diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/03-discoveryScreen_1773391880499.png b/androidApp/fastlane/metadata/android/de-DE/images/phoneScreenshots/03-discoveryScreen_1773391880499.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/phoneScreenshots/03-discoveryScreen_1773391880499.png rename to androidApp/fastlane/metadata/android/de-DE/images/phoneScreenshots/03-discoveryScreen_1773391880499.png diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/04-emptyScanScreen_1773391882198.png b/androidApp/fastlane/metadata/android/de-DE/images/phoneScreenshots/04-emptyScanScreen_1773391882198.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/phoneScreenshots/04-emptyScanScreen_1773391882198.png rename to androidApp/fastlane/metadata/android/de-DE/images/phoneScreenshots/04-emptyScanScreen_1773391882198.png diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/05-settingsScreen_1773391884031.png b/androidApp/fastlane/metadata/android/de-DE/images/phoneScreenshots/05-settingsScreen_1773391884031.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/phoneScreenshots/05-settingsScreen_1773391884031.png rename to androidApp/fastlane/metadata/android/de-DE/images/phoneScreenshots/05-settingsScreen_1773391884031.png diff --git a/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/01-scannedPageScreen_1773392085232.png b/androidApp/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/01-scannedPageScreen_1773392085232.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/sevenInchScreenshots/01-scannedPageScreen_1773392085232.png rename to androidApp/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/01-scannedPageScreen_1773392085232.png diff --git a/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/02-scanSettings_1773392081788.png b/androidApp/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/02-scanSettings_1773392081788.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/sevenInchScreenshots/02-scanSettings_1773392081788.png rename to androidApp/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/02-scanSettings_1773392081788.png diff --git a/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/03-discoveryScreen_1773392082774.png b/androidApp/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/03-discoveryScreen_1773392082774.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/sevenInchScreenshots/03-discoveryScreen_1773392082774.png rename to androidApp/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/03-discoveryScreen_1773392082774.png diff --git a/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/04-emptyScanScreen_1773392084316.png b/androidApp/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/04-emptyScanScreen_1773392084316.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/sevenInchScreenshots/04-emptyScanScreen_1773392084316.png rename to androidApp/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/04-emptyScanScreen_1773392084316.png diff --git a/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/05-settingsScreen_1773392086217.png b/androidApp/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/05-settingsScreen_1773392086217.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/sevenInchScreenshots/05-settingsScreen_1773392086217.png rename to androidApp/fastlane/metadata/android/de-DE/images/sevenInchScreenshots/05-settingsScreen_1773392086217.png diff --git a/fastlane/metadata/android/de-DE/images/tenInchScreenshots/01-scannedPageScreen_1772541896730.png b/androidApp/fastlane/metadata/android/de-DE/images/tenInchScreenshots/01-scannedPageScreen_1772541896730.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/tenInchScreenshots/01-scannedPageScreen_1772541896730.png rename to androidApp/fastlane/metadata/android/de-DE/images/tenInchScreenshots/01-scannedPageScreen_1772541896730.png diff --git a/fastlane/metadata/android/de-DE/images/tenInchScreenshots/02-scanSettings_1772541894045.png b/androidApp/fastlane/metadata/android/de-DE/images/tenInchScreenshots/02-scanSettings_1772541894045.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/tenInchScreenshots/02-scanSettings_1772541894045.png rename to androidApp/fastlane/metadata/android/de-DE/images/tenInchScreenshots/02-scanSettings_1772541894045.png diff --git a/fastlane/metadata/android/de-DE/images/tenInchScreenshots/03-discoveryScreen_1772541894498.png b/androidApp/fastlane/metadata/android/de-DE/images/tenInchScreenshots/03-discoveryScreen_1772541894498.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/tenInchScreenshots/03-discoveryScreen_1772541894498.png rename to androidApp/fastlane/metadata/android/de-DE/images/tenInchScreenshots/03-discoveryScreen_1772541894498.png diff --git a/fastlane/metadata/android/de-DE/images/tenInchScreenshots/04-emptyScanScreen_1772541895682.png b/androidApp/fastlane/metadata/android/de-DE/images/tenInchScreenshots/04-emptyScanScreen_1772541895682.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/tenInchScreenshots/04-emptyScanScreen_1772541895682.png rename to androidApp/fastlane/metadata/android/de-DE/images/tenInchScreenshots/04-emptyScanScreen_1772541895682.png diff --git a/fastlane/metadata/android/de-DE/images/tenInchScreenshots/05-settingsScreen_1772541897397.png b/androidApp/fastlane/metadata/android/de-DE/images/tenInchScreenshots/05-settingsScreen_1772541897397.png similarity index 100% rename from fastlane/metadata/android/de-DE/images/tenInchScreenshots/05-settingsScreen_1772541897397.png rename to androidApp/fastlane/metadata/android/de-DE/images/tenInchScreenshots/05-settingsScreen_1772541897397.png diff --git a/fastlane/metadata/android/de-DE/short_description.txt b/androidApp/fastlane/metadata/android/de-DE/short_description.txt similarity index 100% rename from fastlane/metadata/android/de-DE/short_description.txt rename to androidApp/fastlane/metadata/android/de-DE/short_description.txt diff --git a/fastlane/metadata/android/de-DE/title.txt b/androidApp/fastlane/metadata/android/de-DE/title.txt similarity index 100% rename from fastlane/metadata/android/de-DE/title.txt rename to androidApp/fastlane/metadata/android/de-DE/title.txt diff --git a/fastlane/metadata/android/en-US/changelogs/1000000.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/1000000.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/1000000.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/1000000.txt diff --git a/fastlane/metadata/android/en-US/changelogs/1000001.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/1000001.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/1000001.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/1000001.txt diff --git a/fastlane/metadata/android/en-US/changelogs/1001000.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/1001000.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/1001000.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/1001000.txt diff --git a/fastlane/metadata/android/en-US/changelogs/1002000.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/1002000.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/1002000.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/1002000.txt diff --git a/fastlane/metadata/android/en-US/changelogs/1003000.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/1003000.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/1003000.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/1003000.txt diff --git a/fastlane/metadata/android/en-US/changelogs/1004000.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/1004000.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/1004000.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/1004000.txt diff --git a/fastlane/metadata/android/en-US/changelogs/1005000.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/1005000.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/1005000.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/1005000.txt diff --git a/fastlane/metadata/android/en-US/changelogs/1006001.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/1006001.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/1006001.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/1006001.txt diff --git a/fastlane/metadata/android/en-US/changelogs/1006002.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/1006002.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/1006002.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/1006002.txt diff --git a/fastlane/metadata/android/en-US/changelogs/2000000.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/2000000.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/2000000.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/2000000.txt diff --git a/fastlane/metadata/android/en-US/changelogs/2000001.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/2000001.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/2000001.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/2000001.txt diff --git a/fastlane/metadata/android/en-US/changelogs/2001002.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/2001002.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/2001002.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/2001002.txt diff --git a/fastlane/metadata/android/en-US/changelogs/2001003.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/2001003.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/2001003.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/2001003.txt diff --git a/fastlane/metadata/android/en-US/changelogs/2001004.txt b/androidApp/fastlane/metadata/android/en-US/changelogs/2001004.txt similarity index 100% rename from fastlane/metadata/android/en-US/changelogs/2001004.txt rename to androidApp/fastlane/metadata/android/en-US/changelogs/2001004.txt diff --git a/fastlane/metadata/android/en-US/full_description.txt b/androidApp/fastlane/metadata/android/en-US/full_description.txt similarity index 100% rename from fastlane/metadata/android/en-US/full_description.txt rename to androidApp/fastlane/metadata/android/en-US/full_description.txt diff --git a/fastlane/metadata/android/en-US/images/icon.png b/androidApp/fastlane/metadata/android/en-US/images/icon.png similarity index 100% rename from fastlane/metadata/android/en-US/images/icon.png rename to androidApp/fastlane/metadata/android/en-US/images/icon.png diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/01-scannedPageScreen_1773391873581.png b/androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/01-scannedPageScreen_1773391873581.png similarity index 100% rename from fastlane/metadata/android/en-US/images/phoneScreenshots/01-scannedPageScreen_1773391873581.png rename to androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/01-scannedPageScreen_1773391873581.png diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/02-scanSettings_1773391870896.png b/androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/02-scanSettings_1773391870896.png similarity index 100% rename from fastlane/metadata/android/en-US/images/phoneScreenshots/02-scanSettings_1773391870896.png rename to androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/02-scanSettings_1773391870896.png diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/03-discoveryScreen_1773391871298.png b/androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/03-discoveryScreen_1773391871298.png similarity index 100% rename from fastlane/metadata/android/en-US/images/phoneScreenshots/03-discoveryScreen_1773391871298.png rename to androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/03-discoveryScreen_1773391871298.png diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/04-emptyScanScreen_1773391872597.png b/androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/04-emptyScanScreen_1773391872597.png similarity index 100% rename from fastlane/metadata/android/en-US/images/phoneScreenshots/04-emptyScanScreen_1773391872597.png rename to androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/04-emptyScanScreen_1773391872597.png diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/05-settingsScreen_1773391874196.png b/androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/05-settingsScreen_1773391874196.png similarity index 100% rename from fastlane/metadata/android/en-US/images/phoneScreenshots/05-settingsScreen_1773391874196.png rename to androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/05-settingsScreen_1773391874196.png diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/01-scannedPageScreen_1773392074370.png b/androidApp/fastlane/metadata/android/en-US/images/sevenInchScreenshots/01-scannedPageScreen_1773392074370.png similarity index 100% rename from fastlane/metadata/android/en-US/images/sevenInchScreenshots/01-scannedPageScreen_1773392074370.png rename to androidApp/fastlane/metadata/android/en-US/images/sevenInchScreenshots/01-scannedPageScreen_1773392074370.png diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/02-scanSettings_1773392071595.png b/androidApp/fastlane/metadata/android/en-US/images/sevenInchScreenshots/02-scanSettings_1773392071595.png similarity index 100% rename from fastlane/metadata/android/en-US/images/sevenInchScreenshots/02-scanSettings_1773392071595.png rename to androidApp/fastlane/metadata/android/en-US/images/sevenInchScreenshots/02-scanSettings_1773392071595.png diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/03-discoveryScreen_1773392071982.png b/androidApp/fastlane/metadata/android/en-US/images/sevenInchScreenshots/03-discoveryScreen_1773392071982.png similarity index 100% rename from fastlane/metadata/android/en-US/images/sevenInchScreenshots/03-discoveryScreen_1773392071982.png rename to androidApp/fastlane/metadata/android/en-US/images/sevenInchScreenshots/03-discoveryScreen_1773392071982.png diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/04-emptyScanScreen_1773392073386.png b/androidApp/fastlane/metadata/android/en-US/images/sevenInchScreenshots/04-emptyScanScreen_1773392073386.png similarity index 100% rename from fastlane/metadata/android/en-US/images/sevenInchScreenshots/04-emptyScanScreen_1773392073386.png rename to androidApp/fastlane/metadata/android/en-US/images/sevenInchScreenshots/04-emptyScanScreen_1773392073386.png diff --git a/fastlane/metadata/android/en-US/images/sevenInchScreenshots/05-settingsScreen_1773392074964.png b/androidApp/fastlane/metadata/android/en-US/images/sevenInchScreenshots/05-settingsScreen_1773392074964.png similarity index 100% rename from fastlane/metadata/android/en-US/images/sevenInchScreenshots/05-settingsScreen_1773392074964.png rename to androidApp/fastlane/metadata/android/en-US/images/sevenInchScreenshots/05-settingsScreen_1773392074964.png diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/01-scannedPageScreen_1772541886403.png b/androidApp/fastlane/metadata/android/en-US/images/tenInchScreenshots/01-scannedPageScreen_1772541886403.png similarity index 100% rename from fastlane/metadata/android/en-US/images/tenInchScreenshots/01-scannedPageScreen_1772541886403.png rename to androidApp/fastlane/metadata/android/en-US/images/tenInchScreenshots/01-scannedPageScreen_1772541886403.png diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/02-scanSettings_1772541881705.png b/androidApp/fastlane/metadata/android/en-US/images/tenInchScreenshots/02-scanSettings_1772541881705.png similarity index 100% rename from fastlane/metadata/android/en-US/images/tenInchScreenshots/02-scanSettings_1772541881705.png rename to androidApp/fastlane/metadata/android/en-US/images/tenInchScreenshots/02-scanSettings_1772541881705.png diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/03-discoveryScreen_1772541884121.png b/androidApp/fastlane/metadata/android/en-US/images/tenInchScreenshots/03-discoveryScreen_1772541884121.png similarity index 100% rename from fastlane/metadata/android/en-US/images/tenInchScreenshots/03-discoveryScreen_1772541884121.png rename to androidApp/fastlane/metadata/android/en-US/images/tenInchScreenshots/03-discoveryScreen_1772541884121.png diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/04-emptyScanScreen_1772541885597.png b/androidApp/fastlane/metadata/android/en-US/images/tenInchScreenshots/04-emptyScanScreen_1772541885597.png similarity index 100% rename from fastlane/metadata/android/en-US/images/tenInchScreenshots/04-emptyScanScreen_1772541885597.png rename to androidApp/fastlane/metadata/android/en-US/images/tenInchScreenshots/04-emptyScanScreen_1772541885597.png diff --git a/fastlane/metadata/android/en-US/images/tenInchScreenshots/05-settingsScreen_1772541889078.png b/androidApp/fastlane/metadata/android/en-US/images/tenInchScreenshots/05-settingsScreen_1772541889078.png similarity index 100% rename from fastlane/metadata/android/en-US/images/tenInchScreenshots/05-settingsScreen_1772541889078.png rename to androidApp/fastlane/metadata/android/en-US/images/tenInchScreenshots/05-settingsScreen_1772541889078.png diff --git a/fastlane/metadata/android/en-US/short_description.txt b/androidApp/fastlane/metadata/android/en-US/short_description.txt similarity index 100% rename from fastlane/metadata/android/en-US/short_description.txt rename to androidApp/fastlane/metadata/android/en-US/short_description.txt diff --git a/fastlane/metadata/android/en-US/title.txt b/androidApp/fastlane/metadata/android/en-US/title.txt similarity index 100% rename from fastlane/metadata/android/en-US/title.txt rename to androidApp/fastlane/metadata/android/en-US/title.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/1000000.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/1000000.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/1000000.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/1000000.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/1000001.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/1000001.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/1000001.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/1000001.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/1001000.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/1001000.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/1001000.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/1001000.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/1002000.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/1002000.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/1002000.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/1002000.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/1003000.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/1003000.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/1003000.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/1003000.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/1004000.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/1004000.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/1004000.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/1004000.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/1005000.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/1005000.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/1005000.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/1005000.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/1006001.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/1006001.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/1006001.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/1006001.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/1006002.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/1006002.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/1006002.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/1006002.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/2000000.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/2000000.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/2000000.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/2000000.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/2000001.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/2000001.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/2000001.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/2000001.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/2001002.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/2001002.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/2001002.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/2001002.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/2001003.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/2001003.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/2001003.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/2001003.txt diff --git a/fastlane/metadata/android/it-IT/changelogs/2001004.txt b/androidApp/fastlane/metadata/android/it-IT/changelogs/2001004.txt similarity index 100% rename from fastlane/metadata/android/it-IT/changelogs/2001004.txt rename to androidApp/fastlane/metadata/android/it-IT/changelogs/2001004.txt diff --git a/fastlane/metadata/android/it-IT/full_description.txt b/androidApp/fastlane/metadata/android/it-IT/full_description.txt similarity index 100% rename from fastlane/metadata/android/it-IT/full_description.txt rename to androidApp/fastlane/metadata/android/it-IT/full_description.txt diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/01-scannedPageScreen_1773391892623.png b/androidApp/fastlane/metadata/android/it-IT/images/phoneScreenshots/01-scannedPageScreen_1773391892623.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/phoneScreenshots/01-scannedPageScreen_1773391892623.png rename to androidApp/fastlane/metadata/android/it-IT/images/phoneScreenshots/01-scannedPageScreen_1773391892623.png diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/02-scanSettings_1773391889434.png b/androidApp/fastlane/metadata/android/it-IT/images/phoneScreenshots/02-scanSettings_1773391889434.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/phoneScreenshots/02-scanSettings_1773391889434.png rename to androidApp/fastlane/metadata/android/it-IT/images/phoneScreenshots/02-scanSettings_1773391889434.png diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/03-discoveryScreen_1773391890147.png b/androidApp/fastlane/metadata/android/it-IT/images/phoneScreenshots/03-discoveryScreen_1773391890147.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/phoneScreenshots/03-discoveryScreen_1773391890147.png rename to androidApp/fastlane/metadata/android/it-IT/images/phoneScreenshots/03-discoveryScreen_1773391890147.png diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/04-emptyScanScreen_1773391891679.png b/androidApp/fastlane/metadata/android/it-IT/images/phoneScreenshots/04-emptyScanScreen_1773391891679.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/phoneScreenshots/04-emptyScanScreen_1773391891679.png rename to androidApp/fastlane/metadata/android/it-IT/images/phoneScreenshots/04-emptyScanScreen_1773391891679.png diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/05-settingsScreen_1773391893582.png b/androidApp/fastlane/metadata/android/it-IT/images/phoneScreenshots/05-settingsScreen_1773391893582.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/phoneScreenshots/05-settingsScreen_1773391893582.png rename to androidApp/fastlane/metadata/android/it-IT/images/phoneScreenshots/05-settingsScreen_1773391893582.png diff --git a/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/01-scannedPageScreen_1773392097014.png b/androidApp/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/01-scannedPageScreen_1773392097014.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/sevenInchScreenshots/01-scannedPageScreen_1773392097014.png rename to androidApp/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/01-scannedPageScreen_1773392097014.png diff --git a/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/02-scanSettings_1773392093573.png b/androidApp/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/02-scanSettings_1773392093573.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/sevenInchScreenshots/02-scanSettings_1773392093573.png rename to androidApp/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/02-scanSettings_1773392093573.png diff --git a/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/03-discoveryScreen_1773392094636.png b/androidApp/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/03-discoveryScreen_1773392094636.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/sevenInchScreenshots/03-discoveryScreen_1773392094636.png rename to androidApp/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/03-discoveryScreen_1773392094636.png diff --git a/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/04-emptyScanScreen_1773392096232.png b/androidApp/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/04-emptyScanScreen_1773392096232.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/sevenInchScreenshots/04-emptyScanScreen_1773392096232.png rename to androidApp/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/04-emptyScanScreen_1773392096232.png diff --git a/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/05-settingsScreen_1773392098119.png b/androidApp/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/05-settingsScreen_1773392098119.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/sevenInchScreenshots/05-settingsScreen_1773392098119.png rename to androidApp/fastlane/metadata/android/it-IT/images/sevenInchScreenshots/05-settingsScreen_1773392098119.png diff --git a/fastlane/metadata/android/it-IT/images/tenInchScreenshots/01-scannedPageScreen_1772541911340.png b/androidApp/fastlane/metadata/android/it-IT/images/tenInchScreenshots/01-scannedPageScreen_1772541911340.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/tenInchScreenshots/01-scannedPageScreen_1772541911340.png rename to androidApp/fastlane/metadata/android/it-IT/images/tenInchScreenshots/01-scannedPageScreen_1772541911340.png diff --git a/fastlane/metadata/android/it-IT/images/tenInchScreenshots/02-scanSettings_1772541904718.png b/androidApp/fastlane/metadata/android/it-IT/images/tenInchScreenshots/02-scanSettings_1772541904718.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/tenInchScreenshots/02-scanSettings_1772541904718.png rename to androidApp/fastlane/metadata/android/it-IT/images/tenInchScreenshots/02-scanSettings_1772541904718.png diff --git a/fastlane/metadata/android/it-IT/images/tenInchScreenshots/03-discoveryScreen_1772541907169.png b/androidApp/fastlane/metadata/android/it-IT/images/tenInchScreenshots/03-discoveryScreen_1772541907169.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/tenInchScreenshots/03-discoveryScreen_1772541907169.png rename to androidApp/fastlane/metadata/android/it-IT/images/tenInchScreenshots/03-discoveryScreen_1772541907169.png diff --git a/fastlane/metadata/android/it-IT/images/tenInchScreenshots/04-emptyScanScreen_1772541910309.png b/androidApp/fastlane/metadata/android/it-IT/images/tenInchScreenshots/04-emptyScanScreen_1772541910309.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/tenInchScreenshots/04-emptyScanScreen_1772541910309.png rename to androidApp/fastlane/metadata/android/it-IT/images/tenInchScreenshots/04-emptyScanScreen_1772541910309.png diff --git a/fastlane/metadata/android/it-IT/images/tenInchScreenshots/05-settingsScreen_1772541914017.png b/androidApp/fastlane/metadata/android/it-IT/images/tenInchScreenshots/05-settingsScreen_1772541914017.png similarity index 100% rename from fastlane/metadata/android/it-IT/images/tenInchScreenshots/05-settingsScreen_1772541914017.png rename to androidApp/fastlane/metadata/android/it-IT/images/tenInchScreenshots/05-settingsScreen_1772541914017.png diff --git a/fastlane/metadata/android/it-IT/short_description.txt b/androidApp/fastlane/metadata/android/it-IT/short_description.txt similarity index 100% rename from fastlane/metadata/android/it-IT/short_description.txt rename to androidApp/fastlane/metadata/android/it-IT/short_description.txt diff --git a/fastlane/metadata/android/it-IT/title.txt b/androidApp/fastlane/metadata/android/it-IT/title.txt similarity index 100% rename from fastlane/metadata/android/it-IT/title.txt rename to androidApp/fastlane/metadata/android/it-IT/title.txt diff --git a/fastlane/metadata/android/screenshots.html b/androidApp/fastlane/metadata/android/screenshots.html similarity index 100% rename from fastlane/metadata/android/screenshots.html rename to androidApp/fastlane/metadata/android/screenshots.html diff --git a/fastlane/playMetadata/de-DE/changelogs/1006002.txt b/androidApp/fastlane/playMetadata/de-DE/changelogs/1006002.txt similarity index 100% rename from fastlane/playMetadata/de-DE/changelogs/1006002.txt rename to androidApp/fastlane/playMetadata/de-DE/changelogs/1006002.txt diff --git a/fastlane/playMetadata/de-DE/changelogs/2000000.txt b/androidApp/fastlane/playMetadata/de-DE/changelogs/2000000.txt similarity index 100% rename from fastlane/playMetadata/de-DE/changelogs/2000000.txt rename to androidApp/fastlane/playMetadata/de-DE/changelogs/2000000.txt diff --git a/fastlane/playMetadata/de-DE/changelogs/2000001.txt b/androidApp/fastlane/playMetadata/de-DE/changelogs/2000001.txt similarity index 100% rename from fastlane/playMetadata/de-DE/changelogs/2000001.txt rename to androidApp/fastlane/playMetadata/de-DE/changelogs/2000001.txt diff --git a/fastlane/playMetadata/de-DE/changelogs/2001002.txt b/androidApp/fastlane/playMetadata/de-DE/changelogs/2001002.txt similarity index 100% rename from fastlane/playMetadata/de-DE/changelogs/2001002.txt rename to androidApp/fastlane/playMetadata/de-DE/changelogs/2001002.txt diff --git a/fastlane/playMetadata/de-DE/changelogs/2001003.txt b/androidApp/fastlane/playMetadata/de-DE/changelogs/2001003.txt similarity index 100% rename from fastlane/playMetadata/de-DE/changelogs/2001003.txt rename to androidApp/fastlane/playMetadata/de-DE/changelogs/2001003.txt diff --git a/fastlane/playMetadata/de-DE/changelogs/2001004.txt b/androidApp/fastlane/playMetadata/de-DE/changelogs/2001004.txt similarity index 100% rename from fastlane/playMetadata/de-DE/changelogs/2001004.txt rename to androidApp/fastlane/playMetadata/de-DE/changelogs/2001004.txt diff --git a/fastlane/playMetadata/de-DE/full_description.txt b/androidApp/fastlane/playMetadata/de-DE/full_description.txt similarity index 100% rename from fastlane/playMetadata/de-DE/full_description.txt rename to androidApp/fastlane/playMetadata/de-DE/full_description.txt diff --git a/fastlane/playMetadata/de-DE/images/chromeScreenshots/01-scannedPageScreen_1773392137705.png b/androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/01-scannedPageScreen_1773392137705.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/chromeScreenshots/01-scannedPageScreen_1773392137705.png rename to androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/01-scannedPageScreen_1773392137705.png diff --git a/fastlane/playMetadata/de-DE/images/chromeScreenshots/02-scanSettings_1773392134051.png b/androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/02-scanSettings_1773392134051.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/chromeScreenshots/02-scanSettings_1773392134051.png rename to androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/02-scanSettings_1773392134051.png diff --git a/fastlane/playMetadata/de-DE/images/chromeScreenshots/03-discoveryScreen_1773392134837.png b/androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/03-discoveryScreen_1773392134837.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/chromeScreenshots/03-discoveryScreen_1773392134837.png rename to androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/03-discoveryScreen_1773392134837.png diff --git a/fastlane/playMetadata/de-DE/images/chromeScreenshots/04-emptyScanScreen_1773392136515.png b/androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/04-emptyScanScreen_1773392136515.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/chromeScreenshots/04-emptyScanScreen_1773392136515.png rename to androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/04-emptyScanScreen_1773392136515.png diff --git a/fastlane/playMetadata/de-DE/images/chromeScreenshots/05-settingsScreen_1773392138645.png b/androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/05-settingsScreen_1773392138645.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/chromeScreenshots/05-settingsScreen_1773392138645.png rename to androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/05-settingsScreen_1773392138645.png diff --git a/fastlane/playMetadata/de-DE/images/chromeScreenshots/06-supportScreen_1773392131057.png b/androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/06-supportScreen_1773392131057.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/chromeScreenshots/06-supportScreen_1773392131057.png rename to androidApp/fastlane/playMetadata/de-DE/images/chromeScreenshots/06-supportScreen_1773392131057.png diff --git a/fastlane/playMetadata/de-DE/images/featureGraphic.png b/androidApp/fastlane/playMetadata/de-DE/images/featureGraphic.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/featureGraphic.png rename to androidApp/fastlane/playMetadata/de-DE/images/featureGraphic.png diff --git a/fastlane/playMetadata/de-DE/images/phoneScreenshots/01-scannedPageScreen_1773391854599.png b/androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/01-scannedPageScreen_1773391854599.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/phoneScreenshots/01-scannedPageScreen_1773391854599.png rename to androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/01-scannedPageScreen_1773391854599.png diff --git a/fastlane/playMetadata/de-DE/images/phoneScreenshots/02-scanSettings_1773391851373.png b/androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/02-scanSettings_1773391851373.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/phoneScreenshots/02-scanSettings_1773391851373.png rename to androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/02-scanSettings_1773391851373.png diff --git a/fastlane/playMetadata/de-DE/images/phoneScreenshots/03-discoveryScreen_1773391852033.png b/androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/03-discoveryScreen_1773391852033.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/phoneScreenshots/03-discoveryScreen_1773391852033.png rename to androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/03-discoveryScreen_1773391852033.png diff --git a/fastlane/playMetadata/de-DE/images/phoneScreenshots/04-emptyScanScreen_1773391853682.png b/androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/04-emptyScanScreen_1773391853682.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/phoneScreenshots/04-emptyScanScreen_1773391853682.png rename to androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/04-emptyScanScreen_1773391853682.png diff --git a/fastlane/playMetadata/de-DE/images/phoneScreenshots/05-settingsScreen_1773391855601.png b/androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/05-settingsScreen_1773391855601.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/phoneScreenshots/05-settingsScreen_1773391855601.png rename to androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/05-settingsScreen_1773391855601.png diff --git a/fastlane/playMetadata/de-DE/images/phoneScreenshots/06-supportScreen_1773391848067.png b/androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/06-supportScreen_1773391848067.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/phoneScreenshots/06-supportScreen_1773391848067.png rename to androidApp/fastlane/playMetadata/de-DE/images/phoneScreenshots/06-supportScreen_1773391848067.png diff --git a/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/01-scannedPageScreen_1773392051915.png b/androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/01-scannedPageScreen_1773392051915.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/sevenInchScreenshots/01-scannedPageScreen_1773392051915.png rename to androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/01-scannedPageScreen_1773392051915.png diff --git a/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/02-scanSettings_1773392048636.png b/androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/02-scanSettings_1773392048636.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/sevenInchScreenshots/02-scanSettings_1773392048636.png rename to androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/02-scanSettings_1773392048636.png diff --git a/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/03-discoveryScreen_1773392049419.png b/androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/03-discoveryScreen_1773392049419.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/sevenInchScreenshots/03-discoveryScreen_1773392049419.png rename to androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/03-discoveryScreen_1773392049419.png diff --git a/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/04-emptyScanScreen_1773392051098.png b/androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/04-emptyScanScreen_1773392051098.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/sevenInchScreenshots/04-emptyScanScreen_1773392051098.png rename to androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/04-emptyScanScreen_1773392051098.png diff --git a/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/05-settingsScreen_1773392052967.png b/androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/05-settingsScreen_1773392052967.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/sevenInchScreenshots/05-settingsScreen_1773392052967.png rename to androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/05-settingsScreen_1773392052967.png diff --git a/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/06-supportScreen_1773392044965.png b/androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/06-supportScreen_1773392044965.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/sevenInchScreenshots/06-supportScreen_1773392044965.png rename to androidApp/fastlane/playMetadata/de-DE/images/sevenInchScreenshots/06-supportScreen_1773392044965.png diff --git a/fastlane/playMetadata/de-DE/images/tenInchScreenshots/01-scannedPageScreen_1772541856637.png b/androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/01-scannedPageScreen_1772541856637.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/tenInchScreenshots/01-scannedPageScreen_1772541856637.png rename to androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/01-scannedPageScreen_1772541856637.png diff --git a/fastlane/playMetadata/de-DE/images/tenInchScreenshots/02-scanSettings_1772541853898.png b/androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/02-scanSettings_1772541853898.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/tenInchScreenshots/02-scanSettings_1772541853898.png rename to androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/02-scanSettings_1772541853898.png diff --git a/fastlane/playMetadata/de-DE/images/tenInchScreenshots/03-discoveryScreen_1772541854300.png b/androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/03-discoveryScreen_1772541854300.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/tenInchScreenshots/03-discoveryScreen_1772541854300.png rename to androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/03-discoveryScreen_1772541854300.png diff --git a/fastlane/playMetadata/de-DE/images/tenInchScreenshots/04-emptyScanScreen_1772541855615.png b/androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/04-emptyScanScreen_1772541855615.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/tenInchScreenshots/04-emptyScanScreen_1772541855615.png rename to androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/04-emptyScanScreen_1772541855615.png diff --git a/fastlane/playMetadata/de-DE/images/tenInchScreenshots/05-settingsScreen_1772541857282.png b/androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/05-settingsScreen_1772541857282.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/tenInchScreenshots/05-settingsScreen_1772541857282.png rename to androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/05-settingsScreen_1772541857282.png diff --git a/fastlane/playMetadata/de-DE/images/tenInchScreenshots/06-supportScreen_1772541851562.png b/androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/06-supportScreen_1772541851562.png similarity index 100% rename from fastlane/playMetadata/de-DE/images/tenInchScreenshots/06-supportScreen_1772541851562.png rename to androidApp/fastlane/playMetadata/de-DE/images/tenInchScreenshots/06-supportScreen_1772541851562.png diff --git a/fastlane/playMetadata/de-DE/short_description.txt b/androidApp/fastlane/playMetadata/de-DE/short_description.txt similarity index 100% rename from fastlane/playMetadata/de-DE/short_description.txt rename to androidApp/fastlane/playMetadata/de-DE/short_description.txt diff --git a/fastlane/playMetadata/de-DE/title.txt b/androidApp/fastlane/playMetadata/de-DE/title.txt similarity index 100% rename from fastlane/playMetadata/de-DE/title.txt rename to androidApp/fastlane/playMetadata/de-DE/title.txt diff --git a/fastlane/playMetadata/de-DE/video.txt b/androidApp/fastlane/playMetadata/de-DE/video.txt similarity index 100% rename from fastlane/playMetadata/de-DE/video.txt rename to androidApp/fastlane/playMetadata/de-DE/video.txt diff --git a/fastlane/playMetadata/en-US/changelogs/1006002.txt b/androidApp/fastlane/playMetadata/en-US/changelogs/1006002.txt similarity index 100% rename from fastlane/playMetadata/en-US/changelogs/1006002.txt rename to androidApp/fastlane/playMetadata/en-US/changelogs/1006002.txt diff --git a/fastlane/playMetadata/en-US/changelogs/2000000.txt b/androidApp/fastlane/playMetadata/en-US/changelogs/2000000.txt similarity index 100% rename from fastlane/playMetadata/en-US/changelogs/2000000.txt rename to androidApp/fastlane/playMetadata/en-US/changelogs/2000000.txt diff --git a/fastlane/playMetadata/en-US/changelogs/2000001.txt b/androidApp/fastlane/playMetadata/en-US/changelogs/2000001.txt similarity index 100% rename from fastlane/playMetadata/en-US/changelogs/2000001.txt rename to androidApp/fastlane/playMetadata/en-US/changelogs/2000001.txt diff --git a/fastlane/playMetadata/en-US/changelogs/2001002.txt b/androidApp/fastlane/playMetadata/en-US/changelogs/2001002.txt similarity index 100% rename from fastlane/playMetadata/en-US/changelogs/2001002.txt rename to androidApp/fastlane/playMetadata/en-US/changelogs/2001002.txt diff --git a/fastlane/playMetadata/en-US/changelogs/2001003.txt b/androidApp/fastlane/playMetadata/en-US/changelogs/2001003.txt similarity index 100% rename from fastlane/playMetadata/en-US/changelogs/2001003.txt rename to androidApp/fastlane/playMetadata/en-US/changelogs/2001003.txt diff --git a/fastlane/playMetadata/en-US/changelogs/2001004.txt b/androidApp/fastlane/playMetadata/en-US/changelogs/2001004.txt similarity index 100% rename from fastlane/playMetadata/en-US/changelogs/2001004.txt rename to androidApp/fastlane/playMetadata/en-US/changelogs/2001004.txt diff --git a/fastlane/playMetadata/en-US/full_description.txt b/androidApp/fastlane/playMetadata/en-US/full_description.txt similarity index 100% rename from fastlane/playMetadata/en-US/full_description.txt rename to androidApp/fastlane/playMetadata/en-US/full_description.txt diff --git a/fastlane/playMetadata/en-US/images/chromeScreenshots/01-scannedPageScreen_1773392127266.png b/androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/01-scannedPageScreen_1773392127266.png similarity index 100% rename from fastlane/playMetadata/en-US/images/chromeScreenshots/01-scannedPageScreen_1773392127266.png rename to androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/01-scannedPageScreen_1773392127266.png diff --git a/fastlane/playMetadata/en-US/images/chromeScreenshots/02-scanSettings_1773392124079.png b/androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/02-scanSettings_1773392124079.png similarity index 100% rename from fastlane/playMetadata/en-US/images/chromeScreenshots/02-scanSettings_1773392124079.png rename to androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/02-scanSettings_1773392124079.png diff --git a/fastlane/playMetadata/en-US/images/chromeScreenshots/03-discoveryScreen_1773392124691.png b/androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/03-discoveryScreen_1773392124691.png similarity index 100% rename from fastlane/playMetadata/en-US/images/chromeScreenshots/03-discoveryScreen_1773392124691.png rename to androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/03-discoveryScreen_1773392124691.png diff --git a/fastlane/playMetadata/en-US/images/chromeScreenshots/04-emptyScanScreen_1773392126076.png b/androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/04-emptyScanScreen_1773392126076.png similarity index 100% rename from fastlane/playMetadata/en-US/images/chromeScreenshots/04-emptyScanScreen_1773392126076.png rename to androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/04-emptyScanScreen_1773392126076.png diff --git a/fastlane/playMetadata/en-US/images/chromeScreenshots/05-settingsScreen_1773392128027.png b/androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/05-settingsScreen_1773392128027.png similarity index 100% rename from fastlane/playMetadata/en-US/images/chromeScreenshots/05-settingsScreen_1773392128027.png rename to androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/05-settingsScreen_1773392128027.png diff --git a/fastlane/playMetadata/en-US/images/chromeScreenshots/06-supportScreen_1773392121020.png b/androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/06-supportScreen_1773392121020.png similarity index 100% rename from fastlane/playMetadata/en-US/images/chromeScreenshots/06-supportScreen_1773392121020.png rename to androidApp/fastlane/playMetadata/en-US/images/chromeScreenshots/06-supportScreen_1773392121020.png diff --git a/fastlane/playMetadata/en-US/images/featureGraphic.png b/androidApp/fastlane/playMetadata/en-US/images/featureGraphic.png similarity index 100% rename from fastlane/playMetadata/en-US/images/featureGraphic.png rename to androidApp/fastlane/playMetadata/en-US/images/featureGraphic.png diff --git a/fastlane/playMetadata/en-US/images/icon.png b/androidApp/fastlane/playMetadata/en-US/images/icon.png similarity index 100% rename from fastlane/playMetadata/en-US/images/icon.png rename to androidApp/fastlane/playMetadata/en-US/images/icon.png diff --git a/fastlane/playMetadata/en-US/images/phoneScreenshots/01-scannedPageScreen_1773391844501.png b/androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/01-scannedPageScreen_1773391844501.png similarity index 100% rename from fastlane/playMetadata/en-US/images/phoneScreenshots/01-scannedPageScreen_1773391844501.png rename to androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/01-scannedPageScreen_1773391844501.png diff --git a/fastlane/playMetadata/en-US/images/phoneScreenshots/02-scanSettings_1773391841799.png b/androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/02-scanSettings_1773391841799.png similarity index 100% rename from fastlane/playMetadata/en-US/images/phoneScreenshots/02-scanSettings_1773391841799.png rename to androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/02-scanSettings_1773391841799.png diff --git a/fastlane/playMetadata/en-US/images/phoneScreenshots/03-discoveryScreen_1773391842230.png b/androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/03-discoveryScreen_1773391842230.png similarity index 100% rename from fastlane/playMetadata/en-US/images/phoneScreenshots/03-discoveryScreen_1773391842230.png rename to androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/03-discoveryScreen_1773391842230.png diff --git a/fastlane/playMetadata/en-US/images/phoneScreenshots/04-emptyScanScreen_1773391843467.png b/androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/04-emptyScanScreen_1773391843467.png similarity index 100% rename from fastlane/playMetadata/en-US/images/phoneScreenshots/04-emptyScanScreen_1773391843467.png rename to androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/04-emptyScanScreen_1773391843467.png diff --git a/fastlane/playMetadata/en-US/images/phoneScreenshots/05-settingsScreen_1773391845183.png b/androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/05-settingsScreen_1773391845183.png similarity index 100% rename from fastlane/playMetadata/en-US/images/phoneScreenshots/05-settingsScreen_1773391845183.png rename to androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/05-settingsScreen_1773391845183.png diff --git a/fastlane/playMetadata/en-US/images/phoneScreenshots/06-supportScreen_1773391839216.png b/androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/06-supportScreen_1773391839216.png similarity index 100% rename from fastlane/playMetadata/en-US/images/phoneScreenshots/06-supportScreen_1773391839216.png rename to androidApp/fastlane/playMetadata/en-US/images/phoneScreenshots/06-supportScreen_1773391839216.png diff --git a/fastlane/playMetadata/en-US/images/sevenInchScreenshots/01-scannedPageScreen_1773392041217.png b/androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/01-scannedPageScreen_1773392041217.png similarity index 100% rename from fastlane/playMetadata/en-US/images/sevenInchScreenshots/01-scannedPageScreen_1773392041217.png rename to androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/01-scannedPageScreen_1773392041217.png diff --git a/fastlane/playMetadata/en-US/images/sevenInchScreenshots/02-scanSettings_1773392038538.png b/androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/02-scanSettings_1773392038538.png similarity index 100% rename from fastlane/playMetadata/en-US/images/sevenInchScreenshots/02-scanSettings_1773392038538.png rename to androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/02-scanSettings_1773392038538.png diff --git a/fastlane/playMetadata/en-US/images/sevenInchScreenshots/03-discoveryScreen_1773392039016.png b/androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/03-discoveryScreen_1773392039016.png similarity index 100% rename from fastlane/playMetadata/en-US/images/sevenInchScreenshots/03-discoveryScreen_1773392039016.png rename to androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/03-discoveryScreen_1773392039016.png diff --git a/fastlane/playMetadata/en-US/images/sevenInchScreenshots/04-emptyScanScreen_1773392040264.png b/androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/04-emptyScanScreen_1773392040264.png similarity index 100% rename from fastlane/playMetadata/en-US/images/sevenInchScreenshots/04-emptyScanScreen_1773392040264.png rename to androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/04-emptyScanScreen_1773392040264.png diff --git a/fastlane/playMetadata/en-US/images/sevenInchScreenshots/05-settingsScreen_1773392041800.png b/androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/05-settingsScreen_1773392041800.png similarity index 100% rename from fastlane/playMetadata/en-US/images/sevenInchScreenshots/05-settingsScreen_1773392041800.png rename to androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/05-settingsScreen_1773392041800.png diff --git a/fastlane/playMetadata/en-US/images/sevenInchScreenshots/06-supportScreen_1773392036000.png b/androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/06-supportScreen_1773392036000.png similarity index 100% rename from fastlane/playMetadata/en-US/images/sevenInchScreenshots/06-supportScreen_1773392036000.png rename to androidApp/fastlane/playMetadata/en-US/images/sevenInchScreenshots/06-supportScreen_1773392036000.png diff --git a/fastlane/playMetadata/en-US/images/tenInchScreenshots/01-scannedPageScreen_1772541846501.png b/androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/01-scannedPageScreen_1772541846501.png similarity index 100% rename from fastlane/playMetadata/en-US/images/tenInchScreenshots/01-scannedPageScreen_1772541846501.png rename to androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/01-scannedPageScreen_1772541846501.png diff --git a/fastlane/playMetadata/en-US/images/tenInchScreenshots/02-scanSettings_1772541839135.png b/androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/02-scanSettings_1772541839135.png similarity index 100% rename from fastlane/playMetadata/en-US/images/tenInchScreenshots/02-scanSettings_1772541839135.png rename to androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/02-scanSettings_1772541839135.png diff --git a/fastlane/playMetadata/en-US/images/tenInchScreenshots/03-discoveryScreen_1772541841584.png b/androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/03-discoveryScreen_1772541841584.png similarity index 100% rename from fastlane/playMetadata/en-US/images/tenInchScreenshots/03-discoveryScreen_1772541841584.png rename to androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/03-discoveryScreen_1772541841584.png diff --git a/fastlane/playMetadata/en-US/images/tenInchScreenshots/04-emptyScanScreen_1772541845528.png b/androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/04-emptyScanScreen_1772541845528.png similarity index 100% rename from fastlane/playMetadata/en-US/images/tenInchScreenshots/04-emptyScanScreen_1772541845528.png rename to androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/04-emptyScanScreen_1772541845528.png diff --git a/fastlane/playMetadata/en-US/images/tenInchScreenshots/05-settingsScreen_1772541849182.png b/androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/05-settingsScreen_1772541849182.png similarity index 100% rename from fastlane/playMetadata/en-US/images/tenInchScreenshots/05-settingsScreen_1772541849182.png rename to androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/05-settingsScreen_1772541849182.png diff --git a/fastlane/playMetadata/en-US/images/tenInchScreenshots/06-supportScreen_1772541835912.png b/androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/06-supportScreen_1772541835912.png similarity index 100% rename from fastlane/playMetadata/en-US/images/tenInchScreenshots/06-supportScreen_1772541835912.png rename to androidApp/fastlane/playMetadata/en-US/images/tenInchScreenshots/06-supportScreen_1772541835912.png diff --git a/fastlane/playMetadata/en-US/short_description.txt b/androidApp/fastlane/playMetadata/en-US/short_description.txt similarity index 100% rename from fastlane/playMetadata/en-US/short_description.txt rename to androidApp/fastlane/playMetadata/en-US/short_description.txt diff --git a/fastlane/playMetadata/en-US/title.txt b/androidApp/fastlane/playMetadata/en-US/title.txt similarity index 100% rename from fastlane/playMetadata/en-US/title.txt rename to androidApp/fastlane/playMetadata/en-US/title.txt diff --git a/fastlane/playMetadata/en-US/video.txt b/androidApp/fastlane/playMetadata/en-US/video.txt similarity index 100% rename from fastlane/playMetadata/en-US/video.txt rename to androidApp/fastlane/playMetadata/en-US/video.txt diff --git a/fastlane/playMetadata/it-IT/changelogs/1006002.txt b/androidApp/fastlane/playMetadata/it-IT/changelogs/1006002.txt similarity index 100% rename from fastlane/playMetadata/it-IT/changelogs/1006002.txt rename to androidApp/fastlane/playMetadata/it-IT/changelogs/1006002.txt diff --git a/fastlane/playMetadata/it-IT/changelogs/2000000.txt b/androidApp/fastlane/playMetadata/it-IT/changelogs/2000000.txt similarity index 100% rename from fastlane/playMetadata/it-IT/changelogs/2000000.txt rename to androidApp/fastlane/playMetadata/it-IT/changelogs/2000000.txt diff --git a/fastlane/playMetadata/it-IT/changelogs/2000001.txt b/androidApp/fastlane/playMetadata/it-IT/changelogs/2000001.txt similarity index 100% rename from fastlane/playMetadata/it-IT/changelogs/2000001.txt rename to androidApp/fastlane/playMetadata/it-IT/changelogs/2000001.txt diff --git a/fastlane/playMetadata/it-IT/changelogs/2001002.txt b/androidApp/fastlane/playMetadata/it-IT/changelogs/2001002.txt similarity index 100% rename from fastlane/playMetadata/it-IT/changelogs/2001002.txt rename to androidApp/fastlane/playMetadata/it-IT/changelogs/2001002.txt diff --git a/fastlane/playMetadata/it-IT/changelogs/2001003.txt b/androidApp/fastlane/playMetadata/it-IT/changelogs/2001003.txt similarity index 100% rename from fastlane/playMetadata/it-IT/changelogs/2001003.txt rename to androidApp/fastlane/playMetadata/it-IT/changelogs/2001003.txt diff --git a/fastlane/playMetadata/it-IT/changelogs/2001004.txt b/androidApp/fastlane/playMetadata/it-IT/changelogs/2001004.txt similarity index 100% rename from fastlane/playMetadata/it-IT/changelogs/2001004.txt rename to androidApp/fastlane/playMetadata/it-IT/changelogs/2001004.txt diff --git a/fastlane/playMetadata/it-IT/full_description.txt b/androidApp/fastlane/playMetadata/it-IT/full_description.txt similarity index 100% rename from fastlane/playMetadata/it-IT/full_description.txt rename to androidApp/fastlane/playMetadata/it-IT/full_description.txt diff --git a/fastlane/playMetadata/it-IT/images/chromeScreenshots/01-scannedPageScreen_1773392147446.png b/androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/01-scannedPageScreen_1773392147446.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/chromeScreenshots/01-scannedPageScreen_1773392147446.png rename to androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/01-scannedPageScreen_1773392147446.png diff --git a/fastlane/playMetadata/it-IT/images/chromeScreenshots/02-scanSettings_1773392144173.png b/androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/02-scanSettings_1773392144173.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/chromeScreenshots/02-scanSettings_1773392144173.png rename to androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/02-scanSettings_1773392144173.png diff --git a/fastlane/playMetadata/it-IT/images/chromeScreenshots/03-discoveryScreen_1773392144879.png b/androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/03-discoveryScreen_1773392144879.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/chromeScreenshots/03-discoveryScreen_1773392144879.png rename to androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/03-discoveryScreen_1773392144879.png diff --git a/fastlane/playMetadata/it-IT/images/chromeScreenshots/04-emptyScanScreen_1773392146388.png b/androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/04-emptyScanScreen_1773392146388.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/chromeScreenshots/04-emptyScanScreen_1773392146388.png rename to androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/04-emptyScanScreen_1773392146388.png diff --git a/fastlane/playMetadata/it-IT/images/chromeScreenshots/05-settingsScreen_1773392148380.png b/androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/05-settingsScreen_1773392148380.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/chromeScreenshots/05-settingsScreen_1773392148380.png rename to androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/05-settingsScreen_1773392148380.png diff --git a/fastlane/playMetadata/it-IT/images/chromeScreenshots/06-supportScreen_1773392140988.png b/androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/06-supportScreen_1773392140988.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/chromeScreenshots/06-supportScreen_1773392140988.png rename to androidApp/fastlane/playMetadata/it-IT/images/chromeScreenshots/06-supportScreen_1773392140988.png diff --git a/fastlane/playMetadata/it-IT/images/featureGraphic.png b/androidApp/fastlane/playMetadata/it-IT/images/featureGraphic.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/featureGraphic.png rename to androidApp/fastlane/playMetadata/it-IT/images/featureGraphic.png diff --git a/fastlane/playMetadata/it-IT/images/phoneScreenshots/01-scannedPageScreen_1773391864832.png b/androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/01-scannedPageScreen_1773391864832.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/phoneScreenshots/01-scannedPageScreen_1773391864832.png rename to androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/01-scannedPageScreen_1773391864832.png diff --git a/fastlane/playMetadata/it-IT/images/phoneScreenshots/02-scanSettings_1773391861554.png b/androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/02-scanSettings_1773391861554.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/phoneScreenshots/02-scanSettings_1773391861554.png rename to androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/02-scanSettings_1773391861554.png diff --git a/fastlane/playMetadata/it-IT/images/phoneScreenshots/03-discoveryScreen_1773391862266.png b/androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/03-discoveryScreen_1773391862266.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/phoneScreenshots/03-discoveryScreen_1773391862266.png rename to androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/03-discoveryScreen_1773391862266.png diff --git a/fastlane/playMetadata/it-IT/images/phoneScreenshots/04-emptyScanScreen_1773391863833.png b/androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/04-emptyScanScreen_1773391863833.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/phoneScreenshots/04-emptyScanScreen_1773391863833.png rename to androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/04-emptyScanScreen_1773391863833.png diff --git a/fastlane/playMetadata/it-IT/images/phoneScreenshots/05-settingsScreen_1773391865784.png b/androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/05-settingsScreen_1773391865784.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/phoneScreenshots/05-settingsScreen_1773391865784.png rename to androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/05-settingsScreen_1773391865784.png diff --git a/fastlane/playMetadata/it-IT/images/phoneScreenshots/06-supportScreen_1773391858142.png b/androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/06-supportScreen_1773391858142.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/phoneScreenshots/06-supportScreen_1773391858142.png rename to androidApp/fastlane/playMetadata/it-IT/images/phoneScreenshots/06-supportScreen_1773391858142.png diff --git a/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/01-scannedPageScreen_1773392064698.png b/androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/01-scannedPageScreen_1773392064698.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/sevenInchScreenshots/01-scannedPageScreen_1773392064698.png rename to androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/01-scannedPageScreen_1773392064698.png diff --git a/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/02-scanSettings_1773392060668.png b/androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/02-scanSettings_1773392060668.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/sevenInchScreenshots/02-scanSettings_1773392060668.png rename to androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/02-scanSettings_1773392060668.png diff --git a/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/03-discoveryScreen_1773392062139.png b/androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/03-discoveryScreen_1773392062139.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/sevenInchScreenshots/03-discoveryScreen_1773392062139.png rename to androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/03-discoveryScreen_1773392062139.png diff --git a/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/04-emptyScanScreen_1773392063851.png b/androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/04-emptyScanScreen_1773392063851.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/sevenInchScreenshots/04-emptyScanScreen_1773392063851.png rename to androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/04-emptyScanScreen_1773392063851.png diff --git a/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/05-settingsScreen_1773392065789.png b/androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/05-settingsScreen_1773392065789.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/sevenInchScreenshots/05-settingsScreen_1773392065789.png rename to androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/05-settingsScreen_1773392065789.png diff --git a/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/06-supportScreen_1773392056702.png b/androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/06-supportScreen_1773392056702.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/sevenInchScreenshots/06-supportScreen_1773392056702.png rename to androidApp/fastlane/playMetadata/it-IT/images/sevenInchScreenshots/06-supportScreen_1773392056702.png diff --git a/fastlane/playMetadata/it-IT/images/tenInchScreenshots/01-scannedPageScreen_1772541871263.png b/androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/01-scannedPageScreen_1772541871263.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/tenInchScreenshots/01-scannedPageScreen_1772541871263.png rename to androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/01-scannedPageScreen_1772541871263.png diff --git a/fastlane/playMetadata/it-IT/images/tenInchScreenshots/02-scanSettings_1772541864073.png b/androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/02-scanSettings_1772541864073.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/tenInchScreenshots/02-scanSettings_1772541864073.png rename to androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/02-scanSettings_1772541864073.png diff --git a/fastlane/playMetadata/it-IT/images/tenInchScreenshots/03-discoveryScreen_1772541866487.png b/androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/03-discoveryScreen_1772541866487.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/tenInchScreenshots/03-discoveryScreen_1772541866487.png rename to androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/03-discoveryScreen_1772541866487.png diff --git a/fastlane/playMetadata/it-IT/images/tenInchScreenshots/04-emptyScanScreen_1772541870383.png b/androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/04-emptyScanScreen_1772541870383.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/tenInchScreenshots/04-emptyScanScreen_1772541870383.png rename to androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/04-emptyScanScreen_1772541870383.png diff --git a/fastlane/playMetadata/it-IT/images/tenInchScreenshots/05-settingsScreen_1772541873928.png b/androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/05-settingsScreen_1772541873928.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/tenInchScreenshots/05-settingsScreen_1772541873928.png rename to androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/05-settingsScreen_1772541873928.png diff --git a/fastlane/playMetadata/it-IT/images/tenInchScreenshots/06-supportScreen_1772541861315.png b/androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/06-supportScreen_1772541861315.png similarity index 100% rename from fastlane/playMetadata/it-IT/images/tenInchScreenshots/06-supportScreen_1772541861315.png rename to androidApp/fastlane/playMetadata/it-IT/images/tenInchScreenshots/06-supportScreen_1772541861315.png diff --git a/fastlane/playMetadata/it-IT/short_description.txt b/androidApp/fastlane/playMetadata/it-IT/short_description.txt similarity index 100% rename from fastlane/playMetadata/it-IT/short_description.txt rename to androidApp/fastlane/playMetadata/it-IT/short_description.txt diff --git a/fastlane/playMetadata/it-IT/title.txt b/androidApp/fastlane/playMetadata/it-IT/title.txt similarity index 100% rename from fastlane/playMetadata/it-IT/title.txt rename to androidApp/fastlane/playMetadata/it-IT/title.txt diff --git a/fastlane/playMetadata/it-IT/video.txt b/androidApp/fastlane/playMetadata/it-IT/video.txt similarity index 100% rename from fastlane/playMetadata/it-IT/video.txt rename to androidApp/fastlane/playMetadata/it-IT/video.txt diff --git a/fastlane/playMetadata/screenshots.html b/androidApp/fastlane/playMetadata/screenshots.html similarity index 100% rename from fastlane/playMetadata/screenshots.html rename to androidApp/fastlane/playMetadata/screenshots.html diff --git a/androidApp/gradle/gradle-daemon-jvm.properties b/androidApp/gradle/gradle-daemon-jvm.properties new file mode 100644 index 00000000..c4e7acbd --- /dev/null +++ b/androidApp/gradle/gradle-daemon-jvm.properties @@ -0,0 +1,13 @@ +#This file is generated by updateDaemonJvm +toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/29ee363f71d060405f729a8f1b7f7aef/redirect +toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/67a0fee3c4236b6397dcbe8575ca2011/redirect +toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect +toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/67a0fee3c4236b6397dcbe8575ca2011/redirect +toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/0b98aec810298c2c1d7fdac5dac37910/redirect +toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/658299a896470fbb3103ba3a430ee227/redirect +toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/29ee363f71d060405f729a8f1b7f7aef/redirect +toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/67a0fee3c4236b6397dcbe8575ca2011/redirect +toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/248ffb1098f61659502d0c09aa348294/redirect +toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/ac151d55def6b6a9a159dc4cb4642851/redirect +toolchainVendor=JETBRAINS +toolchainVersion=21 diff --git a/androidApp/gradle/libs.versions.toml b/androidApp/gradle/libs.versions.toml new file mode 100644 index 00000000..e546184f --- /dev/null +++ b/androidApp/gradle/libs.versions.toml @@ -0,0 +1,100 @@ +[versions] +agp = "9.1.0" +coilCompose = "3.3.0" +constraintlayoutCompose = "1.1.1" +datastore = "1.2.0" +esclkt = "2.0.6" +escl-mock-server = "1.0.1" +itextCore = "9.3.0" +kotlin = "2.3.20-Beta1" +coreKtx = "1.17.0" +junit = "4.13.2" +junitVersion = "1.3.0" +espressoCore = "3.7.0" +kotlinReflect = "2.1.20" +kotlinxSerializationJson = "1.9.0" +lifecycleRuntimeKtx = "2.9.4" +activityCompose = "1.11.0" +composeBom = "2025.10.00" +room = "2.8.4" +timber = "5.0.1" +zoomable = "0.18.0" +material3 = "1.5.0-alpha06" +materialIcons = "1.7.8" +navigationCompose = "2.9.5" +versionsPlugin = "0.53.0" +screengrab = "2.1.1" +ktor = "3.4.0" +koin = "4.2.0-RC1" +koin-plugin = "0.3.0" +protobuf-plugin = "0.9.6" +protobuf-kotlin-lite = "4.33.5" +rules = "1.7.0" + +[libraries] + +androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" } + +androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } +androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } +androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } + +koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } +koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin" } +koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin" } +koin-test-junit4 = { module = "io.insert-koin:koin-test-junit4", version.ref = "koin" } + +# Android +koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } +koin-android-test = { module = "io.insert-koin:koin-android-test", version.ref = "koin" } + +koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin"} + +koin-androix-navigation = { module = "io.insert-koin:koin-androidx-compose-navigation", version.ref = "koin"} + +# Compose +koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin" } +koin-compose-viewmodel-navigation = { module = "io.insert-koin:koin-compose-viewmodel-navigation", version.ref = "koin" } +koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" } + +ktor-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor"} +ktor-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor"} +androidx-constraintlayout-compose = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "constraintlayoutCompose" } +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" } +androidx-material-icons-core = { module = "androidx.compose.material:material-icons-core" , version.ref = "materialIcons"} +androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" } +coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coilCompose" } +esclkt = { module = "io.github.chrisimx:esclkt", version.ref = "esclkt" } +itext7-core = { module = "com.itextpdf:itext-core", version.ref = "itextCore" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } +kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlinReflect" } +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } +screengrab = { module = "tools.fastlane:screengrab", version.ref = "screengrab" } +timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } +zoomable = { module = "me.saket.telephoto:zoomable", version.ref = "zoomable" } +protobuf-kotlin-lite = { module = "com.google.protobuf:protobuf-kotlin-lite", version.ref = "protobuf-kotlin-lite"} +androidx-rules = { group = "androidx.test", name = "rules", version.ref = "rules" } + +escl-mock-server = { module = "io.github.chrisimx:escl-mock-server", version.ref = "escl-mock-server"} + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +versions = { id = "com.github.ben-manes.versions", version.ref = "versionsPlugin" } +koin = { id = "io.insert-koin.compiler.plugin", version.ref = "koin-plugin" } +protobuf = { id = "com.google.protobuf", version.ref = "protobuf-plugin" } +room = { id = "androidx.room", version.ref = "room"} \ No newline at end of file diff --git a/app/proguard-rules.pro b/androidApp/proguard-rules.pro similarity index 100% rename from app/proguard-rules.pro rename to androidApp/proguard-rules.pro diff --git a/app/src/androidTest/assets/scan-1.jpg b/androidApp/src/androidTest/assets/scan-1.jpg similarity index 100% rename from app/src/androidTest/assets/scan-1.jpg rename to androidApp/src/androidTest/assets/scan-1.jpg diff --git a/app/src/androidTest/java/io/github/chrisimx/scanbridge/ScanBridgeNavHost.kt b/androidApp/src/androidTest/java/io/github/chrisimx/scanbridge/ScanBridgeNavHost.kt similarity index 100% rename from app/src/androidTest/java/io/github/chrisimx/scanbridge/ScanBridgeNavHost.kt rename to androidApp/src/androidTest/java/io/github/chrisimx/scanbridge/ScanBridgeNavHost.kt diff --git a/app/src/androidTest/java/io/github/chrisimx/scanbridge/ScanBridgeTest.kt b/androidApp/src/androidTest/java/io/github/chrisimx/scanbridge/ScanBridgeTest.kt similarity index 100% rename from app/src/androidTest/java/io/github/chrisimx/scanbridge/ScanBridgeTest.kt rename to androidApp/src/androidTest/java/io/github/chrisimx/scanbridge/ScanBridgeTest.kt diff --git a/app/src/androidTest/java/io/github/chrisimx/scanbridge/screenshot/ScanBridgeScreenshotTest.kt b/androidApp/src/androidTest/java/io/github/chrisimx/scanbridge/screenshot/ScanBridgeScreenshotTest.kt similarity index 100% rename from app/src/androidTest/java/io/github/chrisimx/scanbridge/screenshot/ScanBridgeScreenshotTest.kt rename to androidApp/src/androidTest/java/io/github/chrisimx/scanbridge/screenshot/ScanBridgeScreenshotTest.kt diff --git a/app/src/debug/AndroidManifest.xml b/androidApp/src/debug/AndroidManifest.xml similarity index 100% rename from app/src/debug/AndroidManifest.xml rename to androidApp/src/debug/AndroidManifest.xml diff --git a/app/src/fdroid/java/io/github/chrisimx/scanbridge/StartupTabDefinitions.kt b/androidApp/src/fdroid/java/io/github/chrisimx/scanbridge/StartupTabDefinitions.kt similarity index 100% rename from app/src/fdroid/java/io/github/chrisimx/scanbridge/StartupTabDefinitions.kt rename to androidApp/src/fdroid/java/io/github/chrisimx/scanbridge/StartupTabDefinitions.kt diff --git a/app/src/main/AndroidManifest.xml b/androidApp/src/main/AndroidManifest.xml similarity index 100% rename from app/src/main/AndroidManifest.xml rename to androidApp/src/main/AndroidManifest.xml diff --git a/app/src/main/ic_launcher-playstore.png b/androidApp/src/main/ic_launcher-playstore.png similarity index 100% rename from app/src/main/ic_launcher-playstore.png rename to androidApp/src/main/ic_launcher-playstore.png diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/AppSettingsScreen.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/AppSettingsScreen.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/AppSettingsScreen.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/AppSettingsScreen.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/CrashActivity.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/CrashActivity.kt similarity index 97% rename from app/src/main/java/io/github/chrisimx/scanbridge/CrashActivity.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/CrashActivity.kt index 981beed2..01a16386 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/CrashActivity.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/CrashActivity.kt @@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -28,7 +27,6 @@ import io.github.chrisimx.scanbridge.theme.ScanBridgeTheme import timber.log.Timber class CrashActivity : ComponentActivity() { - @OptIn(ExperimentalMaterial3ExpressiveApi::class) override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() super.onCreate(savedInstanceState) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/CrashHandler.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/CrashHandler.kt similarity index 89% rename from app/src/main/java/io/github/chrisimx/scanbridge/CrashHandler.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/CrashHandler.kt index 8d0eae94..76f02afc 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/CrashHandler.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/CrashHandler.kt @@ -21,15 +21,13 @@ package io.github.chrisimx.scanbridge import android.content.Context import android.content.Intent -import io.github.chrisimx.scanbridge.datastore.lastRouteStore -import io.github.chrisimx.scanbridge.proto.copy import java.io.File import java.time.LocalDateTime import java.time.format.DateTimeFormatter import kotlinx.coroutines.runBlocking import timber.log.Timber -class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler { +class CrashHandler(val context: Context, val lastRouteRepository: LastRouteRepository) : Thread.UncaughtExceptionHandler { private val defaultHandler = Thread.getDefaultUncaughtExceptionHandler() @@ -71,10 +69,6 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler { } suspend fun deleteStoredRoute() { - context.lastRouteStore.updateData { - it.copy { - clearLastRoute() - } - } + lastRouteRepository.setLastRoute(null) } } diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/CropScreen.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/CropScreen.kt similarity index 96% rename from app/src/main/java/io/github/chrisimx/scanbridge/CropScreen.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/CropScreen.kt index 36597ab0..601e70f5 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/CropScreen.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/CropScreen.kt @@ -6,7 +6,6 @@ import androidx.compose.animation.core.snap import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.FabPosition import androidx.compose.material3.Icon @@ -43,7 +42,6 @@ import kotlin.uuid.Uuid import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import me.saket.telephoto.ExperimentalTelephotoApi import me.saket.telephoto.zoomable.EnabledZoomGestures import me.saket.telephoto.zoomable.ZoomSpec import me.saket.telephoto.zoomable.rememberZoomableState @@ -69,7 +67,7 @@ suspend fun finishCrop(cropRect: Rect, file: String): File? = withContext(Dispat return@withContext croppedFile } -@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalTelephotoApi::class) +// TODO: @OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalTelephotoApi::class) @Composable fun CropScreen(scanId: Uuid, returnRoute: BaseRoute, navController: NavController) { val context = LocalContext.current diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/MainActivity.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/MainActivity.kt similarity index 96% rename from app/src/main/java/io/github/chrisimx/scanbridge/MainActivity.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/MainActivity.kt index decde6da..53ebbaed 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/MainActivity.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/MainActivity.kt @@ -31,6 +31,7 @@ import java.io.File import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import org.koin.android.ext.android.get import org.koin.android.ext.android.inject import org.koin.android.scope.AndroidScopeComponent import org.koin.androidx.scope.activityScope @@ -41,6 +42,7 @@ class MainActivity : ComponentActivity(), AndroidScopeComponent { private val localeProvider: AndroidLocaleProvider by inject() + private val crashHandler: Thread.UncaughtExceptionHandler by inject() override val scope: Scope by activityScope() @@ -52,7 +54,7 @@ class MainActivity : } override fun onCreate(savedInstanceState: Bundle?) { - Thread.setDefaultUncaughtExceptionHandler(CrashHandler(this.applicationContext)) + Thread.setDefaultUncaughtExceptionHandler(crashHandler) enableEdgeToEdge() super.onCreate(savedInstanceState) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApp.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApp.kt similarity index 76% rename from app/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApp.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApp.kt index 50578717..c32b116a 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApp.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApp.kt @@ -23,8 +23,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Favorite import androidx.compose.material3.AlertDialog -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -44,35 +42,37 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController -import com.google.protobuf.StringValue -import io.github.chrisimx.scanbridge.datastore.lastRouteStore -import io.github.chrisimx.scanbridge.datastore.shownMessagesStore -import io.github.chrisimx.scanbridge.proto.copy -import io.github.chrisimx.scanbridge.proto.lastRouteOrNull import io.github.chrisimx.scanbridge.theme.ScanBridgeTheme import io.github.chrisimx.scanbridge.uicomponents.CrashFileHandler -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json +import org.koin.compose.koinInject +import org.koin.core.parameter.parametersOf import timber.log.Timber -@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun ScanBridgeApp() { ScanBridgeTheme { val navController = rememberNavController() var startDestination: Any? by remember { mutableStateOf(null) } val context = LocalContext.current + val coroutineScope = rememberCoroutineScope() val currentBackStackEntry by navController.currentBackStackEntryAsState() val typedRoute = currentBackStackEntry?.toTypedRoute() + val lastRouteRepository = koinInject() + val shownMessagesRepository = koinInject { + parametersOf(coroutineScope) + } + + val thanksForPurchaseAlreadyShown by shownMessagesRepository + .getWasShownFlow(UserInformationMessage.THANKS_FOR_PURCHASE) + .collectAsState(true) + LaunchedEffect(Unit) { Timber.d("Loading last route from shared preferences") - val lastRoute = context.lastRouteStore.data.firstOrNull()?.lastRouteOrNull?.value + val lastRoute = lastRouteRepository.getLastRoute() if (lastRoute != null) { try { Timber.d("Last route found: $lastRoute") @@ -95,35 +95,17 @@ fun ScanBridgeApp() { val json = Json.encodeToString(route) Timber.d("Route saved as: $json") - context.lastRouteStore.updateData { - it.copy { - lastRoute = StringValue.of(json) - } - } + lastRouteRepository.setLastRoute(json) } } - val playThankShouldBeShown by remember { - context.shownMessagesStore.data.map { - BuildConfig.FLAVOR == "play" && !it.thankPlayOne - } - }.collectAsState(false) - - val coroutineScope = rememberCoroutineScope() - val markThanksMessageAsRead = { coroutineScope.launch { - withContext(Dispatchers.IO) { - context.shownMessagesStore.updateData { - it.copy { - thankPlayOne = true - } - } - } + shownMessagesRepository.setShown(UserInformationMessage.THANKS_FOR_PURCHASE, true) } } - if (playThankShouldBeShown) { + if (!thanksForPurchaseAlreadyShown) { AlertDialog( { markThanksMessageAsRead() diff --git a/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApplication.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApplication.kt new file mode 100644 index 00000000..bd8e67da --- /dev/null +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApplication.kt @@ -0,0 +1,104 @@ +package io.github.chrisimx.scanbridge + +import AndroidHttpClientFactory +import AndroidScanBridgeDbBuilderFactory +import android.app.Application +import android.content.Context +import androidx.datastore.core.DataStore +import io.github.chrisimx.scanbridge.data.ui.CustomScannerViewModel +import io.github.chrisimx.scanbridge.data.ui.ScanSettingsComposableStateHolder +import io.github.chrisimx.scanbridge.data.ui.ScanningScreenViewModel +import io.github.chrisimx.scanbridge.datastore.appSettingsStore +import io.github.chrisimx.scanbridge.datastore.shownMessagesStore +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.infrastructure.KmLogScanBridgeLoggerFactory +import io.github.chrisimx.scanbridge.migrations.MigrationExecutor +import io.github.chrisimx.scanbridge.migrations.RoomBackedMigrationExecutor +import io.github.chrisimx.scanbridge.migrations.migrationsModule +import io.github.chrisimx.scanbridge.ports.HttpClientFactory +import io.github.chrisimx.scanbridge.ports.LocaleProvider +import io.github.chrisimx.scanbridge.ports.ScanBridgeLoggerFactory +import io.github.chrisimx.scanbridge.proto.ScanBridgeSettings +import io.github.chrisimx.scanbridge.proto.ShownMessages +import io.github.chrisimx.scanbridge.repositories.DatastoreLastRouteRepository +import io.github.chrisimx.scanbridge.repositories.DatastoreShownMessagesRepository +import io.github.chrisimx.scanbridge.repositories.RoomLastRouteRepository +import io.github.chrisimx.scanbridge.services.AndroidLocaleProvider +import io.github.chrisimx.scanbridge.services.DebugLogService +import io.github.chrisimx.scanbridge.services.FileDebugLogService +import io.github.chrisimx.scanbridge.services.ScanJobRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.startKoin +import org.koin.core.qualifier.named +import org.koin.dsl.bind +import org.koin.dsl.module +import org.koin.mp.KoinPlatform.getKoin +import org.koin.plugin.module.dsl.create +import org.koin.plugin.module.dsl.factory +import org.koin.plugin.module.dsl.single +import org.koin.plugin.module.dsl.viewModel +import timber.log.Timber + +fun createAppSettingsDataStore(context: Context) = context.appSettingsStore +fun createShownMessagesDataStore(context: Context) = context.shownMessagesStore + +fun createScanBridgeDb(factory: ScanBridgeDbFactory): ScanBridgeDb = factory.createInstance() +val appModule = module { + single>(named()) { + create(::createShownMessagesDataStore) + } + single>(named()) { + create(::createAppSettingsDataStore) + } + single() bind Thread.UncaughtExceptionHandler::class + single() bind LocaleProvider::class + single { + FileDebugLogService(get(named()), get()) + } bind DebugLogService::class + single() bind HttpClientFactory::class + single() bind ScanBridgeLoggerFactory::class + single() + single() bind MigrationExecutor::class + includes(migrationsModule) + single() bind ScanBridgeDbBuilderFactory::class + single() bind ScanBridgeDbFactory::class + single { + create(::createScanBridgeDb) + } + single() + single() bind LastRouteRepository::class + single { (scope: CoroutineScope) -> + DatastoreShownMessagesRepository(get(named()), scope) + } bind ShownMessagesRepository::class + factory() + viewModel() + viewModel() +} + +class ScanBridgeApplication : Application() { + override fun onCreate() { + super.onCreate() + startKoin { + androidContext(this@ScanBridgeApplication) + modules(appModule) + } + + Timber.plant(Timber.DebugTree()) + + runMigrations() + } + + fun runMigrations() { + val coroutineScope = CoroutineScope(Dispatchers.IO) + val migrationExecutor = getKoin().get() + coroutineScope.launch { + migrationExecutor.runMigrations() + } + } +} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeNavHost.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeNavHost.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeNavHost.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeNavHost.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/ScanSettings.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanSettings.kt similarity index 99% rename from app/src/main/java/io/github/chrisimx/scanbridge/ScanSettings.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanSettings.kt index e891892d..fefdf13f 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/ScanSettings.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanSettings.kt @@ -56,9 +56,9 @@ import androidx.compose.ui.unit.dp import io.github.chrisimx.esclkt.DiscreteResolution import io.github.chrisimx.esclkt.SupportedResolutions import io.github.chrisimx.esclkt.equalsLength -import io.github.chrisimx.scanbridge.data.ui.NumberValidationResult import io.github.chrisimx.scanbridge.data.ui.ScanSettingsComposableStateHolder import io.github.chrisimx.scanbridge.data.ui.ScanSettingsLengthUnit +import io.github.chrisimx.scanbridge.model.NumberValidationResult import io.github.chrisimx.scanbridge.uicomponents.SizeBasedConditionalView import io.github.chrisimx.scanbridge.uicomponents.ValidatedDimensionsTextEdit import io.github.chrisimx.scanbridge.util.localizedString diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/ScannerBrowser.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScannerBrowser.kt similarity index 96% rename from app/src/main/java/io/github/chrisimx/scanbridge/ScannerBrowser.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/ScannerBrowser.kt index 7030942a..cfb26d07 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/ScannerBrowser.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScannerBrowser.kt @@ -48,6 +48,7 @@ import androidx.navigation.NavController import io.github.chrisimx.scanbridge.data.model.EditedCustomScanner import io.github.chrisimx.scanbridge.data.ui.CustomScannerViewModel import io.github.chrisimx.scanbridge.db.entities.CustomScanner +import io.github.chrisimx.scanbridge.model.DiscoveredScanner import io.github.chrisimx.scanbridge.uicomponents.FoundScannerItem import io.github.chrisimx.scanbridge.uicomponents.FullScreenError import io.github.chrisimx.scanbridge.uicomponents.dialog.CustomScannerDialog @@ -63,14 +64,14 @@ fun startScannerDiscovery( context: Context, scannerMap: SnapshotStateMap, scannerMapSecure: SnapshotStateMap -): Optional>> { +): Optional>> { val service = getSystemService(context, NsdManager::class.java) if (service == null) { Timber.e("Couldn't get NsdManager service") return Optional.empty() } - val listener = ScannerDiscovery(service, isSecure = false, scannerMap) - val listenerSecure = ScannerDiscovery(service, isSecure = true, scannerMapSecure) + val listener = ScannerDiscoveryBackend(service, isSecure = false, scannerMap) + val listenerSecure = ScannerDiscoveryBackend(service, isSecure = true, scannerMapSecure) service.discoverServices("_uscan._tcp", NsdManager.PROTOCOL_DNS_SD, listener) service.discoverServices("_uscans._tcp", NsdManager.PROTOCOL_DNS_SD, listenerSecure) Timber.i("Discovery started") diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/ScannerDiscoveryBackend.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScannerDiscoveryBackend.kt similarity index 97% rename from app/src/main/java/io/github/chrisimx/scanbridge/ScannerDiscoveryBackend.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/ScannerDiscoveryBackend.kt index 256e5ef5..48b22c38 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/ScannerDiscoveryBackend.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScannerDiscoveryBackend.kt @@ -24,6 +24,7 @@ import android.net.nsd.NsdServiceInfo import android.os.Build import android.os.ext.SdkExtensions import androidx.compose.runtime.snapshots.SnapshotStateMap +import io.github.chrisimx.scanbridge.model.DiscoveredScanner import io.ktor.http.URLBuilder import io.ktor.http.URLProtocol import io.ktor.http.Url @@ -35,9 +36,7 @@ import timber.log.Timber private const val TAG = "ScannerDiscovery" -data class DiscoveredScanner(val name: String, val addresses: List) - -class ScannerDiscovery( +class ScannerDiscoveryBackend( val nsdManager: NsdManager, val isSecure: Boolean, val statefulScannerMap: SnapshotStateMap @@ -156,7 +155,7 @@ class ScannerDiscovery( } } -private fun ScannerDiscovery.tryParseScannerUrl(address: InetAddress, serviceInfo: NsdServiceInfo, rs: String): Url? { +private fun ScannerDiscoveryBackend.tryParseScannerUrl(address: InetAddress, serviceInfo: NsdServiceInfo, rs: String): Url? { if (address.isLinkLocalAddress) { Timber.tag(TAG).d("Ignoring link local address: ${address.hostAddress}") return null diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/ScanningScreen.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanningScreen.kt similarity index 99% rename from app/src/main/java/io/github/chrisimx/scanbridge/ScanningScreen.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanningScreen.kt index 0e695d25..d332932a 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/ScanningScreen.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/ScanningScreen.kt @@ -115,6 +115,8 @@ import me.saket.telephoto.zoomable.rememberZoomableState import me.saket.telephoto.zoomable.zoomable import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf +import scanbridge.composeui.generated.resources.Res +import scanbridge.composeui.generated.resources.trying_to_retrieve_scannercapabilities import timber.log.Timber private const val TAG = "ScanningScreen" @@ -354,7 +356,7 @@ fun ScanningScreen( } LoadingScreen( - loadingText = R.string.trying_to_retrieve_scannercapabilities + loadingText = Res.string.trying_to_retrieve_scannercapabilities ) } diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/StartupScreen.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/StartupScreen.kt similarity index 99% rename from app/src/main/java/io/github/chrisimx/scanbridge/StartupScreen.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/StartupScreen.kt index 0323e206..76685def 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/StartupScreen.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/StartupScreen.kt @@ -50,6 +50,7 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.navigation.NavController import io.github.chrisimx.scanbridge.data.model.EditedCustomScanner +import io.github.chrisimx.scanbridge.model.DiscoveredScanner import timber.log.Timber @OptIn(ExperimentalMaterial3Api::class) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/androidservice/ScanJobForegroundService.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/androidservice/ScanJobForegroundService.kt similarity index 93% rename from app/src/main/java/io/github/chrisimx/scanbridge/androidservice/ScanJobForegroundService.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/androidservice/ScanJobForegroundService.kt index 20567fbb..4f95b5c9 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/androidservice/ScanJobForegroundService.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/androidservice/ScanJobForegroundService.kt @@ -12,18 +12,20 @@ import android.os.IBinder import androidx.compose.ui.graphics.asImageBitmap import androidx.core.app.NotificationCompat import androidx.lifecycle.application -import androidx.room.withTransaction +import androidx.room.immediateTransaction +import androidx.room.useWriterConnection import io.github.chrisimx.esclkt.ESCLHttpCallResult import io.github.chrisimx.esclkt.ESCLRequestClient import io.github.chrisimx.esclkt.JobState import io.github.chrisimx.esclkt.ScanSettings import io.github.chrisimx.scanbridge.MainActivity import io.github.chrisimx.scanbridge.R -import io.github.chrisimx.scanbridge.data.model.ScanJob -import io.github.chrisimx.scanbridge.data.ui.ScanRelativeRotation import io.github.chrisimx.scanbridge.db.ScanBridgeDb import io.github.chrisimx.scanbridge.db.daos.ScannedPageDao import io.github.chrisimx.scanbridge.db.entities.ScannedPage +import io.github.chrisimx.scanbridge.model.ScanJob +import io.github.chrisimx.scanbridge.model.ScanRelativeRotation +import io.github.chrisimx.scanbridge.ports.HttpClientFactory import io.github.chrisimx.scanbridge.services.ScanJobRepository import io.github.chrisimx.scanbridge.util.extractPdfImages import io.github.chrisimx.scanbridge.util.toJobStateString @@ -63,6 +65,9 @@ class ScanJobForegroundService : Service() { } private val scanJobs: ScanJobRepository by inject() + + private val httpClientFactory: HttpClientFactory by inject() + private val db: ScanBridgeDb by inject() private val scannedPageDao: ScannedPageDao = db.scannedPageDao() @@ -165,7 +170,10 @@ class ScanJobForegroundService : Service() { private suspend fun doScan(scanJob: ScanJob) { val currentScanSettings = scanJob.scanSettings - val esclRequestClient = scanJob.esclClient + val esclRequestClient = ESCLRequestClient( + scanJob.scannerBaseUrl, + httpClientFactory.create(scanJob.httpClientConfig) + ) scanJobs.notifyStarted(scanJob) @@ -365,20 +373,22 @@ class ScanJobForegroundService : Service() { suspend fun addScan(sessionID: Uuid, path: String, settings: ScanSettings, rotation: ScanRelativeRotation) { Timber.d("Adding scan: $path, $rotation") - db.withTransaction { - val highestIdx = scannedPageDao.getHighestIdxForSession(sessionID) ?: -1 - - Timber.d("Inserting scan with index ${highestIdx + 1}") - scannedPageDao.insertAll( - ScannedPage( - Uuid.generateV4(), - sessionID, - path, - settings, - rotation, - highestIdx + 1 + db.useWriterConnection { + it.immediateTransaction { + val highestIdx = scannedPageDao.getHighestIdxForSession(sessionID) ?: -1 + + Timber.d("Inserting scan with index ${highestIdx + 1}") + scannedPageDao.insertAll( + ScannedPage( + Uuid.generateV4(), + sessionID, + path, + settings, + rotation, + highestIdx + 1 + ) ) - ) + } } } diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/data/model/EditedCustomScanner.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/model/EditedCustomScanner.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/data/model/EditedCustomScanner.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/data/model/EditedCustomScanner.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/data/model/LegacyESCLScanSettings.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/model/LegacyESCLScanSettings.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/data/model/LegacyESCLScanSettings.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/data/model/LegacyESCLScanSettings.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/data/model/LegacySessionV2.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/model/LegacySessionV2.kt similarity index 97% rename from app/src/main/java/io/github/chrisimx/scanbridge/data/model/LegacySessionV2.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/data/model/LegacySessionV2.kt index e56f1db8..e1aa2c04 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/data/model/LegacySessionV2.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/model/LegacySessionV2.kt @@ -4,7 +4,7 @@ import io.github.chrisimx.esclkt.ScanSettings import io.github.chrisimx.esclkt.ScannerCapabilities import io.github.chrisimx.esclkt.getInputSourceCaps import io.github.chrisimx.esclkt.getInputSourceOptions -import io.github.chrisimx.scanbridge.data.ui.ScanRelativeRotation +import io.github.chrisimx.scanbridge.model.ScanRelativeRotation import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import timber.log.Timber diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/data/ui/CustomScannerViewModel.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/CustomScannerViewModel.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/data/ui/CustomScannerViewModel.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/CustomScannerViewModel.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanSettingsComposableStateHolder.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanSettingsComposableStateHolder.kt similarity index 96% rename from app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanSettingsComposableStateHolder.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanSettingsComposableStateHolder.kt index 1d122b68..259258c4 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanSettingsComposableStateHolder.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanSettingsComposableStateHolder.kt @@ -40,11 +40,13 @@ import io.github.chrisimx.esclkt.millimeters import io.github.chrisimx.esclkt.scanRegion import io.github.chrisimx.esclkt.threeHundredthsOfInch import io.github.chrisimx.scanbridge.R -import io.github.chrisimx.scanbridge.services.LocaleProvider +import io.github.chrisimx.scanbridge.model.Locale +import io.github.chrisimx.scanbridge.model.NumberValidationResult +import io.github.chrisimx.scanbridge.model.ScanSettingsEnterableData +import io.github.chrisimx.scanbridge.ports.LocaleProvider import io.github.chrisimx.scanbridge.util.derived import io.github.chrisimx.scanbridge.util.getMaxResolution import io.github.chrisimx.scanbridge.util.toDoubleLocalized -import java.util.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -72,7 +74,7 @@ class ScanSettingsComposableStateHolder( @InjectedParam val scanSettings: StateFlow, @InjectedParam - private val initialScanSettingsData: ScanSettingsStateData, + private val initialScanSettingsData: ScanSettingsEnterableData, @InjectedParam private val updateSettings: suspend (ScanSettings.() -> ScanSettings) -> Unit, @InjectedParam @@ -82,7 +84,7 @@ class ScanSettingsComposableStateHolder( ) { private val _uiState = MutableStateFlow(initialScanSettingsData) - val uiState: StateFlow = _uiState.asStateFlow() + val uiState: StateFlow = _uiState.asStateFlow() val inputSourceOptions: StateFlow> = _uiState.derived(coroutineScope) { it.capabilities.getInputSourceOptions() @@ -402,12 +404,11 @@ class ScanSettingsComposableStateHolder( } } - private fun unitByLocale(locale: Locale = Locale.getDefault()): ScanSettingsLengthUnit = - if (locale.country in setOf("US", "LR", "MM")) { - ScanSettingsLengthUnit.INCH - } else { - ScanSettingsLengthUnit.MILLIMETER - } + private fun unitByLocale(locale: Locale): ScanSettingsLengthUnit = if (locale.country in setOf("US", "LR", "MM")) { + ScanSettingsLengthUnit.INCH + } else { + ScanSettingsLengthUnit.MILLIMETER + } fun selectMaxRegion() { _uiState.update { diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenData.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenData.kt similarity index 91% rename from app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenData.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenData.kt index 656d2cb4..6b0c5320 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenData.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenData.kt @@ -23,25 +23,13 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.State import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import io.github.chrisimx.esclkt.ESCLRequestClient import io.github.chrisimx.esclkt.ScannerCapabilities import java.io.File import kotlin.uuid.Uuid -enum class ScanRelativeRotation { - Rotated, - Original -} - data class ErrorDescription(val pretext: Int?, val icon: Int?, val text: String?) -fun ScanRelativeRotation.toggleRotation() = when (this) { - ScanRelativeRotation.Rotated -> ScanRelativeRotation.Original - ScanRelativeRotation.Original -> ScanRelativeRotation.Rotated -} - data class ScanningScreenData( - val esclClient: ESCLRequestClient, val sessionID: Uuid, val confirmDialogShown: MutableState = mutableStateOf(false), val confirmPageDeleteDialogShown: MutableState = mutableStateOf(false), @@ -58,7 +46,6 @@ data class ScanningScreenData( val isRotating: MutableState = mutableStateOf(false) ) { fun toImmutable() = ImmutableScanningScreenData( - esclClient, sessionID, confirmDialogShown, confirmPageDeleteDialogShown, @@ -77,7 +64,6 @@ data class ScanningScreenData( } data class ImmutableScanningScreenData( - val esclClient: ESCLRequestClient, val sessionID: Uuid, private val confirmDialogShownState: State, private val confirmPageDeleteDialogShownState: State, diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenViewModel.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenViewModel.kt similarity index 91% rename from app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenViewModel.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenViewModel.kt index 3d88cc57..1d27c139 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenViewModel.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanningScreenViewModel.kt @@ -29,14 +29,14 @@ import androidx.core.content.FileProvider import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.application import androidx.lifecycle.viewModelScope -import androidx.room.withTransaction +import androidx.room.immediateTransaction +import androidx.room.useWriterConnection import com.itextpdf.io.image.ImageDataFactory import com.itextpdf.kernel.geom.PageSize import com.itextpdf.kernel.pdf.PdfDocument import com.itextpdf.kernel.pdf.PdfWriter import com.itextpdf.layout.Document import com.itextpdf.layout.element.Image -import getTrustAllTM import io.github.chrisimx.esclkt.ESCLRequestClient import io.github.chrisimx.esclkt.InputSource import io.github.chrisimx.esclkt.ScanRegion @@ -55,6 +55,12 @@ import io.github.chrisimx.scanbridge.db.ScanBridgeDb import io.github.chrisimx.scanbridge.db.entities.ScannedPage import io.github.chrisimx.scanbridge.db.entities.Session import io.github.chrisimx.scanbridge.db.entities.TempFile +import io.github.chrisimx.scanbridge.model.HttpClientConfig +import io.github.chrisimx.scanbridge.model.ScanJob +import io.github.chrisimx.scanbridge.model.ScanRelativeRotation +import io.github.chrisimx.scanbridge.model.ScanSettingsEnterableData +import io.github.chrisimx.scanbridge.model.toggleRotation +import io.github.chrisimx.scanbridge.ports.HttpClientFactory import io.github.chrisimx.scanbridge.proto.chunkSizePdfExportOrNull import io.github.chrisimx.scanbridge.services.ScanJobRepository import io.github.chrisimx.scanbridge.stores.DefaultScanSettingsStore @@ -65,11 +71,6 @@ import io.github.chrisimx.scanbridge.util.rotateBy90 import io.github.chrisimx.scanbridge.util.saveAsJPEG import io.github.chrisimx.scanbridge.util.snackbarErrorRetrievingPage import io.github.chrisimx.scanbridge.util.zipFiles -import io.ktor.client.HttpClient -import io.ktor.client.engine.okhttp.OkHttp -import io.ktor.client.plugins.HttpTimeout -import io.ktor.client.plugins.logging.Logger -import io.ktor.client.plugins.logging.Logging import io.ktor.http.Url import java.io.File import java.nio.file.Files @@ -103,49 +104,22 @@ enum class ScanningScreenEvent { class ScanningScreenViewModel( @InjectedParam - address: Url, + val address: Url, @InjectedParam - timeout: UInt, + val timeout: UInt, @InjectedParam - withDebugInterceptor: Boolean, + val withDebugInterceptor: Boolean, @InjectedParam - certificateValidationDisabled: Boolean, + val certificateValidationDisabled: Boolean, @InjectedParam val sessionID: Uuid, val db: ScanBridgeDb, application: Application, - val scanJobRepo: ScanJobRepository + val scanJobRepo: ScanJobRepository, + val httpClientFactory: HttpClientFactory ) : AndroidViewModel(application) { private val _scanningScreenData = ScanningScreenData( - ESCLRequestClient( - address, - HttpClient(OkHttp) { - install(HttpTimeout) { - requestTimeoutMillis = timeout.toLong() * 1000 - connectTimeoutMillis = timeout.toLong() * 1000 - socketTimeoutMillis = timeout.toLong() * 1000 - } - if (withDebugInterceptor) { - install(Logging) { - logger = object : Logger { - override fun log(message: String) { - Timber.tag("ESCLRequestClient").d(message) - } - } - } - } - if (certificateValidationDisabled) { - engine { - config { - val (socketFactory, trustManager) = getTrustAllTM() - sslSocketFactory(socketFactory, trustManager) - hostnameVerifier { _, _ -> true } - } - } - } - } - ), sessionID ) val scanningScreenData: ImmutableScanningScreenData @@ -309,7 +283,7 @@ class ScanningScreenViewModel( } } - suspend fun saveUpdatedScanSettingsUiData(newData: ScanSettingsStateData?) { + suspend fun saveUpdatedScanSettingsUiData(newData: ScanSettingsEnterableData?) { Timber.d("Settings ui data updated $newData") sessionDao.updateScanSettingsUiData(sessionID, newData) } @@ -321,17 +295,19 @@ class ScanningScreenViewModel( Timber.d("Stored session: $storedSession") val updateSettings: suspend (ScanSettings.() -> ScanSettings) -> Unit = { lambda -> - db.withTransaction { - val oldSession = sessionDao.getSessionById(sessionID) ?: return@withTransaction - val newSession = oldSession.copy( - currentScanSettings = oldSession.currentScanSettings?.lambda() - ) - Timber.d("Settings updated ${newSession.currentScanSettings}") - sessionDao.update(newSession) + db.useWriterConnection { + it.immediateTransaction { + val oldSession = sessionDao.getSessionById(sessionID) ?: return@immediateTransaction + val newSession = oldSession.copy( + currentScanSettings = oldSession.currentScanSettings?.lambda() + ) + Timber.d("Settings updated ${newSession.currentScanSettings}") + sessionDao.update(newSession) + } } } - val defaultScanSettingsUIData = ScanSettingsStateData( + val defaultScanSettingsUIData = ScanSettingsEnterableData( caps ) @@ -510,11 +486,16 @@ class ScanningScreenViewModel( return@launch } - val scanJob = io.github.chrisimx.scanbridge.data.model.ScanJob( + val scanJob = ScanJob( Uuid.generateV4(), sessionID, currentSettings, - _scanningScreenData.esclClient + address, + HttpClientConfig( + certificateValidationDisabled, + withDebugInterceptor, + timeout.toULong() + ) ) scanJobRepo.enqueue(scanJob) ScanJobForegroundService.startService(application) @@ -526,14 +507,16 @@ class ScanningScreenViewModel( val filePaths = mutableListOf() val tmpPaths = mutableListOf() - db.withTransaction { - val scannedPages = scannedPageDao.getAllForSession(sessionID) - val tmpFiles = tmpFileDao.getFilesBySessionId(sessionID) + db.useWriterConnection { + it.immediateTransaction { + val scannedPages = scannedPageDao.getAllForSession(sessionID) + val tmpFiles = tmpFileDao.getFilesBySessionId(sessionID) - filePaths += scannedPages.map { it.filePath } - tmpPaths += tmpFiles.map { it.path } + filePaths += scannedPages.map { it.filePath } + tmpPaths += tmpFiles.map { it.path } - sessionDao.deleteById(sessionID) + sessionDao.deleteById(sessionID) + } } withContext(Dispatchers.IO) { @@ -769,8 +752,20 @@ class ScanningScreenViewModel( } } + fun createHttpClientConfig() = HttpClientConfig( + certificateValidationDisabled, + withDebugInterceptor, + timeout.toULong() + ) + fun retrieveScannerCapabilities() = viewModelScope.launch { - val esclClient = scanningScreenData.esclClient + val httpClient = httpClientFactory.create( + createHttpClientConfig() + ) + val esclClient = ESCLRequestClient( + address, + httpClient + ) val scannerCapabilitiesResult = esclClient.getScannerCapabilities() diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/datastore/DataStores.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/datastore/DataStores.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/datastore/DataStores.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/datastore/DataStores.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/datastore/LastRouteStoreSerializer.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/datastore/LastRouteStoreSerializer.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/datastore/LastRouteStoreSerializer.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/datastore/LastRouteStoreSerializer.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/datastore/ScanBridgeSettingsSerializer.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/datastore/ScanBridgeSettingsSerializer.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/datastore/ScanBridgeSettingsSerializer.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/datastore/ScanBridgeSettingsSerializer.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/datastore/ScanSettingsDataStoreHelpers.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/datastore/ScanSettingsDataStoreHelpers.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/datastore/ScanSettingsDataStoreHelpers.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/datastore/ScanSettingsDataStoreHelpers.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/datastore/ShownMessagesSerializer.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/datastore/ShownMessagesSerializer.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/datastore/ShownMessagesSerializer.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/datastore/ShownMessagesSerializer.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/logs/FileLogger.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/logs/FileLogger.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/logs/FileLogger.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/logs/FileLogger.kt diff --git a/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/Migration.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/Migration.kt new file mode 100644 index 00000000..6ec515de --- /dev/null +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/Migration.kt @@ -0,0 +1,16 @@ +package io.github.chrisimx.scanbridge.migrations + +import io.github.chrisimx.scanbridge.db.ScanBridgeDb + +interface Migration { + /** + * A unique identifier of the migration that will be used to determine if it has already run + */ + val migrationId: String + + /** + * Execute the migration + * @return Whether the migration was successful + */ + suspend fun migrate(db: ScanBridgeDb): Boolean +} diff --git a/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/MigrationExecutor.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/MigrationExecutor.kt new file mode 100644 index 00000000..f0968f49 --- /dev/null +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/MigrationExecutor.kt @@ -0,0 +1,5 @@ +package io.github.chrisimx.scanbridge.migrations + +interface MigrationExecutor { + suspend fun runMigrations() +} diff --git a/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/MigrationRegistry.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/MigrationRegistry.kt new file mode 100644 index 00000000..a4e1839e --- /dev/null +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/MigrationRegistry.kt @@ -0,0 +1,23 @@ +package io.github.chrisimx.scanbridge.migrations + +import io.github.chrisimx.scanbridge.repositories.DatastoreLastRouteRepository +import io.github.chrisimx.scanbridge.repositories.LastRouteRepoAutoMigration +import io.github.chrisimx.scanbridge.repositories.RoomLastRouteRepository +import org.koin.dsl.bind +import org.koin.dsl.module +import org.koin.plugin.module.dsl.create + +fun createLastRouteRepoAutoMigration( + datastoreLastRouteRepository: DatastoreLastRouteRepository, + roomLastRouteRepository: RoomLastRouteRepository +): LastRouteRepoAutoMigration = LastRouteRepoAutoMigration( + datastoreLastRouteRepository, + roomLastRouteRepository, + "LastRouteDataStoreToRoom" +) + +val migrationsModule = module { + single { + create(::createLastRouteRepoAutoMigration) + } bind Migration::class +} diff --git a/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/RoomBackedMigrationExecutor.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/RoomBackedMigrationExecutor.kt new file mode 100644 index 00000000..c6942117 --- /dev/null +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/migrations/RoomBackedMigrationExecutor.kt @@ -0,0 +1,36 @@ +package io.github.chrisimx.scanbridge.migrations + +import io.github.chrisimx.scanbridge.db.ScanBridgeDb +import io.github.chrisimx.scanbridge.db.entities.ExecutedMigrationToRoom +import io.github.chrisimx.scanbridge.ports.ScanBridgeLoggerFactory +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.koin.mp.KoinPlatform.getKoin + +class RoomBackedMigrationExecutor(val db: ScanBridgeDb, loggerFactory: ScanBridgeLoggerFactory) : MigrationExecutor { + val logger = loggerFactory.withClass(this::class) + val executedMigrationsDao = db.executedMigrationsDao() + + override suspend fun runMigrations() { + val migrations = getKoin().getAll() + + migrations.forEach { + withContext(Dispatchers.IO) { + val ranAlready = executedMigrationsDao.isAlreadyDone(it.migrationId) + if (!ranAlready) { + val success = it.migrate(db) + if (success) { + executedMigrationsDao.markAsExecuted( + ExecutedMigrationToRoom(it.migrationId) + ) + logger.info { "Migration with id ${it.migrationId} has finished successfully." } + } else { + logger.error { "Migration with id ${it.migrationId} has failed" } + } + } else { + logger.debug { "Migration with id ${it.migrationId} has already run" } + } + } + } + } +} diff --git a/androidApp/src/main/java/io/github/chrisimx/scanbridge/repositories/DatastoreLastRouteRepository.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/repositories/DatastoreLastRouteRepository.kt new file mode 100644 index 00000000..2a6d61c2 --- /dev/null +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/repositories/DatastoreLastRouteRepository.kt @@ -0,0 +1,32 @@ +package io.github.chrisimx.scanbridge.repositories + +import android.content.Context +import com.google.protobuf.StringValue +import io.github.chrisimx.scanbridge.LastRouteRepository +import io.github.chrisimx.scanbridge.datastore.lastRouteStore +import io.github.chrisimx.scanbridge.proto.copy +import io.github.chrisimx.scanbridge.proto.lastRouteOrNull +import kotlinx.coroutines.flow.firstOrNull + +class DatastoreLastRouteRepository(context: Context) : LastRouteRepository { + val lastRouteStore = context.lastRouteStore + override suspend fun getLastRoute(): String? = lastRouteStore.data.firstOrNull()?.lastRouteOrNull?.value + + override suspend fun setLastRoute(route: String?) { + if (route != null) { + lastRouteStore.updateData { + it.copy { + lastRoute = StringValue.of(route) + } + } + } else { + lastRouteStore.updateData { + lastRouteStore.updateData { + it.copy { + clearLastRoute() + } + } + } + } + } +} diff --git a/androidApp/src/main/java/io/github/chrisimx/scanbridge/repositories/DatastoreShownMessagesRepository.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/repositories/DatastoreShownMessagesRepository.kt new file mode 100644 index 00000000..afc939d4 --- /dev/null +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/repositories/DatastoreShownMessagesRepository.kt @@ -0,0 +1,36 @@ +package io.github.chrisimx.scanbridge.repositories + +import androidx.datastore.core.DataStore +import io.github.chrisimx.scanbridge.BuildConfig +import io.github.chrisimx.scanbridge.ShownMessagesRepository +import io.github.chrisimx.scanbridge.UserInformationMessage +import io.github.chrisimx.scanbridge.proto.ShownMessages +import io.github.chrisimx.scanbridge.proto.copy +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import org.koin.core.annotation.InjectedParam + +class DatastoreShownMessagesRepository( + val shownMessagesDataStore: DataStore, + @InjectedParam + val coroutineScope: CoroutineScope +) : ShownMessagesRepository { + override fun getWasShownFlow(message: UserInformationMessage): Flow = shownMessagesDataStore.data.map { + (BuildConfig.FLAVOR != "play" && message.playOnly) || !when (message) { + UserInformationMessage.THANKS_FOR_PURCHASE -> it.thankPlayOne + } + } + + override suspend fun setShown(message: UserInformationMessage, shown: Boolean) { + shownMessagesDataStore.updateData { + it.copy { + when (message) { + UserInformationMessage.THANKS_FOR_PURCHASE -> { + thankPlayOne = shown + } + } + } + } + } +} diff --git a/androidApp/src/main/java/io/github/chrisimx/scanbridge/repositories/RoomLastRouteRepository.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/repositories/RoomLastRouteRepository.kt new file mode 100644 index 00000000..413cc57b --- /dev/null +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/repositories/RoomLastRouteRepository.kt @@ -0,0 +1,27 @@ +package io.github.chrisimx.scanbridge.repositories + +import io.github.chrisimx.scanbridge.LastRouteRepository +import io.github.chrisimx.scanbridge.db.ScanBridgeDb +import io.github.chrisimx.scanbridge.db.entities.LastRoute +import io.github.chrisimx.scanbridge.migrations.Migration + +class RoomLastRouteRepository(db: ScanBridgeDb) : LastRouteRepository { + val lastRouteDao = db.lastRouteDao() + override suspend fun getLastRoute(): String? = lastRouteDao.getLastRoute()?.route + + override suspend fun setLastRoute(route: String?) { + if (route != null) { + lastRouteDao.setLastRoute(LastRoute(route)) + } else { + lastRouteDao.clearLastRoute() + } + } +} + +class LastRouteRepoAutoMigration(val a: LastRouteRepository, val b: LastRouteRepository, override val migrationId: String) : Migration { + override suspend fun migrate(db: ScanBridgeDb): Boolean { + val toBeMigrated = a.getLastRoute() + b.setLastRoute(toBeMigrated) + return true + } +} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/services/AndroidLocaleProvider.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/services/AndroidLocaleProvider.kt similarity index 51% rename from app/src/main/java/io/github/chrisimx/scanbridge/services/AndroidLocaleProvider.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/services/AndroidLocaleProvider.kt index db456fe2..7b262da6 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/services/AndroidLocaleProvider.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/services/AndroidLocaleProvider.kt @@ -1,20 +1,22 @@ package io.github.chrisimx.scanbridge.services import android.annotation.SuppressLint -import java.util.Locale +import io.github.chrisimx.scanbridge.model.Locale +import io.github.chrisimx.scanbridge.ports.LocaleProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import timber.log.Timber class AndroidLocaleProvider : LocaleProvider { - @SuppressLint("ConstantLocale") - private val _locale = MutableStateFlow(Locale.getDefault()) + @SuppressLint("ConstantLocale") // Constant local is not correct because update is called on Activity recreation + private val _locale = MutableStateFlow(getCurrentLocale()) override val locale: StateFlow = _locale.asStateFlow() + private fun getCurrentLocale(): Locale = Locale(java.util.Locale.getDefault().country) + internal fun update() { - val locale = Locale.getDefault() Timber.d("Locale updated to $locale") - _locale.value = locale + _locale.value = getCurrentLocale() } } diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/services/DebugLogService.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/services/DebugLogService.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/services/DebugLogService.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/services/DebugLogService.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/services/FileDebugLogService.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/services/FileDebugLogService.kt similarity index 96% rename from app/src/main/java/io/github/chrisimx/scanbridge/services/FileDebugLogService.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/services/FileDebugLogService.kt index 780a1650..7fdd3017 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/services/FileDebugLogService.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/services/FileDebugLogService.kt @@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import timber.log.Timber -class FileDebugLogService(val appSettings: DataStore, val application: Application) : DebugLogService { +class FileDebugLogService(appSettings: DataStore, val application: Application) : DebugLogService { val scope = CoroutineScope(Dispatchers.Main) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/services/ScanJobRepository.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/services/ScanJobRepository.kt similarity index 98% rename from app/src/main/java/io/github/chrisimx/scanbridge/services/ScanJobRepository.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/services/ScanJobRepository.kt index d9962c2e..703127a2 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/services/ScanJobRepository.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/services/ScanJobRepository.kt @@ -1,6 +1,6 @@ package io.github.chrisimx.scanbridge.services -import io.github.chrisimx.scanbridge.data.model.ScanJob +import io.github.chrisimx.scanbridge.model.ScanJob import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.BufferOverflow diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/stores/DefaultScanSettingsStore.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/stores/DefaultScanSettingsStore.kt similarity index 93% rename from app/src/main/java/io/github/chrisimx/scanbridge/stores/DefaultScanSettingsStore.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/stores/DefaultScanSettingsStore.kt index a534ef49..606ce6b6 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/stores/DefaultScanSettingsStore.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/stores/DefaultScanSettingsStore.kt @@ -22,13 +22,13 @@ package io.github.chrisimx.scanbridge.stores import android.content.Context import com.google.protobuf.StringValue import io.github.chrisimx.esclkt.ScanSettings -import io.github.chrisimx.scanbridge.data.ui.ScanSettingsStateData +import io.github.chrisimx.scanbridge.ScanSettingsJson import io.github.chrisimx.scanbridge.datastore.appSettingsStore import io.github.chrisimx.scanbridge.datastore.updateSettings +import io.github.chrisimx.scanbridge.model.ScanSettingsEnterableData import io.github.chrisimx.scanbridge.proto.lastUsedScanSettingsOrNull import io.github.chrisimx.scanbridge.proto.lastUsedScanSettingsUiStateOrNull import io.github.chrisimx.scanbridge.proto.rememberScanSettingsOrNull -import io.github.chrisimx.scanbridge.util.ScanSettingsJson import kotlinx.coroutines.flow.first import timber.log.Timber @@ -38,7 +38,7 @@ object DefaultScanSettingsStore { return appPreferences.rememberScanSettingsOrNull?.value ?: true } - suspend fun save(context: Context, scanSettings: ScanSettings, uiStateData: ScanSettingsStateData?) { + suspend fun save(context: Context, scanSettings: ScanSettings, uiStateData: ScanSettingsEnterableData?) { if (!isRememberSettingsEnabled(context)) { Timber.d("Scan settings persistence is disabled, skipping save") return @@ -61,7 +61,7 @@ object DefaultScanSettingsStore { } } - suspend fun load(context: Context): Pair { + suspend fun load(context: Context): Pair { if (!isRememberSettingsEnabled(context)) { Timber.d("Scan settings persistence is disabled, returning null") return null to null @@ -80,7 +80,7 @@ object DefaultScanSettingsStore { val json = ScanSettingsJson.json val lastUsedScanSettingsDecoded = json.decodeFromString(lastUsedScanSettings) val lastUsedScanSettingsUIStateDecoded = lastUsedScanSettingsUiState?.let { - json.decodeFromString(it) + json.decodeFromString(it) } Timber.d("Loaded default scan settings $lastUsedScanSettings, $lastUsedScanSettingsUIStateDecoded") return lastUsedScanSettingsDecoded to lastUsedScanSettingsUIStateDecoded diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/stores/LegacyCustomScannerStore.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/stores/LegacyCustomScannerStore.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/stores/LegacyCustomScannerStore.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/stores/LegacyCustomScannerStore.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/stores/LegacySessionsStore.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/stores/LegacySessionsStore.kt similarity index 73% rename from app/src/main/java/io/github/chrisimx/scanbridge/stores/LegacySessionsStore.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/stores/LegacySessionsStore.kt index 542f4970..027d52c1 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/stores/LegacySessionsStore.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/stores/LegacySessionsStore.kt @@ -1,9 +1,10 @@ package io.github.chrisimx.scanbridge.stores import android.content.Context -import androidx.room.util.copy -import androidx.room.withTransaction +import androidx.room.immediateTransaction +import androidx.room.useWriterConnection import io.github.chrisimx.esclkt.ScannerCapabilities +import io.github.chrisimx.scanbridge.ScanSettingsJson import io.github.chrisimx.scanbridge.data.model.LegacySessionV2 import io.github.chrisimx.scanbridge.data.model.LegacySessionV2.Companion.fromString import io.github.chrisimx.scanbridge.datastore.appSettingsStore @@ -12,14 +13,11 @@ import io.github.chrisimx.scanbridge.db.entities.ScannedPage import io.github.chrisimx.scanbridge.db.entities.Session import io.github.chrisimx.scanbridge.db.entities.TempFile import io.github.chrisimx.scanbridge.proto.copy -import io.github.chrisimx.scanbridge.util.ScanSettingsJson import java.io.File import java.nio.file.Files import kotlin.concurrent.atomics.AtomicBoolean import kotlin.concurrent.atomics.ExperimentalAtomicApi import kotlin.io.path.Path -import kotlin.io.path.extension -import kotlin.io.path.nameWithoutExtension import kotlin.uuid.Uuid import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -84,29 +82,10 @@ object LegacySessionsStore { val sessionId = Uuid.parse(legacySession.sessionID) - db.withTransaction { - sessionDao().insertAll( - Session(sessionId, legacySession.scanSettings, null) - ) - - tmpFileDao().insertAllList( - legacySession.tmpFiles.map { - TempFile(ownerSessionId = sessionId, path = it) - } - ) - - scannedPageDao().insertAllList( - legacySession.scannedPages.mapIndexed { index, page -> - ScannedPage( - scanId = Uuid.generateV4(), - ownerSessionId = sessionId, - filePath = page.filePath, - originalScanSettings = page.originalScanSettings, - rotation = page.rotation, - orderIndex = index - ) - } - ) + db.useWriterConnection { + it.immediateTransaction { + db.insertLegacySessionData(sessionId, legacySession) + } } Files.deleteIfExists(sessionDir.resolve("$sessionIdString.session")) @@ -124,4 +103,29 @@ object LegacySessionsStore { return this } + + private suspend fun ScanBridgeDb.insertLegacySessionData(sessionId: Uuid, legacySession: LegacySessionV2) { + sessionDao().insertAll( + Session(sessionId, legacySession.scanSettings, null) + ) + + tmpFileDao().insertAllList( + legacySession.tmpFiles.map { + TempFile(ownerSessionId = sessionId, path = it) + } + ) + + scannedPageDao().insertAllList( + legacySession.scannedPages.mapIndexed { index, page -> + ScannedPage( + scanId = Uuid.generateV4(), + ownerSessionId = sessionId, + filePath = page.filePath, + originalScanSettings = page.originalScanSettings, + rotation = page.rotation, + orderIndex = index + ) + } + ) + } } diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/CrashFileHandler.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/CrashFileHandler.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/CrashFileHandler.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/CrashFileHandler.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/CroppableImage.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/CroppableImage.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/CroppableImage.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/CroppableImage.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/ExportSettingsPopup.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/ExportSettingsPopup.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/ExportSettingsPopup.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/ExportSettingsPopup.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/FoundScannerItem.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/FoundScannerItem.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/FoundScannerItem.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/FoundScannerItem.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/FullScreenError.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/FullScreenError.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/FullScreenError.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/FullScreenError.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/SizeBasedConditionalView.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/SizeBasedConditionalView.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/SizeBasedConditionalView.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/SizeBasedConditionalView.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/TemporaryFileHandlePrompt.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/TemporaryFileHandlePrompt.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/TemporaryFileHandlePrompt.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/TemporaryFileHandlePrompt.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/TitledCard.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/TitledCard.kt similarity index 98% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/TitledCard.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/TitledCard.kt index b11e9198..8bfd0e24 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/TitledCard.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/TitledCard.kt @@ -47,7 +47,7 @@ fun TitledCard(title: String, color: Color = Teal1, content: @Composable () -> U Text( title, modifier = Modifier.padding(bottom = 16.dp), - fontFamily = Poppins, + fontFamily = Poppins(), fontWeight = FontWeight.SemiBold, fontSize = 20.sp, color = color diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/ValidatedTextField.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/ValidatedTextField.kt similarity index 97% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/ValidatedTextField.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/ValidatedTextField.kt index 88ea65ba..89a869ca 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/ValidatedTextField.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/ValidatedTextField.kt @@ -28,7 +28,8 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.KeyboardType import io.github.chrisimx.scanbridge.R -import io.github.chrisimx.scanbridge.data.ui.NumberValidationResult +import io.github.chrisimx.scanbridge.model.NumberValidationResult + fun NumberValidationResult.toHumanString(context: Context): String = when (this) { is NumberValidationResult.OutOfRange -> context.getString(R.string.error_state_not_in_allowed_range) NumberValidationResult.NotANumber -> context.getString(R.string.error_state_not_a_valid_number) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/ConfirmCloseDialog.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/ConfirmCloseDialog.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/ConfirmCloseDialog.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/ConfirmCloseDialog.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/CrashFileDialog.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/CrashFileDialog.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/CrashFileDialog.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/CrashFileDialog.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/CustomScannerDialog.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/CustomScannerDialog.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/CustomScannerDialog.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/CustomScannerDialog.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/DeleteDialog.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/DeleteDialog.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/DeleteDialog.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/DeleteDialog.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/ErrorDialog.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/ErrorDialog.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/ErrorDialog.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/ErrorDialog.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/LoadingDialog.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/LoadingDialog.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/LoadingDialog.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/LoadingDialog.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/SimpleTextDialog.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/SimpleTextDialog.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/SimpleTextDialog.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/SimpleTextDialog.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/TemporaryFileHandlingDialog.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/TemporaryFileHandlingDialog.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/TemporaryFileHandlingDialog.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/dialog/TemporaryFileHandlingDialog.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/CheckboxSetting.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/CheckboxSetting.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/CheckboxSetting.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/CheckboxSetting.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/MoreInformationButton.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/MoreInformationButton.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/MoreInformationButton.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/MoreInformationButton.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/UIntSetting.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/UIntSetting.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/UIntSetting.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/UIntSetting.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/VersionComposable.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/VersionComposable.kt similarity index 97% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/VersionComposable.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/VersionComposable.kt index 7424eb8e..58c7cfdd 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/VersionComposable.kt +++ b/androidApp/src/main/java/io/github/chrisimx/scanbridge/uicomponents/settings/VersionComposable.kt @@ -58,7 +58,7 @@ fun VersionComposable() { Text( stringResource(R.string.app_name), modifier = Modifier.padding(PaddingValues(4.dp)), - fontFamily = Poppins, + fontFamily = Poppins(), fontSize = 24.sp, fontWeight = FontWeight.ExtraBold, style = MaterialTheme.typography.labelLarge.copy( @@ -69,7 +69,7 @@ fun VersionComposable() { Text( "${BuildConfig.VERSION_NAME.removeSuffix("-play")} (${BuildConfig.VERSION_CODE}, ${BuildConfig.GIT_COMMIT_HASH})", fontStyle = FontStyle.Normal, - fontFamily = Poppins + fontFamily = Poppins() ) val editionNotice = mutableListOf() @@ -87,7 +87,7 @@ fun VersionComposable() { Text( editionNotice.joinToString(), fontStyle = FontStyle.Italic, - fontFamily = Poppins + fontFamily = Poppins() ) } diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/ESCLKtExtensions.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/util/ESCLKtExtensions.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/ESCLKtExtensions.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/util/ESCLKtExtensions.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/ImageUtil.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/util/ImageUtil.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/ImageUtil.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/util/ImageUtil.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/NavControllerExtensions.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/util/NavControllerExtensions.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/NavControllerExtensions.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/util/NavControllerExtensions.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/PdfUtil.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/util/PdfUtil.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/PdfUtil.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/util/PdfUtil.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/ScanFileNameUtil.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/util/ScanFileNameUtil.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/ScanFileNameUtil.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/util/ScanFileNameUtil.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/StateFlowExtensions.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/util/StateFlowExtensions.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/StateFlowExtensions.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/util/StateFlowExtensions.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/TempFileUtil.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/util/TempFileUtil.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/TempFileUtil.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/util/TempFileUtil.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/UIUtils.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/util/UIUtils.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/UIUtils.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/util/UIUtils.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/ZipArchiveUtil.kt b/androidApp/src/main/java/io/github/chrisimx/scanbridge/util/ZipArchiveUtil.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/ZipArchiveUtil.kt rename to androidApp/src/main/java/io/github/chrisimx/scanbridge/util/ZipArchiveUtil.kt diff --git a/app/src/main/proto/app_settings.proto b/androidApp/src/main/proto/app_settings.proto similarity index 100% rename from app/src/main/proto/app_settings.proto rename to androidApp/src/main/proto/app_settings.proto diff --git a/app/src/main/proto/route_store.proto b/androidApp/src/main/proto/route_store.proto similarity index 100% rename from app/src/main/proto/route_store.proto rename to androidApp/src/main/proto/route_store.proto diff --git a/app/src/main/proto/shown_messages.proto b/androidApp/src/main/proto/shown_messages.proto similarity index 100% rename from app/src/main/proto/shown_messages.proto rename to androidApp/src/main/proto/shown_messages.proto diff --git a/app/src/main/res/drawable/baseline_image_24.xml b/androidApp/src/main/res/drawable/baseline_image_24.xml similarity index 100% rename from app/src/main/res/drawable/baseline_image_24.xml rename to androidApp/src/main/res/drawable/baseline_image_24.xml diff --git a/app/src/main/res/drawable/baseline_picture_as_pdf_24.xml b/androidApp/src/main/res/drawable/baseline_picture_as_pdf_24.xml similarity index 100% rename from app/src/main/res/drawable/baseline_picture_as_pdf_24.xml rename to androidApp/src/main/res/drawable/baseline_picture_as_pdf_24.xml diff --git a/app/src/main/res/drawable/baseline_rotate_right_24.xml b/androidApp/src/main/res/drawable/baseline_rotate_right_24.xml similarity index 100% rename from app/src/main/res/drawable/baseline_rotate_right_24.xml rename to androidApp/src/main/res/drawable/baseline_rotate_right_24.xml diff --git a/app/src/main/res/drawable/favorite_24px.xml b/androidApp/src/main/res/drawable/favorite_24px.xml similarity index 100% rename from app/src/main/res/drawable/favorite_24px.xml rename to androidApp/src/main/res/drawable/favorite_24px.xml diff --git a/app/src/main/res/drawable/github_mark.xml b/androidApp/src/main/res/drawable/github_mark.xml similarity index 100% rename from app/src/main/res/drawable/github_mark.xml rename to androidApp/src/main/res/drawable/github_mark.xml diff --git a/app/src/main/res/drawable/icon_about_dialog.png b/androidApp/src/main/res/drawable/icon_about_dialog.png similarity index 100% rename from app/src/main/res/drawable/icon_about_dialog.png rename to androidApp/src/main/res/drawable/icon_about_dialog.png diff --git a/app/src/main/res/drawable/outline_crop_24.xml b/androidApp/src/main/res/drawable/outline_crop_24.xml similarity index 100% rename from app/src/main/res/drawable/outline_crop_24.xml rename to androidApp/src/main/res/drawable/outline_crop_24.xml diff --git a/app/src/main/res/drawable/outline_edit_24.xml b/androidApp/src/main/res/drawable/outline_edit_24.xml similarity index 100% rename from app/src/main/res/drawable/outline_edit_24.xml rename to androidApp/src/main/res/drawable/outline_edit_24.xml diff --git a/app/src/main/res/drawable/outline_error_24.xml b/androidApp/src/main/res/drawable/outline_error_24.xml similarity index 100% rename from app/src/main/res/drawable/outline_error_24.xml rename to androidApp/src/main/res/drawable/outline_error_24.xml diff --git a/app/src/main/res/drawable/outline_file_save_24.xml b/androidApp/src/main/res/drawable/outline_file_save_24.xml similarity index 100% rename from app/src/main/res/drawable/outline_file_save_24.xml rename to androidApp/src/main/res/drawable/outline_file_save_24.xml diff --git a/app/src/main/res/drawable/outline_pan_zoom_24.xml b/androidApp/src/main/res/drawable/outline_pan_zoom_24.xml similarity index 100% rename from app/src/main/res/drawable/outline_pan_zoom_24.xml rename to androidApp/src/main/res/drawable/outline_pan_zoom_24.xml diff --git a/app/src/main/res/drawable/outline_scan_24.xml b/androidApp/src/main/res/drawable/outline_scan_24.xml similarity index 100% rename from app/src/main/res/drawable/outline_scan_24.xml rename to androidApp/src/main/res/drawable/outline_scan_24.xml diff --git a/app/src/main/res/drawable/round_print_36.xml b/androidApp/src/main/res/drawable/round_print_36.xml similarity index 100% rename from app/src/main/res/drawable/round_print_36.xml rename to androidApp/src/main/res/drawable/round_print_36.xml diff --git a/app/src/main/res/drawable/rounded_adf_scanner_24.xml b/androidApp/src/main/res/drawable/rounded_adf_scanner_24.xml similarity index 100% rename from app/src/main/res/drawable/rounded_adf_scanner_24.xml rename to androidApp/src/main/res/drawable/rounded_adf_scanner_24.xml diff --git a/app/src/main/res/drawable/rounded_content_copy_24.xml b/androidApp/src/main/res/drawable/rounded_content_copy_24.xml similarity index 100% rename from app/src/main/res/drawable/rounded_content_copy_24.xml rename to androidApp/src/main/res/drawable/rounded_content_copy_24.xml diff --git a/app/src/main/res/drawable/rounded_document_scanner_24.xml b/androidApp/src/main/res/drawable/rounded_document_scanner_24.xml similarity index 100% rename from app/src/main/res/drawable/rounded_document_scanner_24.xml rename to androidApp/src/main/res/drawable/rounded_document_scanner_24.xml diff --git a/app/src/main/res/drawable/rounded_scanner_24.xml b/androidApp/src/main/res/drawable/rounded_scanner_24.xml similarity index 100% rename from app/src/main/res/drawable/rounded_scanner_24.xml rename to androidApp/src/main/res/drawable/rounded_scanner_24.xml diff --git a/app/src/main/res/drawable/rounded_warning_24.xml b/androidApp/src/main/res/drawable/rounded_warning_24.xml similarity index 100% rename from app/src/main/res/drawable/rounded_warning_24.xml rename to androidApp/src/main/res/drawable/rounded_warning_24.xml diff --git a/app/src/main/res/drawable/twotone_wifi_find_24.xml b/androidApp/src/main/res/drawable/twotone_wifi_find_24.xml similarity index 100% rename from app/src/main/res/drawable/twotone_wifi_find_24.xml rename to androidApp/src/main/res/drawable/twotone_wifi_find_24.xml diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/androidApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to androidApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/androidApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to androidApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/androidApp/src/main/res/mipmap-hdpi/ic_launcher.webp similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher.webp rename to androidApp/src/main/res/mipmap-hdpi/ic_launcher.webp diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp b/androidApp/src/main/res/mipmap-hdpi/ic_launcher_background.webp similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher_background.webp rename to androidApp/src/main/res/mipmap-hdpi/ic_launcher_background.webp diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/androidApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp rename to androidApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/androidApp/src/main/res/mipmap-hdpi/ic_launcher_round.webp similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher_round.webp rename to androidApp/src/main/res/mipmap-hdpi/ic_launcher_round.webp diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/androidApp/src/main/res/mipmap-mdpi/ic_launcher.webp similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher.webp rename to androidApp/src/main/res/mipmap-mdpi/ic_launcher.webp diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp b/androidApp/src/main/res/mipmap-mdpi/ic_launcher_background.webp similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher_background.webp rename to androidApp/src/main/res/mipmap-mdpi/ic_launcher_background.webp diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/androidApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp rename to androidApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/androidApp/src/main/res/mipmap-mdpi/ic_launcher_round.webp similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher_round.webp rename to androidApp/src/main/res/mipmap-mdpi/ic_launcher_round.webp diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/androidApp/src/main/res/mipmap-xhdpi/ic_launcher.webp similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher.webp rename to androidApp/src/main/res/mipmap-xhdpi/ic_launcher.webp diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp b/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_background.webp similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp rename to androidApp/src/main/res/mipmap-xhdpi/ic_launcher_background.webp diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp rename to androidApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_round.webp similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp rename to androidApp/src/main/res/mipmap-xhdpi/ic_launcher_round.webp diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher.webp similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher.webp rename to androidApp/src/main/res/mipmap-xxhdpi/ic_launcher.webp diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp b/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp rename to androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp rename to androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp rename to androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher.webp similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp rename to androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher.webp diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp b/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp rename to androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp rename to androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp rename to androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp diff --git a/app/src/main/res/raw/test_scanner_capabilities b/androidApp/src/main/res/raw/test_scanner_capabilities similarity index 100% rename from app/src/main/res/raw/test_scanner_capabilities rename to androidApp/src/main/res/raw/test_scanner_capabilities diff --git a/app/src/main/res/resources.properties b/androidApp/src/main/res/resources.properties similarity index 100% rename from app/src/main/res/resources.properties rename to androidApp/src/main/res/resources.properties diff --git a/app/src/main/res/values-de/strings.xml b/androidApp/src/main/res/values-de/strings.xml similarity index 100% rename from app/src/main/res/values-de/strings.xml rename to androidApp/src/main/res/values-de/strings.xml diff --git a/app/src/main/res/values-it/strings.xml b/androidApp/src/main/res/values-it/strings.xml similarity index 100% rename from app/src/main/res/values-it/strings.xml rename to androidApp/src/main/res/values-it/strings.xml diff --git a/app/src/main/res/values/colors.xml b/androidApp/src/main/res/values/colors.xml similarity index 100% rename from app/src/main/res/values/colors.xml rename to androidApp/src/main/res/values/colors.xml diff --git a/app/src/main/res/values/strings.xml b/androidApp/src/main/res/values/strings.xml similarity index 100% rename from app/src/main/res/values/strings.xml rename to androidApp/src/main/res/values/strings.xml diff --git a/app/src/main/res/values/themes.xml b/androidApp/src/main/res/values/themes.xml similarity index 100% rename from app/src/main/res/values/themes.xml rename to androidApp/src/main/res/values/themes.xml diff --git a/app/src/main/res/xml/backup_rules.xml b/androidApp/src/main/res/xml/backup_rules.xml similarity index 100% rename from app/src/main/res/xml/backup_rules.xml rename to androidApp/src/main/res/xml/backup_rules.xml diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/androidApp/src/main/res/xml/data_extraction_rules.xml similarity index 100% rename from app/src/main/res/xml/data_extraction_rules.xml rename to androidApp/src/main/res/xml/data_extraction_rules.xml diff --git a/app/src/main/res/xml/network_security_config.xml b/androidApp/src/main/res/xml/network_security_config.xml similarity index 100% rename from app/src/main/res/xml/network_security_config.xml rename to androidApp/src/main/res/xml/network_security_config.xml diff --git a/app/src/main/res/xml/provider_paths.xml b/androidApp/src/main/res/xml/provider_paths.xml similarity index 100% rename from app/src/main/res/xml/provider_paths.xml rename to androidApp/src/main/res/xml/provider_paths.xml diff --git a/app/src/play/AndroidManifest.xml b/androidApp/src/play/AndroidManifest.xml similarity index 100% rename from app/src/play/AndroidManifest.xml rename to androidApp/src/play/AndroidManifest.xml diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/AccountSetupScreen.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/AccountSetupScreen.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/AccountSetupScreen.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/AccountSetupScreen.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/InternetConnectivityFlow.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/InternetConnectivityFlow.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/InternetConnectivityFlow.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/InternetConnectivityFlow.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/LicenseErrorStringMapping.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/LicenseErrorStringMapping.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/LicenseErrorStringMapping.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/LicenseErrorStringMapping.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/OwnershipProofService.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/OwnershipProofService.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/OwnershipProofService.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/OwnershipProofService.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/OwnershipTestScreen.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/OwnershipTestScreen.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/OwnershipTestScreen.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/OwnershipTestScreen.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/PlainTextObfuscator.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/PlainTextObfuscator.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/PlainTextObfuscator.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/PlainTextObfuscator.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/SignupScreen.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/SignupScreen.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/SignupScreen.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/SignupScreen.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/SimpleStrictLicensePolicy.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/SimpleStrictLicensePolicy.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/SimpleStrictLicensePolicy.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/SimpleStrictLicensePolicy.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/SpecialIcons.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/SpecialIcons.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/SpecialIcons.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/SpecialIcons.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/StartupTabDefinitions.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/StartupTabDefinitions.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/StartupTabDefinitions.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/StartupTabDefinitions.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/SuccessSigningUpScreen.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/SuccessSigningUpScreen.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/SuccessSigningUpScreen.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/SuccessSigningUpScreen.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/SupportScreen.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/SupportScreen.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/SupportScreen.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/SupportScreen.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/zammadapi/AccountVerificationClient.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/zammadapi/AccountVerificationClient.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/zammadapi/AccountVerificationClient.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/zammadapi/AccountVerificationClient.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/zammadapi/AccountVerifierApi.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/zammadapi/AccountVerifierApi.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/zammadapi/AccountVerifierApi.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/zammadapi/AccountVerifierApi.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/AccountCreationRequest.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/AccountCreationRequest.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/AccountCreationRequest.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/AccountCreationRequest.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/GoogleChallenge.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/GoogleChallenge.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/GoogleChallenge.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/GoogleChallenge.kt diff --git a/app/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/VIPCreationResult.kt b/androidApp/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/VIPCreationResult.kt similarity index 100% rename from app/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/VIPCreationResult.kt rename to androidApp/src/play/java/io/github/chrisimx/scanbridge/zammadapi/models/VIPCreationResult.kt diff --git a/app/src/play/res/drawable/fireamp_icon.xml b/androidApp/src/play/res/drawable/fireamp_icon.xml similarity index 100% rename from app/src/play/res/drawable/fireamp_icon.xml rename to androidApp/src/play/res/drawable/fireamp_icon.xml diff --git a/app/src/play/res/drawable/outline_globe_24.xml b/androidApp/src/play/res/drawable/outline_globe_24.xml similarity index 100% rename from app/src/play/res/drawable/outline_globe_24.xml rename to androidApp/src/play/res/drawable/outline_globe_24.xml diff --git a/app/src/play/res/values-de/strings.xml b/androidApp/src/play/res/values-de/strings.xml similarity index 100% rename from app/src/play/res/values-de/strings.xml rename to androidApp/src/play/res/values-de/strings.xml diff --git a/app/src/play/res/values-it/strings.xml b/androidApp/src/play/res/values-it/strings.xml similarity index 100% rename from app/src/play/res/values-it/strings.xml rename to androidApp/src/play/res/values-it/strings.xml diff --git a/app/src/play/res/values/strings.xml b/androidApp/src/play/res/values/strings.xml similarity index 100% rename from app/src/play/res/values/strings.xml rename to androidApp/src/play/res/values/strings.xml diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApplication.kt b/app/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApplication.kt deleted file mode 100644 index 91667bb1..00000000 --- a/app/src/main/java/io/github/chrisimx/scanbridge/ScanBridgeApplication.kt +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.chrisimx.scanbridge - -import android.app.Application -import android.content.Context -import androidx.datastore.core.DataStore -import androidx.room.Room -import io.github.chrisimx.scanbridge.data.ui.CustomScannerViewModel -import io.github.chrisimx.scanbridge.data.ui.ScanSettingsComposableStateHolder -import io.github.chrisimx.scanbridge.data.ui.ScanningScreenViewModel -import io.github.chrisimx.scanbridge.datastore.appSettingsStore -import io.github.chrisimx.scanbridge.db.ScanBridgeDb -import io.github.chrisimx.scanbridge.proto.ScanBridgeSettings -import io.github.chrisimx.scanbridge.services.AndroidLocaleProvider -import io.github.chrisimx.scanbridge.services.DebugLogService -import io.github.chrisimx.scanbridge.services.FileDebugLogService -import io.github.chrisimx.scanbridge.services.LocaleProvider -import io.github.chrisimx.scanbridge.services.ScanJobRepository -import io.github.chrisimx.scanbridge.stores.LegacyCustomScannerStore.migrateLegacyCustomScanners -import io.github.chrisimx.scanbridge.stores.LegacySessionsStore.migrateLegacySessions -import java.util.concurrent.Executors -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.runBlocking -import org.koin.android.ext.koin.androidContext -import org.koin.core.context.startKoin -import org.koin.dsl.bind -import org.koin.dsl.module -import org.koin.plugin.module.dsl.factory -import org.koin.plugin.module.dsl.single -import org.koin.plugin.module.dsl.viewModel -import timber.log.Timber - -val appModule = module { - single> { - get().appSettingsStore - } - single() bind LocaleProvider::class - single() bind DebugLogService::class - single() - single { - val context = get() - val writeDebug = runBlocking { context.appSettingsStore.data.firstOrNull()?.writeDebug ?: false } - val builder = Room.databaseBuilder( - get(), - ScanBridgeDb::class.java, - "scanbridge" - ) - if (writeDebug) { - builder.setQueryCallback( - { sqlQuery, bindArgs -> - Timber.tag("RoomDebug").d("SQL: $sqlQuery, args: $bindArgs") - }, - Executors.newSingleThreadExecutor() - ) - } - builder.build() - .migrateLegacyCustomScanners(get()) - .migrateLegacySessions(get()) - } - factory() - viewModel() - viewModel() -} - -class ScanBridgeApplication : Application() { - override fun onCreate() { - super.onCreate() - startKoin { - androidContext(this@ScanBridgeApplication) - modules(appModule) - } - - Timber.plant(Timber.DebugTree()) - } -} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/data/model/ScanJob.kt b/app/src/main/java/io/github/chrisimx/scanbridge/data/model/ScanJob.kt deleted file mode 100644 index 47f30b49..00000000 --- a/app/src/main/java/io/github/chrisimx/scanbridge/data/model/ScanJob.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.github.chrisimx.scanbridge.data.model - -import io.github.chrisimx.esclkt.ESCLRequestClient -import io.github.chrisimx.esclkt.ScanSettings -import kotlin.uuid.Uuid - -data class ScanJob(val jobID: Uuid, val ownerSessionId: Uuid, val scanSettings: ScanSettings, val esclClient: ESCLRequestClient) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanSettingsStateData.kt b/app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanSettingsStateData.kt deleted file mode 100644 index 62a322e6..00000000 --- a/app/src/main/java/io/github/chrisimx/scanbridge/data/ui/ScanSettingsStateData.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2024-2025 Christian Nagel and contributors - * - * This file is part of ScanBridge. - * - * ScanBridge is free software: you can redistribute it and/or modify it under the terms of - * the GNU General Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * ScanBridge is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with eSCLKt. - * If not, see . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package io.github.chrisimx.scanbridge.data.ui - -import io.github.chrisimx.esclkt.ScannerCapabilities -import io.github.chrisimx.scanbridge.data.model.PaperFormat -import io.github.chrisimx.scanbridge.data.model.loadDefaultFormats -import kotlinx.serialization.Serializable - -@Serializable -sealed class NumberValidationResult { - data class Success(val value: Double) : NumberValidationResult() - data class OutOfRange(val min: Double, val max: Double) : NumberValidationResult() - data object NotANumber : NumberValidationResult() -} - -@Serializable -data class ScanSettingsStateData( - val capabilities: ScannerCapabilities, - val paperFormats: List = loadDefaultFormats(), - val customMenuEnabled: Boolean = false, - val widthString: String = "", - val heightString: String = "", - val maximumSize: Boolean = true -) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsUiDataTypeConverter.kt b/app/src/main/java/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsUiDataTypeConverter.kt deleted file mode 100644 index 293b59a4..00000000 --- a/app/src/main/java/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsUiDataTypeConverter.kt +++ /dev/null @@ -1,22 +0,0 @@ -package io.github.chrisimx.scanbridge.db.typeconverters - -import androidx.room.TypeConverter -import io.github.chrisimx.scanbridge.data.ui.ScanSettingsStateData -import io.github.chrisimx.scanbridge.util.ScanSettingsJson - -class ScanSettingsUiDataTypeConverter { - - @TypeConverter - fun fromScanSettingsString(scanSettings: String): ScanSettingsStateData? = if (scanSettings == "null") { - null - } else { - ScanSettingsJson.json.decodeFromString(scanSettings) - } - - @TypeConverter - fun toScanSettingsString(scanSettings: ScanSettingsStateData?): String = if (scanSettings == null) { - "null" - } else { - ScanSettingsJson.json.encodeToString(scanSettings) - } -} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/services/LocaleProvider.kt b/app/src/main/java/io/github/chrisimx/scanbridge/services/LocaleProvider.kt deleted file mode 100644 index 8aef6fd8..00000000 --- a/app/src/main/java/io/github/chrisimx/scanbridge/services/LocaleProvider.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.github.chrisimx.scanbridge.services - -import java.util.Locale -import kotlinx.coroutines.flow.StateFlow - -interface LocaleProvider { - val locale: StateFlow -} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/theme/Font.kt b/app/src/main/java/io/github/chrisimx/scanbridge/theme/Font.kt deleted file mode 100644 index 8fdf3d94..00000000 --- a/app/src/main/java/io/github/chrisimx/scanbridge/theme/Font.kt +++ /dev/null @@ -1,36 +0,0 @@ -package io.github.chrisimx.scanbridge.theme - -import androidx.compose.ui.text.font.Font -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontStyle -import androidx.compose.ui.text.font.FontWeight -import io.github.chrisimx.scanbridge.R - -val Poppins = FontFamily( - Font(R.font.poppins_thin, weight = FontWeight.Thin), - Font(R.font.poppins_thinitalic, weight = FontWeight.Thin, style = FontStyle.Italic), - - Font(R.font.poppins_extralight, weight = FontWeight.ExtraLight), - Font(R.font.poppins_extralightitalic, weight = FontWeight.ExtraLight, style = FontStyle.Italic), - - Font(R.font.poppins_light, weight = FontWeight.Light), - Font(R.font.poppins_lightitalic, weight = FontWeight.Light, style = FontStyle.Italic), - - Font(R.font.poppins_regular, weight = FontWeight.Normal), - Font(R.font.poppins_italic, weight = FontWeight.Normal, style = FontStyle.Italic), - - Font(R.font.poppins_medium, weight = FontWeight.Medium), - Font(R.font.poppins_mediumitalic, weight = FontWeight.Medium, style = FontStyle.Italic), - - Font(R.font.poppins_semibold, weight = FontWeight.SemiBold), - Font(R.font.poppins_semibolditalic, weight = FontWeight.SemiBold, style = FontStyle.Italic), - - Font(R.font.poppins_bold, weight = FontWeight.Bold), - Font(R.font.poppins_bolditalic, weight = FontWeight.Bold, style = FontStyle.Italic), - - Font(R.font.poppins_extrabold, weight = FontWeight.ExtraBold), - Font(R.font.poppins_extrabolditalic, weight = FontWeight.ExtraBold, style = FontStyle.Italic), - - Font(R.font.poppins_black, weight = FontWeight.Black), - Font(R.font.poppins_blackitalic, weight = FontWeight.Black, style = FontStyle.Italic) -) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/theme/Typography.kt b/app/src/main/java/io/github/chrisimx/scanbridge/theme/Typography.kt deleted file mode 100644 index a99f7cf7..00000000 --- a/app/src/main/java/io/github/chrisimx/scanbridge/theme/Typography.kt +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2024-2025 Christian Nagel and contributors - * - * This file is part of ScanBridge. - * - * ScanBridge is free software: you can redistribute it and/or modify it under the terms of - * the GNU General Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * ScanBridge is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with eSCLKt. - * If not, see . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package io.github.chrisimx.scanbridge.theme - -import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi -import androidx.compose.material3.Typography -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.sp - -// Set of Material typography styles to start with -@OptIn(ExperimentalMaterial3ExpressiveApi::class) -val Typography = Typography( - titleSmall = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 20.sp, - letterSpacing = 0.sp - ), - titleMedium = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - fontSize = 18.sp, - lineHeight = 24.sp, - letterSpacing = 0.sp - ), - titleMediumEmphasized = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.ExtraBold, - fontSize = 18.sp, - lineHeight = 24.sp, - letterSpacing = 0.sp - ), - titleLarge = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp - ), - titleLargeEmphasized = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.ExtraBold, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp - ), - labelSmall = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - lineHeight = 14.sp, - fontSize = 11.sp, - letterSpacing = 0.sp - ), - labelMedium = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - lineHeight = 14.sp, - fontSize = 14.sp, - letterSpacing = 0.sp - ), - labelLarge = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - letterSpacing = 0.sp - ), - bodySmall = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - letterSpacing = 0.sp - ), - bodySmallEmphasized = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.ExtraBold, - letterSpacing = 0.sp - ), - bodyMedium = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - letterSpacing = 0.sp - ), - bodyMediumEmphasized = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.ExtraBold, - letterSpacing = 0.sp - ), - bodyLarge = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.5.sp - ), - bodyLargeEmphasized = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.ExtraBold, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.5.sp - ), - displaySmall = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - letterSpacing = 0.sp - ), - displayMedium = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - letterSpacing = 0.sp - ), - displayLarge = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - letterSpacing = 0.sp - ), - displaySmallEmphasized = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.ExtraBold, - letterSpacing = 0.sp - ), - displayMediumEmphasized = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.ExtraBold, - letterSpacing = 0.sp - ), - displayLargeEmphasized = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.ExtraBold, - letterSpacing = 0.sp - ), - headlineLarge = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - fontSize = 24.sp, - lineHeight = 32.sp, - letterSpacing = 0.sp - ), - headlineMedium = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - fontSize = 20.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp - ), - headlineMediumEmphasized = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.ExtraBold, - fontSize = 20.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp - ), - headlineSmall = TextStyle( - fontFamily = Poppins, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.sp - ) -) diff --git a/app/src/test/java/org/github/chrisimx/scanbridge/ScanSettingsStoreTest.kt b/app/src/test/java/org/github/chrisimx/scanbridge/ScanSettingsStoreTest.kt deleted file mode 100644 index d2320e3b..00000000 --- a/app/src/test/java/org/github/chrisimx/scanbridge/ScanSettingsStoreTest.kt +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2024-2025 Christian Nagel and contributors - * - * This file is part of ScanBridge. - * - * ScanBridge is free software: you can redistribute it and/or modify it under the terms of - * the GNU General Public License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * ScanBridge is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with eSCLKt. - * If not, see . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -package org.github.chrisimx.scanbridge - -import io.github.chrisimx.esclkt.ColorMode -import io.github.chrisimx.esclkt.EnumOrRaw -import io.github.chrisimx.esclkt.InputSource -import io.github.chrisimx.scanbridge.data.model.StatelessImmutableESCLScanSettingsState -import io.github.chrisimx.scanbridge.data.model.StatelessImmutableScanRegion -import org.junit.Assert.assertEquals -import org.junit.Test - -class ScanSettingsStoreTest { - - @Test - fun testScanSettingsPersistenceBehavior() { - val testSettings = StatelessImmutableESCLScanSettingsState( - version = "2.63", - intent = null, - scanRegions = StatelessImmutableScanRegion("297", "210", "0", "0"), - documentFormatExt = "application/pdf", - contentType = null, - inputSource = InputSource.Feeder, - xResolution = 300u, - yResolution = 300u, - colorMode = EnumOrRaw.Known(ColorMode.RGB24), - colorSpace = null, - mediaType = null, - ccdChannel = null, - binaryRendering = null, - duplex = true, - numberOfPages = null, - brightness = null, - compressionFactor = null, - contrast = null, - gamma = null, - highlight = null, - noiseRemoval = null, - shadow = null, - sharpen = null, - threshold = null, - contextID = null, - blankPageDetection = null, - feedDirection = null, - blankPageDetectionAndRemoval = null - ) - - assertEquals(InputSource.Feeder, testSettings.inputSource) - assertEquals(true, testSettings.duplex) - assertEquals("210", testSettings.scanRegions?.width) - assertEquals("297", testSettings.scanRegions?.height) - assertEquals("application/pdf", testSettings.documentFormatExt) - - // Test conversion to mutable (for editing in UI) - val mutableSettings = testSettings.toMutable() - assertEquals(InputSource.Feeder, mutableSettings.inputSource) - assertEquals(true, mutableSettings.duplex) - - // Test conversion back to stateless (for persistence) - val statelessSettings = mutableSettings.toStateless() - assertEquals(testSettings.inputSource, statelessSettings.inputSource) - assertEquals(testSettings.duplex, statelessSettings.duplex) - assertEquals(testSettings.documentFormatExt, statelessSettings.documentFormatExt) - } - - @Test - fun testScanSettingsStatelessDataStructure() { - val testScanRegion = StatelessImmutableScanRegion( - "297", - "210", - "0", - "0" - ) - - val testSettings = StatelessImmutableESCLScanSettingsState( - version = "2.63", - intent = null, - scanRegions = testScanRegion, - documentFormatExt = "image/jpeg", - contentType = null, - inputSource = InputSource.Feeder, - xResolution = 300u, - yResolution = 300u, - colorMode = EnumOrRaw.Known(ColorMode.RGB24), - colorSpace = null, - mediaType = null, - ccdChannel = null, - binaryRendering = null, - duplex = true, - numberOfPages = null, - brightness = null, - compressionFactor = null, - contrast = null, - gamma = null, - highlight = null, - noiseRemoval = null, - shadow = null, - sharpen = null, - threshold = null, - contextID = null, - blankPageDetection = null, - feedDirection = null, - blankPageDetectionAndRemoval = null - ) - - assertEquals(InputSource.Feeder, testSettings.inputSource) - assertEquals(true, testSettings.duplex) - assertEquals("image/jpeg", testSettings.documentFormatExt) - assertEquals(true, testSettings.scanRegions != null) - - // Test the toMutable conversion to ensure settings can be converted back - val mutableSettings = testSettings.toMutable() - assertEquals(InputSource.Feeder, mutableSettings.inputSource) - assertEquals(true, mutableSettings.duplex) - assertEquals("image/jpeg", mutableSettings.documentFormatExt) - - // Test that we can convert back to stateless - val reconvertedSettings = mutableSettings.toStateless() - assertEquals(testSettings.inputSource, reconvertedSettings.inputSource) - assertEquals(testSettings.duplex, reconvertedSettings.duplex) - assertEquals(testSettings.documentFormatExt, reconvertedSettings.documentFormatExt) - } - - @Test - fun testScanRegionDataStructure() { - val a4Region = StatelessImmutableScanRegion("297", "210", "0", "0") - val mutableA4 = a4Region.toMutable() - - assertEquals("210", mutableA4.width) - assertEquals("297", mutableA4.height) - assertEquals("0", mutableA4.xOffset) - assertEquals("0", mutableA4.yOffset) - - // Test that we can modify mutable settings - mutableA4.width = "148" // A5 width - mutableA4.height = "210" // A5 height - - assertEquals("148", mutableA4.width) - assertEquals("210", mutableA4.height) - - // Test conversion back to stateless - val a5Region = mutableA4.toStateless() - val reconvertedA5 = a5Region.toMutable() - assertEquals("148", reconvertedA5.width) - assertEquals("210", reconvertedA5.height) - } -} diff --git a/build.gradle.kts b/build.gradle.kts index d497f649..c70a45c6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,13 @@ import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask -// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - alias(libs.plugins.android.application) apply false - alias(libs.plugins.kotlin.compose) apply false + alias(libs.plugins.kotlin.multiplatform).apply(false) + alias(libs.plugins.compose.compiler).apply(false) + alias(libs.plugins.compose.multiplatform).apply(false) + alias(libs.plugins.kotlin.android).apply(false) + alias(libs.plugins.android.application).apply(false) + alias(libs.plugins.android.kmp.library).apply(false) + alias(libs.plugins.kotlin.jvm).apply(false) alias(libs.plugins.versions) } diff --git a/composeUI/.gitignore b/composeUI/.gitignore new file mode 100644 index 00000000..92e0b0fb --- /dev/null +++ b/composeUI/.gitignore @@ -0,0 +1,2 @@ +/build +build \ No newline at end of file diff --git a/composeUI/build.gradle.kts b/composeUI/build.gradle.kts new file mode 100644 index 00000000..a7dc95b6 --- /dev/null +++ b/composeUI/build.gradle.kts @@ -0,0 +1,74 @@ +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget + +plugins { + alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.compose.multiplatform) + alias(libs.plugins.android.kmp.library) +} + +kotlin { + jvm { + compilerOptions { jvmTarget = JvmTarget.JVM_17 } + } + + android { + namespace = "io.github.chrisimx.scanbridge" + compileSdk = 36 + minSdk = 23 + androidResources.enable = true + + compilerOptions { + jvmTarget.set( + org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + ) + } + } + + sourceSets { + commonMain.dependencies { + api(libs.compose.runtime) + api(libs.compose.ui) + api(libs.compose.foundation) + api(libs.compose.resources) + api(libs.compose.ui.tooling.preview) + api(libs.compose.material3) + } + + commonTest.dependencies { + implementation(kotlin("test")) + implementation(libs.compose.ui.test) + } + + androidMain.dependencies { + } + + jvmMain.dependencies { + implementation(compose.desktop.currentOs) + } + } + + targets + .withType() + .matching { it.konanTarget.family.isAppleFamily } + .configureEach { + binaries { + framework { + baseName = "ScanBridgeSharedUI" + isStatic = true + } + } + } +} + +dependencies { + androidRuntimeClasspath("org.jetbrains.compose.ui:ui-tooling:1.10.0") +} + +compose.resources { + publicResClass = true + // packageOfResClass = "me.sample.library.resources" + generateResClass = always +} diff --git a/composeUI/src/androidMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.android.kt b/composeUI/src/androidMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.android.kt new file mode 100644 index 00000000..0c3ef625 --- /dev/null +++ b/composeUI/src/androidMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.android.kt @@ -0,0 +1,24 @@ +package io.github.chrisimx.scanbridge.theme + +import android.os.Build +import androidx.compose.material3.ColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +@Composable +actual fun platformDarkColorScheme(): ColorScheme? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val context = LocalContext.current + dynamicDarkColorScheme(context) +} else { + null +} + +@Composable +actual fun platformLightColorScheme(): ColorScheme? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val context = LocalContext.current + dynamicLightColorScheme(context) +} else { + null +} diff --git a/composeUI/src/appleMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.apple.kt b/composeUI/src/appleMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.apple.kt new file mode 100644 index 00000000..52760201 --- /dev/null +++ b/composeUI/src/appleMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.apple.kt @@ -0,0 +1,9 @@ +package io.github.chrisimx.scanbridge.theme + +import androidx.compose.material3.ColorScheme +import androidx.compose.runtime.Composable + +@Composable +actual fun platformDarkColorScheme(): ColorScheme? { + TODO("Not yet implemented") +} diff --git a/composeUI/src/commonMain/composeResources/drawable/ic_cyclone.xml b/composeUI/src/commonMain/composeResources/drawable/ic_cyclone.xml new file mode 100644 index 00000000..f1c45b5a --- /dev/null +++ b/composeUI/src/commonMain/composeResources/drawable/ic_cyclone.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/composeUI/src/commonMain/composeResources/drawable/ic_dark_mode.xml b/composeUI/src/commonMain/composeResources/drawable/ic_dark_mode.xml new file mode 100644 index 00000000..0ce2444a --- /dev/null +++ b/composeUI/src/commonMain/composeResources/drawable/ic_dark_mode.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/composeUI/src/commonMain/composeResources/drawable/ic_light_mode.xml b/composeUI/src/commonMain/composeResources/drawable/ic_light_mode.xml new file mode 100644 index 00000000..b7331d3e --- /dev/null +++ b/composeUI/src/commonMain/composeResources/drawable/ic_light_mode.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/composeUI/src/commonMain/composeResources/drawable/ic_rotate_right.xml b/composeUI/src/commonMain/composeResources/drawable/ic_rotate_right.xml new file mode 100644 index 00000000..18106717 --- /dev/null +++ b/composeUI/src/commonMain/composeResources/drawable/ic_rotate_right.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/font/poppins_black.ttf b/composeUI/src/commonMain/composeResources/font/poppins_black.ttf similarity index 100% rename from app/src/main/res/font/poppins_black.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_black.ttf diff --git a/app/src/main/res/font/poppins_blackitalic.ttf b/composeUI/src/commonMain/composeResources/font/poppins_blackitalic.ttf similarity index 100% rename from app/src/main/res/font/poppins_blackitalic.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_blackitalic.ttf diff --git a/app/src/main/res/font/poppins_bold.ttf b/composeUI/src/commonMain/composeResources/font/poppins_bold.ttf similarity index 100% rename from app/src/main/res/font/poppins_bold.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_bold.ttf diff --git a/app/src/main/res/font/poppins_bolditalic.ttf b/composeUI/src/commonMain/composeResources/font/poppins_bolditalic.ttf similarity index 100% rename from app/src/main/res/font/poppins_bolditalic.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_bolditalic.ttf diff --git a/app/src/main/res/font/poppins_extrabold.ttf b/composeUI/src/commonMain/composeResources/font/poppins_extrabold.ttf similarity index 100% rename from app/src/main/res/font/poppins_extrabold.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_extrabold.ttf diff --git a/app/src/main/res/font/poppins_extrabolditalic.ttf b/composeUI/src/commonMain/composeResources/font/poppins_extrabolditalic.ttf similarity index 100% rename from app/src/main/res/font/poppins_extrabolditalic.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_extrabolditalic.ttf diff --git a/app/src/main/res/font/poppins_extralight.ttf b/composeUI/src/commonMain/composeResources/font/poppins_extralight.ttf similarity index 100% rename from app/src/main/res/font/poppins_extralight.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_extralight.ttf diff --git a/app/src/main/res/font/poppins_extralightitalic.ttf b/composeUI/src/commonMain/composeResources/font/poppins_extralightitalic.ttf similarity index 100% rename from app/src/main/res/font/poppins_extralightitalic.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_extralightitalic.ttf diff --git a/app/src/main/res/font/poppins_italic.ttf b/composeUI/src/commonMain/composeResources/font/poppins_italic.ttf similarity index 100% rename from app/src/main/res/font/poppins_italic.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_italic.ttf diff --git a/app/src/main/res/font/poppins_light.ttf b/composeUI/src/commonMain/composeResources/font/poppins_light.ttf similarity index 100% rename from app/src/main/res/font/poppins_light.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_light.ttf diff --git a/app/src/main/res/font/poppins_lightitalic.ttf b/composeUI/src/commonMain/composeResources/font/poppins_lightitalic.ttf similarity index 100% rename from app/src/main/res/font/poppins_lightitalic.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_lightitalic.ttf diff --git a/app/src/main/res/font/poppins_medium.ttf b/composeUI/src/commonMain/composeResources/font/poppins_medium.ttf similarity index 100% rename from app/src/main/res/font/poppins_medium.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_medium.ttf diff --git a/app/src/main/res/font/poppins_mediumitalic.ttf b/composeUI/src/commonMain/composeResources/font/poppins_mediumitalic.ttf similarity index 100% rename from app/src/main/res/font/poppins_mediumitalic.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_mediumitalic.ttf diff --git a/app/src/main/res/font/poppins_regular.ttf b/composeUI/src/commonMain/composeResources/font/poppins_regular.ttf similarity index 100% rename from app/src/main/res/font/poppins_regular.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_regular.ttf diff --git a/app/src/main/res/font/poppins_semibold.ttf b/composeUI/src/commonMain/composeResources/font/poppins_semibold.ttf similarity index 100% rename from app/src/main/res/font/poppins_semibold.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_semibold.ttf diff --git a/app/src/main/res/font/poppins_semibolditalic.ttf b/composeUI/src/commonMain/composeResources/font/poppins_semibolditalic.ttf similarity index 100% rename from app/src/main/res/font/poppins_semibolditalic.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_semibolditalic.ttf diff --git a/app/src/main/res/font/poppins_thin.ttf b/composeUI/src/commonMain/composeResources/font/poppins_thin.ttf similarity index 100% rename from app/src/main/res/font/poppins_thin.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_thin.ttf diff --git a/app/src/main/res/font/poppins_thinitalic.ttf b/composeUI/src/commonMain/composeResources/font/poppins_thinitalic.ttf similarity index 100% rename from app/src/main/res/font/poppins_thinitalic.ttf rename to composeUI/src/commonMain/composeResources/font/poppins_thinitalic.ttf diff --git a/composeUI/src/commonMain/composeResources/values-de/strings.xml b/composeUI/src/commonMain/composeResources/values-de/strings.xml new file mode 100644 index 00000000..a56588bb --- /dev/null +++ b/composeUI/src/commonMain/composeResources/values-de/strings.xml @@ -0,0 +1,127 @@ + + + Druckersymbol + Einstellungen + Es wurden keine Scanner gefunden. Bist du mit einem lokalen Netzwerk verbunden? + Warnungssymbol + Fehler + Fehler beim Abrufen der Eigenschaften des Scanners:\n\n%1$s + Okay + Die Eigenschaften des Scanners werden abgerufen + Scannen + Abbrechen + Bricht ab… + Eingescannte Seite + Der Scanauftrag wurde annulliert + Der Scanauftrag wurde aufgrund eines Fehlers abgebrochen + Der Scanauftrag wurde erfolgreich fertiggestellt + Der Scanauftrag ist derzeit noch unerledigt + Es werden derzeit noch Seiten verarbeitet + Der Status des Scanauftrags konnte nicht abrufen werden + Seite löschen + Nach links verschieben + Nach rechts verschieben + Seite %1$s von %2$s + Exportieren + Seite wird abgerufen + Wird exportiert… + Bisher keine Seiten. Klicke den Scanbutton :) + Flachbett + ADF + Verfügbare Scanner + Scannersuche + Einstellungen im eSCLKt-Format kopieren + Scaneinstellungen + Außerhalb des unterstützten Bereichs + Ungültige Nummer + Gültig + Quelle: + Auflösung (DPI): + Duplex + Standard + Breite (in %1$s) + Höhe (in %1$s) + Maximum + Benutzerdefiniert + Ein Scanauftrag läuft bereits + Fehler beim Abrufen einer Seite: %1$s + Kopieren + Fehler + Ungespeicherte Scans + Willst du wirklich die Scanoberfläche schließen? Alle Scans, die du nicht exportiert hast, gehen dabei verloren! + Abbrechen + Verlassen + Appsymbol + Debug + Informationen zu dieser Einstellung + Absturzprotokoll gefunden + Ein Absturzprotokoll wurde gefunden. Dies ist der Fehler der zum Absturz führte. Bitte füge ihn deinem Bugreport an: + OK, löschen + Kamera + Temporäre Dateien gefunden + Temporäre Dateien (Scans und/oder Exporte) wurden im App-Speicher gefunden. Diese Dateien verbleiben im App-Speicher, wenn die App aus der Appübersicht geschlossen oder von Android während einer Scansitzung beendet wurde. Der Hauptgrund für diese Nachfrage ist, dass eine Bestätigung für das Löschen in diesem Fall nicht möglich war.\n\nWas möchtest du mit den folgenden Scan- und Exportdateien machen?:\n%1$s + Löschen + Nichts machen + Nach rechts drehen + Wird gedreht… + Auf einen benutzdefinierten Scanner zugreifen + Verbinden + URL (eSCL-Ressource) + Verbinden mit benutzerdefinierten Scanner + Ungültige URL + Gib bitte eine URL ein + Benutzerdefinierter Scanner + Als PDF exportieren + Als JPEG-Archiv exportieren + Keine weiteren Seiten. %1$s + Fehler beim Herunterladen des empfangenen Bilds als Datei: %1$s + Empfangenes Bild konnte nicht dekodiert werden. %1$s + Scanpreset: + Scanbereich: + Willst du wirklich die derzeitig ausgewählte Seite löschen? Dieser Vorgang ist unwiderruflich. + Debugprotokoll aufzeichnen + Alle Debuglogs werden zu einer in den Einstellungen exportierbaren Datei geschrieben. Dies kann zum Erstellen von Fehlerberichten sehr nützlich sein. + Debugprotokoll löschen + Debugprotokoll exportieren + Diese Einstellung legt fest wie lange ScanBridge maximal auf eine Antwort vom Scanner wartet bevor es den Scanversuch abbricht.\n\nDiese Einstellung ist für langsame Scanner und große Scanbereiche nützlich. + Timeoutlänge für Scannerantwort (in Sekunden) + Erweiterte Einstellungen + + Name + HP Deskjet + Entdeckte Scanner + Gespeicherte Scanner + Max. Seitenzahl für pro PDF + "Da der Arbeitsspeicher von Smartphones begrenzt ist kann es schwierig werden sehr große PDFs zu erzeugen. Um Abstürze zu verhindern, teilt ScanBridge einen PDF-Export auf mehrere PDFs auf, wenn die hier festgelegte Grenze überschritten würde. In diesem Fall werden die PDFs in einem ZIP-Archiv zusammengefasst. Falls gewünscht, können die PDFs dann im Nachhinein zusammengeführt werden. \n\nWarnung: Wenn diese Option zu weit erhöht wird und sehr viele Seiten als PDF exportiert werden sollen, kann es zu Abstürzen kommen." + HTTPS-Zertifikatsüberprüfung umgehen + Diese Einstellung deaktiviert alle Zertifikatsprüfungen bei HTTPS-Verbindungen. Jedes Zertifikat wird folglich akzeptiert, egal ob es ungültig oder selbstsigniert ist. Diese Einstellung sollte nicht in unsicheren Netwerken verwendet werden, denn durch sie wird ein Man-in-the-Middle-Angriff leicht durchführbar.\n\nIn den meisten Fällen werden Scanner in privaten Netzwerken oder über VPN-Verbindungen verwendet, wo Authentizität in der Regel keine große Rolle spielt. In solchen Umgebungen ist es unwahrscheinlich, dass das Deaktivieren der Zertifikatsprüfung ein echtes Sicherheitsrisiko darstellt. Und falls Vertraulichkeit oder Authentizität doch eine Rolle spielen, hilft selbst HTTPS nur begrenzt – denn eSCL bietet keinerlei Client-Authentifizierung. Jeder mit Netzwerkzugriff auf den Scanner kann potenziell auf gescannte Seiten zugreifen. + Speichern der zuletzt verwendeten Scaneinstellungen + Wenn diese Option aktiviert ist, werden die zuletzt verwendeten Scaneinstellungen (z.B. Quelle, Duplex usw.) beim Erstellen einer neuen Scansitzung wiederhergestellt.\n\nWenn sie deaktiviert ist, beginnt jede Sitzung mit den standardmäßigen Scaneinstellungen (höchste Auflösung, größtmöglicher Scanbereich). + Für ScanBridge spenden + Den Quellcode anschauen + In Datei speichern + Bild wird geladen… + Seite zuschneiden + Zuschneiden + Seite wird zugeschnitten… + Zoom-Gesten aktivieren + ScanBridge ist abgestürzt :( + Die Eigenschaften des Scanners sollten bereits abgerufen sein wurden jedoch nicht gefunden. + mm + Zoll + Es tut uns leid. ScanBridge ist abgestürzt. Bitte melde dieses Problem und füge die folgende Fehlermeldung bei (du kannst sie mit der Schaltfläche unten kopieren). + Vorherige Sitzung konnte nicht geladen werden… %1$s + Falls du Hilfe brauchst oder Feedback geben willst, kannst du uns gerne über die E-Mail support@fireamp.eu kontaktieren. Wir werden uns sobald wie möglich bei dir melden! + Danke für deinen Kauf von ScanBridge! + Scan läuft… + Gescannte Seiten werden im Hintergrund abgerufen. + Farbmodus: + Schwarz-Weiß + Farbe ({bitdepth} bit) + Automatische Erkennung + Graustufen ({bitdepth} bit) + Speichern + Benutzerdefinierten Scanner bearbeiten + Willst du den benutzerdefinierten Scanner wirklich löschen? Dieser Vorgang ist unwiderruflich. + Benutzerdefinierten Scanner löschen + \ No newline at end of file diff --git a/composeUI/src/commonMain/composeResources/values-it/strings.xml b/composeUI/src/commonMain/composeResources/values-it/strings.xml new file mode 100644 index 00000000..7ebb1aa4 --- /dev/null +++ b/composeUI/src/commonMain/composeResources/values-it/strings.xml @@ -0,0 +1,126 @@ + + Icona stampante + Impostazioni + Nessuno scanner disponibile. Sei connesso alla rete locale? + Icona di avviso + Errore + Si è verificato un errore durante il tentativo di recuperare le funzionalità dello scanner:\n\n%1$s + OK + Tentativo di recupero delle funzionalità dello scanner + Scansiona + Annullamento in corso… + Pagina scansionata + L\'attività è stata annullata + L\'attività è stata interrotta a causa di un errore + L\'attività è stata completata correttamente + L\'attività è ancora in sospeso + Le pagine sono ancora in elaborazione + Impossibile recuperare lo stato dell\'attività + Elimina la pagina corrente + Scambia con la pagina precedente + Scambia con la pagina successiva + Pagina %1$s di %2$s + Esporta + Recupero della pagina + Esportazione in corso… + Nessuna pagina è stata ancora scansionata. Fai clic sul pulsante Scansiona :) + Piana/Vetro + Alimentatore + Scanner disponibili + Analisi della rete + Copia le impostazioni di scansione correnti in formato eSCLKt + Impostazioni di scansione + Valore fuori dall\'intervallo consentito + Numero non valido + Valido + Sorgente di input: + Risoluzione utilizzata (dpi): + Duplex + Predefinito + Larghezza (in %1$s) + Altezza (in %1$s) + Dimensione massima + Personalizzato + Attività ancora in esecuzione + Errore durante il recupero della pagina: %1$s + Copia + Errore + Scansioni non salvate + Vuoi davvero chiudere l\'attività di scansione? Tutte le scansioni non esportate andranno perse! + Annulla + Esci + Icona applicazione + Debug + Ulteriori informazioni su questa impostazione + Registro degli arresti anomali trovato + Registro degli arresti anomali individuato. Questa è l\'eccezione che ha causato l\'arresto anomalo. Allega questo messaggio alla tua segnalazione di bug: + OK, eliminalo + Fotocamera + Trovati file temporanei + Sono stati trovati file temporanei (scansioni e/o esportazioni) nell\'archivio dell\'app. Si tratta di file che rimangono nell\'archivio dell\'app se l\'app viene chiusa dall\'anteprima o interrotta da Android durante una sessione di scansione. Il motivo principale di questo avviso è che, chiudendo l\'app in questo modo, non era possibile confermare l\'eliminazione.\n\nCosa vuoi fare con i seguenti file di scansione ed esportazione?:\n%1$s + Elimina + Non fare nulla + Ruota a destra + Rotazione in corso… + Accedi allo scanner personalizzato + Connettiti + URL (risorsa eSCL) + Connettiti a uno scanner personalizzato + URL non valido + Per favore inserisci un URL + Scanner personalizzato + Esporta come PDF + Esporta come archivio di file JPEG + Nessuna pagina aggiuntiva. %1$s + Errore durante la copia dell\'immagine ricevuta nel file: %1$s + Impossibile decodificare l\'immagine ricevuta. %1$s + Modalità di scansione: + Area di scansione: + Eliminare la pagina corrente? Questa azione non può essere annullata. + Log di debug + Tutti i dati di log disponibili verranno scritti in un file esportabile. Utile per inviare segnalazioni di bug. + Cancella registro di debug + Esporta registro di debug + Questo timeout indica per quanto tempo ScanBridge aspetta la risposta dello scanner prima di interrompere la scansione.\n\nÈ particolarmente utile quando si usano scanner lenti o si devono scansionare aree molto grandi, che richiedono più tempo per la scansione. + Timeout di risposta (in secondi) + Impostazioni avanzate + + Nome + HP Deskjet + Scanner rilevati + Scanner salvati + Numero massimo di pagine per file PDF + Poiché uno smartphone ha una memoria limitata, può diventare difficile gestire PDF di grandi dimensioni. Per evitare arresti anomali, ScanBridge limita il numero massimo di pagine memorizzate in un file PDF quando si esportano pagine scansionate in PDF. Se ci sono troppe pagine, vengono creati più PDF e archiviati in un archivio ZIP. Se necessario, i file PDF possono essere uniti successivamente.\n\nAttenzione: un aumento eccessivo di questo valore può causare arresti anomali durante l\'esportazione di un numero elevato di pagine. + Disabilita controlli certificati + Questa opzione disabilita la convalida di tutti i certificati HTTPS. Verrà accettato qualsiasi certificato, inclusi quelli autofirmati, scaduti o non validi. Non utilizzare questa opzione su reti pubbliche o non sicure, poiché rende possibili attacchi man-in-the-middle (MitM). Nella maggior parte dei casi, gli scanner vengono utilizzati su reti private o tramite connessioni VPN, dove le criticità sull\'autenticazione sono minime. In tali ambienti, è improbabile che la disabilitazione dei controlli dei certificati rappresenti un rischio reale per la sicurezza. E nel caso in cui la riservatezza o l\'autenticità siano un problema, anche HTTPS non sarà di grande aiuto, poiché eSCL non dispone di autenticazione client. Chiunque abbia accesso alla rete può potenzialmente recuperare le pagine scansionate. + Ricorda le impostazioni di scansione + Se abilitata, quando si crea una nuova sessione di scansione verranno ripristinate le ultime impostazioni di scansione utilizzate (sorgente di input, duplex, ecc.). Se disabilitata, ogni sessione inizia con le impostazioni di scansione predefinite (massima risoluzione, area di scansione più ampia possibile). + Dona a ScanBridge + Codice sorgente + Annulla + Salva in file + Caricamento dell’immagine… + La sessione precedente non può essere caricata… %1$s + Le proprietà dello scanner dovrebbero essere già state recuperate, ma non sono state trovate. + mm + Ritaglia pagina + Ritaglia + La pagina viene ritagliata… + Attiva i gesti di zoom + ScanBridge si è bloccato :( + Ci dispiace. ScanBridge si è bloccato. Si prega di segnalare questo problema e di allegare il seguente messaggio di errore (puoi copiarlo con il pulsante in basso). + pollice + Se hai bisogno di aiuto o vuoi inviarci un feedback, puoi contattarci liberamente all’indirizzo support@fireamp.eu . Ti risponderemo il prima possibile! + Grazie per aver acquistato ScanBridge! + Scansione in corso… + Le pagine scansionate vengono recuperate in background. + Modalità colore: + Bianco e nero + Colore ({bitdepth} bit) + Rilevamento automatico + Scala di grigi ({bitdepth} bit) + Salva + Modifica scanner personalizzato + Vuoi davvero eliminare lo scanner personalizzato? Questa operazione è irreversibile. + Elimina scanner personalizzato + \ No newline at end of file diff --git a/composeUI/src/commonMain/composeResources/values/strings.xml b/composeUI/src/commonMain/composeResources/values/strings.xml new file mode 100644 index 00000000..1d72524c --- /dev/null +++ b/composeUI/src/commonMain/composeResources/values/strings.xml @@ -0,0 +1,129 @@ + + ScanBridge + Printer icon + Settings + No scanners found. Are you connected to a local network? + Warning icon + Error + An error occurred while trying to retrieve scanner capabilities:\n\n%1$s + Okay + Trying to retrieve ScannerCapabilities + Scan + Cancel + Cancelling… + A scanned page + The job was canceled + The job was aborted because of an error + The job was completed successfully + The job is still pending + The pages are still processed + The job state can\'t be retrieved + Delete current page + Swap with previous + Swap with next + Page %1$s of %2$s + Export + Retrieving page + Exporting… + No pages were scanned yet. Click the scan button :) + Platen + ADF + Available scanners + Discovery + Copy current scan options in eSCLKt format + Scan settings + Not in allowed range + Not a valid number + Valid + Input source: + Used Resolution (dpi): + Duplex + Default + Width (in %1$s) + Height (in %1$s) + Maximum size + Custom + Job still running + Error while retrieving page: %1$s + Copy + Error + Scans unsaved + Do you really want to close the scanning interface? Any scans that you didn\'t export will be lost! + Cancel + Leave + App icon + Debug + Info button for the setting + Crash log file exists + A crash log was found. This is the exception which led to the crash. Please attach this to your bug report: + OK, delete it + Camera + Temporary files found + Temporary files (scans and/or exports) were found in the app storage. These are files which remain in the app storage if the app is closed from the overview or killed by Android while being in a scanning session. The main reason for this dialog is that asking for confirmation of deletion was impossible when the app was closed in this way.\n\nWhat do you want to do with the following scan and export files?:\n%1$s + Delete + Do nothing + Rotate right + Rotating… + Access custom scanner + Just connect + URL (eSCL resource) + Connect to a custom scanner + Invalid URL + Please enter an URL + Custom scanner + Export as PDF + Export as archive of JPEGs + No further pages. %1$s + Error while copying received image to file: %1$s + Couldn\'t decode received image. %1$s + Intent: + Scan Region: + Do you really want to delete the current page? This action can not be undone. + Debug log + This will write all available log data to an exportable file. This is useful for submitting bug repots. + Clear debug log + Export debug log + This timeout determines how long ScanBridge waits at maximum for the scanner to respond to requests until it aborts the scan job.\n\nThis is mostly useful for slow scanners and large scan areas which take longer to scan. + Response Timeout (in seconds) + Advanced Settings + + Name + HP Deskjet + Discovered scanners + Saved scanners + Max. pages per PDF file + As a smartphone has limited memory, it can becomes difficult to handle large PDFs. To prevent crashes, ScanBridge limits the maximum count pages stored in one PDF file when exporting scanned pages as PDF. If there are too much pages, multiple PDFs are created and stored into a ZIP archive. These PDFs can be merged afterwards, if needed.\n\nWarning: Increasing this too far can lead to crashes while exporting if a large number of pages are to be exported. + Disable certificate checks + This option disables all HTTPS certificate validation. Any certificate will be accepted, including self-signed, expired, or otherwise invalid ones. Do not use this option on insecure or public networks, as it makes man-in-the-middle (MitM) attacks possible.\n\nIn most cases, scanners are used on private networks or over VPN connections, where concerns about authenticity are minimal. In such environments, disabling certificate checks is unlikely to pose a real security risk. And in case confidentiality or authenticity is a concern, even HTTPS won\'t help much, as eSCL lacks client authentication altogether. Anyone with access to the network can potentially retrieve scanned pages. + Remember scan settings + When enabled, your last used scan settings (input source, duplex, etc.) will be restored when you create a new scan session.\n\nWhen disabled, each session starts with default scan settings (highest resolution, largest possible scan area). + Support development + View source code + F-Droid + Play Store + Save to File + Loading image… + Crop current page + Crop + Cropping page… + Activate zoom gestures + ScanBridge crashed :( + "We are sorry. ScanBridge has crashed. Please report this issue and attach the following stacktrace (you can copy it with the button at the bottom)" + Loading previous session failed… %1$s + The scanner capabilities should be retrieved at this point, but they weren\'t. + mm + Inches + Scanned pages are received in the background. + If you need help or want to provide feedback, contact us anytime at support@fireamp.eu. We will get back to you as quickly as possible! + Thank you for purchasing ScanBridge! + Scan job running… + Color Mode: + + Color ({bitdepth} bit) + Automatic detection + Grayscale ({bitdepth} bit) + Save + Edit custom scanner + Do you really want to delete this custom scanner? This action cannot be undone. + Delete custom scanner + \ No newline at end of file diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/theme/Color.kt b/composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/theme/Color.kt similarity index 90% rename from app/src/main/java/io/github/chrisimx/scanbridge/theme/Color.kt rename to composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/theme/Color.kt index 021f8553..6209286f 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/theme/Color.kt +++ b/composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/theme/Color.kt @@ -19,6 +19,7 @@ package io.github.chrisimx.scanbridge.theme +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color @@ -36,6 +37,6 @@ val Purple = Color(0xFF702CCC) val gradientBrush = Brush.linearGradient( colors = listOf(NiceBlue, Purple), // Colors of the gradient - start = androidx.compose.ui.geometry.Offset.Zero, // Start position - end = androidx.compose.ui.geometry.Offset.Infinite // End position + start = Offset.Zero, // Start position + end = Offset.Infinite // End position ) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/theme/Theme.kt b/composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.kt similarity index 75% rename from app/src/main/java/io/github/chrisimx/scanbridge/theme/Theme.kt rename to composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.kt index bb7cafce..aa346b1e 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/theme/Theme.kt +++ b/composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.kt @@ -19,23 +19,20 @@ package io.github.chrisimx.scanbridge.theme -import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme -import androidx.compose.material3.dynamicDarkColorScheme -import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -private val DarkColorScheme = darkColorScheme( +val DarkColorScheme = darkColorScheme( primary = Purple80, secondary = PurpleGrey80, tertiary = Pink80 ) -private val LightColorScheme = lightColorScheme( +val LightColorScheme = lightColorScheme( primary = Purple40, secondary = PurpleGrey40, tertiary = Pink40 @@ -51,6 +48,12 @@ private val LightColorScheme = lightColorScheme( */ ) +@Composable +expect fun platformDarkColorScheme(): ColorScheme? + +@Composable +expect fun platformLightColorScheme(): ColorScheme? + @Composable fun ScanBridgeTheme( darkTheme: Boolean = isSystemInDarkTheme(), @@ -59,19 +62,13 @@ fun ScanBridgeTheme( content: @Composable () -> Unit ) { val colorScheme = when { - dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { - val context = LocalContext.current - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) - } - - darkTheme -> DarkColorScheme - - else -> LightColorScheme + darkTheme -> platformDarkColorScheme() ?: DarkColorScheme + else -> platformLightColorScheme() ?: LightColorScheme } MaterialTheme( colorScheme = colorScheme, - typography = Typography, + typography = PoppinsTypography(), content = content ) } diff --git a/composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/theme/Typography.kt b/composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/theme/Typography.kt new file mode 100644 index 00000000..ecff2280 --- /dev/null +++ b/composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/theme/Typography.kt @@ -0,0 +1,198 @@ +package io.github.chrisimx.scanbridge.theme + +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.Typography +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp +import org.jetbrains.compose.resources.Font +import scanbridge.composeui.generated.resources.* +import scanbridge.composeui.generated.resources.Res + +@Composable +fun Poppins(): FontFamily = FontFamily( + Font(Res.font.poppins_thin, weight = FontWeight.Thin), + Font(Res.font.poppins_thinitalic, weight = FontWeight.Thin, style = FontStyle.Italic), + + Font(Res.font.poppins_extralight, weight = FontWeight.ExtraLight), + Font(Res.font.poppins_extralightitalic, weight = FontWeight.ExtraLight, style = FontStyle.Italic), + + Font(Res.font.poppins_light, weight = FontWeight.Light), + Font(Res.font.poppins_lightitalic, weight = FontWeight.Light, style = FontStyle.Italic), + + Font(Res.font.poppins_regular, weight = FontWeight.Normal), + Font(Res.font.poppins_italic, weight = FontWeight.Normal, style = FontStyle.Italic), + + Font(Res.font.poppins_medium, weight = FontWeight.Medium), + Font(Res.font.poppins_mediumitalic, weight = FontWeight.Medium, style = FontStyle.Italic), + + Font(Res.font.poppins_semibold, weight = FontWeight.SemiBold), + Font(Res.font.poppins_semibolditalic, weight = FontWeight.SemiBold, style = FontStyle.Italic), + + Font(Res.font.poppins_bold, weight = FontWeight.Bold), + Font(Res.font.poppins_bolditalic, weight = FontWeight.Bold, style = FontStyle.Italic), + + Font(Res.font.poppins_extrabold, weight = FontWeight.ExtraBold), + Font(Res.font.poppins_extrabolditalic, weight = FontWeight.ExtraBold, style = FontStyle.Italic), + + Font(Res.font.poppins_black, weight = FontWeight.Black), + Font(Res.font.poppins_blackitalic, weight = FontWeight.Black, style = FontStyle.Italic) +) + +@OptIn(ExperimentalMaterial3ExpressiveApi::class) +@Composable +fun PoppinsTypography(): Typography { + val poppinsFont = Poppins() + + return Typography( + titleSmall = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 20.sp, + letterSpacing = 0.sp + ), + titleMedium = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + fontSize = 18.sp, + lineHeight = 24.sp, + letterSpacing = 0.sp + ), + titleMediumEmphasized = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.ExtraBold, + fontSize = 18.sp, + lineHeight = 24.sp, + letterSpacing = 0.sp + ), + titleLarge = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + titleLargeEmphasized = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.ExtraBold, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + lineHeight = 14.sp, + fontSize = 11.sp, + letterSpacing = 0.sp + ), + labelMedium = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + lineHeight = 14.sp, + fontSize = 14.sp, + letterSpacing = 0.sp + ), + labelLarge = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + letterSpacing = 0.sp + ), + bodySmall = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + letterSpacing = 0.sp + ), + bodySmallEmphasized = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.ExtraBold, + letterSpacing = 0.sp + ), + bodyMedium = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + letterSpacing = 0.sp + ), + bodyMediumEmphasized = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.ExtraBold, + letterSpacing = 0.sp + ), + bodyLarge = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ), + bodyLargeEmphasized = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.ExtraBold, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ), + displaySmall = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + letterSpacing = 0.sp + ), + displayMedium = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + letterSpacing = 0.sp + ), + displayLarge = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + letterSpacing = 0.sp + ), + displaySmallEmphasized = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.ExtraBold, + letterSpacing = 0.sp + ), + displayMediumEmphasized = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.ExtraBold, + letterSpacing = 0.sp + ), + displayLargeEmphasized = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.ExtraBold, + letterSpacing = 0.sp + ), + headlineLarge = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + fontSize = 24.sp, + lineHeight = 32.sp, + letterSpacing = 0.sp + ), + headlineMedium = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + fontSize = 20.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + headlineMediumEmphasized = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.ExtraBold, + fontSize = 20.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + headlineSmall = TextStyle( + fontFamily = poppinsFont, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.sp + ) + ) +} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/LoadingScreen.kt b/composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/uicomponents/LoadingScreen.kt similarity index 78% rename from app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/LoadingScreen.kt rename to composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/uicomponents/LoadingScreen.kt index 92d16a13..f0c41190 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/uicomponents/LoadingScreen.kt +++ b/composeUI/src/commonMain/kotlin/io/github/chrisimx/scanbridge/uicomponents/LoadingScreen.kt @@ -28,18 +28,24 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import io.github.chrisimx.scanbridge.theme.ScanBridgeTheme +import org.jetbrains.compose.resources.StringResource +import org.jetbrains.compose.resources.stringResource +import scanbridge.composeui.generated.resources.Res +import scanbridge.composeui.generated.resources.trying_to_retrieve_scannercapabilities @Composable -fun LoadingScreen(loadingText: Int) { +fun LoadingScreen(loadingText: StringResource) { Column( modifier = Modifier .fillMaxSize() @@ -60,3 +66,13 @@ fun LoadingScreen(loadingText: Int) { ) } } + +@Composable +@Preview +fun LoadingScreenPreview() { + ScanBridgeTheme { + Scaffold { + LoadingScreen(Res.string.trying_to_retrieve_scannercapabilities) + } + } +} diff --git a/composeUI/src/jvmMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.jvm.kt b/composeUI/src/jvmMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.jvm.kt new file mode 100644 index 00000000..862a0dd4 --- /dev/null +++ b/composeUI/src/jvmMain/kotlin/io/github/chrisimx/scanbridge/theme/Theme.jvm.kt @@ -0,0 +1,10 @@ +package io.github.chrisimx.scanbridge.theme + +import androidx.compose.material3.ColorScheme +import androidx.compose.runtime.Composable + +@Composable +actual fun platformDarkColorScheme(): ColorScheme? = null + +@Composable +actual fun platformLightColorScheme(): ColorScheme? = null diff --git a/core/.gitignore b/core/.gitignore new file mode 100644 index 00000000..92e0b0fb --- /dev/null +++ b/core/.gitignore @@ -0,0 +1,2 @@ +/build +build \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts new file mode 100644 index 00000000..329bec11 --- /dev/null +++ b/core/build.gradle.kts @@ -0,0 +1,91 @@ +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget + +plugins { + alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.android.kmp.library) + alias(libs.plugins.koin) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.ksp) + alias(libs.plugins.room) +} + +kotlin { + compilerOptions { + optIn.add("kotlin.uuid.ExperimentalUuidApi") + freeCompilerArgs.add("-Xnon-local-break-continue") + } +} + +kotlin { + jvm { + compilerOptions { jvmTarget = JvmTarget.JVM_17 } + } + + android { + namespace = "io.github.chrisimx.scanbridge" + compileSdk = 36 + minSdk = 23 + + compilerOptions { + jvmTarget.set( + org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + ) + } + } + + iosArm64() + iosSimulatorArm64() + + sourceSets { + commonMain.dependencies { + api("com.diamondedge:logging:2.1.0") + api(libs.koin.core) + api(libs.koin.annotations) + api(libs.kotlinx.coroutines) + api(libs.kotlinx.serialization.json) + api(libs.ktor.client.core) + api(libs.ktor.logging) + api(libs.esclkt) + + // Room deps + implementation(libs.androidx.room.runtime) + implementation(libs.androidx.sqlite.bundled) + } + + commonTest.dependencies { + implementation(kotlin("test")) + } + + androidMain.dependencies { + api(libs.ktor.client.okhttp) + } + + jvmMain.dependencies { + } + } + + targets + .withType() + .matching { it.konanTarget.family.isAppleFamily } + .configureEach { + binaries { + framework { + baseName = "ScanBridgeCore" + isStatic = true + } + } + } +} + +room { + schemaDirectory("$projectDir/schemas") +} + +dependencies { + add("kspAndroid", libs.androidx.room.compiler) + add("kspJvm", libs.androidx.room.compiler) + add("kspIosSimulatorArm64", libs.androidx.room.compiler) + add("kspIosArm64", libs.androidx.room.compiler) +} diff --git a/app/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/1.json b/core/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/1.json similarity index 100% rename from app/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/1.json rename to core/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/1.json diff --git a/app/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/2.json b/core/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/2.json similarity index 100% rename from app/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/2.json rename to core/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/2.json diff --git a/core/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/3.json b/core/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/3.json new file mode 100644 index 00000000..86a6e511 --- /dev/null +++ b/core/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/3.json @@ -0,0 +1,238 @@ +{ + "formatVersion": 1, + "database": { + "version": 3, + "identityHash": "07cfa3c6a4549c1d0782b1afbe48d17e", + "entities": [ + { + "tableName": "customscanners", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + } + }, + { + "tableName": "scannedpages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`scanId` TEXT NOT NULL, `ownerSessionId` TEXT NOT NULL, `filePath` TEXT NOT NULL, `originalScanSettings` TEXT NOT NULL, `rotation` TEXT NOT NULL, `orderIndex` INTEGER NOT NULL, PRIMARY KEY(`scanId`), FOREIGN KEY(`ownerSessionId`) REFERENCES `sessions`(`sessionId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "scanId", + "columnName": "scanId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ownerSessionId", + "columnName": "ownerSessionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "filePath", + "columnName": "filePath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "originalScanSettings", + "columnName": "originalScanSettings", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rotation", + "columnName": "rotation", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderIndex", + "columnName": "orderIndex", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "scanId" + ] + }, + "indices": [ + { + "name": "index_scannedpages_ownerSessionId", + "unique": false, + "columnNames": [ + "ownerSessionId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_scannedpages_ownerSessionId` ON `${TABLE_NAME}` (`ownerSessionId`)" + }, + { + "name": "index_scannedpages_ownerSessionId_orderIndex", + "unique": true, + "columnNames": [ + "ownerSessionId", + "orderIndex" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_scannedpages_ownerSessionId_orderIndex` ON `${TABLE_NAME}` (`ownerSessionId`, `orderIndex`)" + } + ], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "ownerSessionId" + ], + "referencedColumns": [ + "sessionId" + ] + } + ] + }, + { + "tableName": "sessions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`sessionId` TEXT NOT NULL, `currentScanSettings` TEXT, `currentSettingsUIData` TEXT DEFAULT null, `currentPage` INTEGER NOT NULL, PRIMARY KEY(`sessionId`))", + "fields": [ + { + "fieldPath": "sessionId", + "columnName": "sessionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currentScanSettings", + "columnName": "currentScanSettings", + "affinity": "TEXT" + }, + { + "fieldPath": "currentSettingsUIData", + "columnName": "currentSettingsUIData", + "affinity": "TEXT", + "defaultValue": "null" + }, + { + "fieldPath": "currentPage", + "columnName": "currentPage", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "sessionId" + ] + } + }, + { + "tableName": "tempfiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tempFileId` TEXT NOT NULL, `ownerSessionId` TEXT NOT NULL, `path` TEXT NOT NULL, PRIMARY KEY(`tempFileId`), FOREIGN KEY(`ownerSessionId`) REFERENCES `sessions`(`sessionId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "tempFileId", + "columnName": "tempFileId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ownerSessionId", + "columnName": "ownerSessionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "tempFileId" + ] + }, + "indices": [ + { + "name": "index_tempfiles_ownerSessionId", + "unique": false, + "columnNames": [ + "ownerSessionId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_tempfiles_ownerSessionId` ON `${TABLE_NAME}` (`ownerSessionId`)" + } + ], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "ownerSessionId" + ], + "referencedColumns": [ + "sessionId" + ] + } + ] + }, + { + "tableName": "lastroute", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`route` TEXT NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "route", + "columnName": "route", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '07cfa3c6a4549c1d0782b1afbe48d17e')" + ] + } +} \ No newline at end of file diff --git a/core/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/4.json b/core/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/4.json new file mode 100644 index 00000000..50c594c1 --- /dev/null +++ b/core/schemas/io.github.chrisimx.scanbridge.db.ScanBridgeDb/4.json @@ -0,0 +1,256 @@ +{ + "formatVersion": 1, + "database": { + "version": 4, + "identityHash": "739608178e7b7634ce893a4594feea9a", + "entities": [ + { + "tableName": "customscanners", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + } + }, + { + "tableName": "scannedpages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`scanId` TEXT NOT NULL, `ownerSessionId` TEXT NOT NULL, `filePath` TEXT NOT NULL, `originalScanSettings` TEXT NOT NULL, `rotation` TEXT NOT NULL, `orderIndex` INTEGER NOT NULL, PRIMARY KEY(`scanId`), FOREIGN KEY(`ownerSessionId`) REFERENCES `sessions`(`sessionId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "scanId", + "columnName": "scanId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ownerSessionId", + "columnName": "ownerSessionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "filePath", + "columnName": "filePath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "originalScanSettings", + "columnName": "originalScanSettings", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rotation", + "columnName": "rotation", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderIndex", + "columnName": "orderIndex", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "scanId" + ] + }, + "indices": [ + { + "name": "index_scannedpages_ownerSessionId", + "unique": false, + "columnNames": [ + "ownerSessionId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_scannedpages_ownerSessionId` ON `${TABLE_NAME}` (`ownerSessionId`)" + }, + { + "name": "index_scannedpages_ownerSessionId_orderIndex", + "unique": true, + "columnNames": [ + "ownerSessionId", + "orderIndex" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_scannedpages_ownerSessionId_orderIndex` ON `${TABLE_NAME}` (`ownerSessionId`, `orderIndex`)" + } + ], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "ownerSessionId" + ], + "referencedColumns": [ + "sessionId" + ] + } + ] + }, + { + "tableName": "sessions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`sessionId` TEXT NOT NULL, `currentScanSettings` TEXT, `currentSettingsUIData` TEXT DEFAULT null, `currentPage` INTEGER NOT NULL, PRIMARY KEY(`sessionId`))", + "fields": [ + { + "fieldPath": "sessionId", + "columnName": "sessionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currentScanSettings", + "columnName": "currentScanSettings", + "affinity": "TEXT" + }, + { + "fieldPath": "currentSettingsUIData", + "columnName": "currentSettingsUIData", + "affinity": "TEXT", + "defaultValue": "null" + }, + { + "fieldPath": "currentPage", + "columnName": "currentPage", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "sessionId" + ] + } + }, + { + "tableName": "tempfiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tempFileId` TEXT NOT NULL, `ownerSessionId` TEXT NOT NULL, `path` TEXT NOT NULL, PRIMARY KEY(`tempFileId`), FOREIGN KEY(`ownerSessionId`) REFERENCES `sessions`(`sessionId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "tempFileId", + "columnName": "tempFileId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ownerSessionId", + "columnName": "ownerSessionId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "tempFileId" + ] + }, + "indices": [ + { + "name": "index_tempfiles_ownerSessionId", + "unique": false, + "columnNames": [ + "ownerSessionId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_tempfiles_ownerSessionId` ON `${TABLE_NAME}` (`ownerSessionId`)" + } + ], + "foreignKeys": [ + { + "table": "sessions", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "ownerSessionId" + ], + "referencedColumns": [ + "sessionId" + ] + } + ] + }, + { + "tableName": "lastroute", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`route` TEXT NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "route", + "columnName": "route", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "executedmigrationtoroom", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`migrationId` TEXT NOT NULL, PRIMARY KEY(`migrationId`))", + "fields": [ + { + "fieldPath": "migrationId", + "columnName": "migrationId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "migrationId" + ] + } + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '739608178e7b7634ce893a4594feea9a')" + ] + } +} \ No newline at end of file diff --git a/core/src/androidMain/kotlin/AndroidHttpClientFactory.kt b/core/src/androidMain/kotlin/AndroidHttpClientFactory.kt new file mode 100644 index 00000000..dca1f40f --- /dev/null +++ b/core/src/androidMain/kotlin/AndroidHttpClientFactory.kt @@ -0,0 +1,38 @@ +import io.github.chrisimx.scanbridge.model.HttpClientConfig +import io.github.chrisimx.scanbridge.ports.HttpClientFactory +import io.github.chrisimx.scanbridge.ports.ScanBridgeLoggerFactory +import io.ktor.client.HttpClient +import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging + +class AndroidHttpClientFactory(loggerFactory: ScanBridgeLoggerFactory) : HttpClientFactory { + val httpClientLogger = loggerFactory.withTag("AndroidHttpClient") + + override fun create(config: HttpClientConfig): HttpClient = HttpClient(OkHttp) { + install(HttpTimeout) { + requestTimeoutMillis = config.timeoutInSeconds.toLong() * 1000 + connectTimeoutMillis = config.timeoutInSeconds.toLong() * 1000 + socketTimeoutMillis = config.timeoutInSeconds.toLong() * 1000 + } + if (config.debugLogging) { + install(Logging) { + logger = object : Logger { + override fun log(message: String) { + httpClientLogger.debug { message } + } + } + } + } + if (config.disableCertValidation) { + engine { + config { + val (socketFactory, trustManager) = getTrustAllTM() + sslSocketFactory(socketFactory, trustManager) + hostnameVerifier { _, _ -> true } + } + } + } + } +} diff --git a/core/src/androidMain/kotlin/AndroidScanBridgeDbBuilderFactory.kt b/core/src/androidMain/kotlin/AndroidScanBridgeDbBuilderFactory.kt new file mode 100644 index 00000000..8f522fea --- /dev/null +++ b/core/src/androidMain/kotlin/AndroidScanBridgeDbBuilderFactory.kt @@ -0,0 +1,13 @@ +import android.content.Context +import androidx.room.Room +import androidx.room.RoomDatabase +import io.github.chrisimx.scanbridge.db.ScanBridgeDb +import io.github.chrisimx.scanbridge.db.ScanBridgeDbBuilderFactory + +class AndroidScanBridgeDbBuilderFactory(private val context: Context) : ScanBridgeDbBuilderFactory { + override fun getBuilder(): RoomDatabase.Builder { + val databaseFile = context.getDatabasePath("scanbridge") + val builder = Room.databaseBuilder(context, databaseFile.absolutePath) + return builder + } +} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/TrustAllTrustManager.kt b/core/src/androidMain/kotlin/TrustAllTrustManager.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/TrustAllTrustManager.kt rename to core/src/androidMain/kotlin/TrustAllTrustManager.kt diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/LastRouteRepository.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/LastRouteRepository.kt new file mode 100644 index 00000000..d7027afc --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/LastRouteRepository.kt @@ -0,0 +1,6 @@ +package io.github.chrisimx.scanbridge + +interface LastRouteRepository { + suspend fun getLastRoute(): String? + suspend fun setLastRoute(route: String?) +} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/data/model/PaperFormat.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/PaperFormat.kt similarity index 97% rename from app/src/main/java/io/github/chrisimx/scanbridge/data/model/PaperFormat.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/PaperFormat.kt index b315c118..411cd7d4 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/data/model/PaperFormat.kt +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/PaperFormat.kt @@ -1,4 +1,4 @@ -package io.github.chrisimx.scanbridge.data.model +package io.github.chrisimx.scanbridge import io.github.chrisimx.esclkt.LengthUnit import io.github.chrisimx.esclkt.Millimeters diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/util/ScanSettingsJson.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ScanSettingsJson.kt similarity index 95% rename from app/src/main/java/io/github/chrisimx/scanbridge/util/ScanSettingsJson.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ScanSettingsJson.kt index 9b1ff20e..7a320eac 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/util/ScanSettingsJson.kt +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ScanSettingsJson.kt @@ -1,4 +1,4 @@ -package io.github.chrisimx.scanbridge.util +package io.github.chrisimx.scanbridge import io.github.chrisimx.esclkt.Inches import io.github.chrisimx.esclkt.LengthUnit diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ShownMessagesRepository.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ShownMessagesRepository.kt new file mode 100644 index 00000000..af6b8460 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ShownMessagesRepository.kt @@ -0,0 +1,12 @@ +package io.github.chrisimx.scanbridge + +import kotlinx.coroutines.flow.Flow + +interface ShownMessagesRepository { + fun getWasShownFlow(message: UserInformationMessage): Flow + suspend fun setShown(message: UserInformationMessage, shown: Boolean) +} + +enum class UserInformationMessage(val playOnly: Boolean) { + THANKS_FOR_PURCHASE(true) +} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/ScanBridgeDb.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/ScanBridgeDb.kt similarity index 68% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/ScanBridgeDb.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/ScanBridgeDb.kt index 04734596..376e8f42 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/db/ScanBridgeDb.kt +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/ScanBridgeDb.kt @@ -5,10 +5,14 @@ import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters import io.github.chrisimx.scanbridge.db.daos.CustomScannerDao +import io.github.chrisimx.scanbridge.db.daos.ExecutedMigrationsDao +import io.github.chrisimx.scanbridge.db.daos.LastRouteDao import io.github.chrisimx.scanbridge.db.daos.ScannedPageDao import io.github.chrisimx.scanbridge.db.daos.SessionDao import io.github.chrisimx.scanbridge.db.daos.TempFileDao import io.github.chrisimx.scanbridge.db.entities.CustomScanner +import io.github.chrisimx.scanbridge.db.entities.ExecutedMigrationToRoom +import io.github.chrisimx.scanbridge.db.entities.LastRoute import io.github.chrisimx.scanbridge.db.entities.ScannedPage import io.github.chrisimx.scanbridge.db.entities.Session import io.github.chrisimx.scanbridge.db.entities.TempFile @@ -18,12 +22,22 @@ import io.github.chrisimx.scanbridge.db.typeconverters.UrlTypeConverter import io.github.chrisimx.scanbridge.db.typeconverters.UuidTypeConverter @Database( - entities = [CustomScanner::class, ScannedPage::class, Session::class, TempFile::class], - version = 2, + entities = [ + CustomScanner::class, ScannedPage::class, Session::class, TempFile::class, LastRoute::class, ExecutedMigrationToRoom::class + ], + version = 4, autoMigrations = [ AutoMigration( from = 1, to = 2 + ), + AutoMigration( + from = 2, + to = 3 + ), + AutoMigration( + from = 3, + to = 4 ) ] ) @@ -38,4 +52,6 @@ abstract class ScanBridgeDb : RoomDatabase() { abstract fun scannedPageDao(): ScannedPageDao abstract fun sessionDao(): SessionDao abstract fun tmpFileDao(): TempFileDao + abstract fun lastRouteDao(): LastRouteDao + abstract fun executedMigrationsDao(): ExecutedMigrationsDao } diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/ScanBridgeDbBuilderFactory.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/ScanBridgeDbBuilderFactory.kt new file mode 100644 index 00000000..8f8866fb --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/ScanBridgeDbBuilderFactory.kt @@ -0,0 +1,7 @@ +package io.github.chrisimx.scanbridge.db + +import androidx.room.RoomDatabase + +interface ScanBridgeDbBuilderFactory { + fun getBuilder(): RoomDatabase.Builder +} diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/ScanBridgeDbFactory.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/ScanBridgeDbFactory.kt new file mode 100644 index 00000000..5980bea5 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/ScanBridgeDbFactory.kt @@ -0,0 +1,19 @@ +package io.github.chrisimx.scanbridge.db + +import androidx.sqlite.driver.bundled.BundledSQLiteDriver +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO + +interface ScanBridgeDbFactory { + fun createInstance(): ScanBridgeDb +} + +class DefaultScanBridgeDbFactory(val builderFactory: ScanBridgeDbBuilderFactory) : ScanBridgeDbFactory { + override fun createInstance(): ScanBridgeDb { + val dbBuilder = builderFactory.getBuilder() + return dbBuilder + .setDriver(BundledSQLiteDriver()) + .setQueryCoroutineContext(Dispatchers.IO) + .build() + } +} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/daos/CustomScannerDao.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/CustomScannerDao.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/daos/CustomScannerDao.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/CustomScannerDao.kt diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/ExecutedMigrationsDao.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/ExecutedMigrationsDao.kt new file mode 100644 index 00000000..778ba47b --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/ExecutedMigrationsDao.kt @@ -0,0 +1,18 @@ +package io.github.chrisimx.scanbridge.db.daos + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import io.github.chrisimx.scanbridge.db.entities.ExecutedMigrationToRoom + +@Dao +interface ExecutedMigrationsDao { + @Insert(onConflict = OnConflictStrategy.IGNORE) + fun markAsExecuted(migration: ExecutedMigrationToRoom) + + @Query("SELECT * FROM executedmigrationtoroom WHERE migrationId = :id") + fun getExecutedMigration(id: String): ExecutedMigrationToRoom? + + fun isAlreadyDone(id: String): Boolean = getExecutedMigration(id) != null +} diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/LastRouteDao.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/LastRouteDao.kt new file mode 100644 index 00000000..807a0c24 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/LastRouteDao.kt @@ -0,0 +1,19 @@ +package io.github.chrisimx.scanbridge.db.daos + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import io.github.chrisimx.scanbridge.db.entities.LastRoute + +@Dao +interface LastRouteDao { + @Query("SELECT * FROM lastroute WHERE id = 1") + suspend fun getLastRoute(): LastRoute? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun setLastRoute(lastRoute: LastRoute) + + @Query("DELETE FROM lastroute WHERE id = 1") + suspend fun clearLastRoute() +} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/daos/ScannedPageDao.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/ScannedPageDao.kt similarity index 96% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/daos/ScannedPageDao.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/ScannedPageDao.kt index d4ea1a32..c9786d7c 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/db/daos/ScannedPageDao.kt +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/ScannedPageDao.kt @@ -9,7 +9,6 @@ import androidx.room.Update import io.github.chrisimx.scanbridge.db.entities.ScannedPage import kotlin.uuid.Uuid import kotlinx.coroutines.flow.Flow -import timber.log.Timber @Dao interface ScannedPageDao { @@ -40,7 +39,6 @@ interface ScannedPageDao { val page2 = getByScanId(page2.scanId) if (page1 == null || page2 == null) { - Timber.e("Could not swap pages: $page1, $page2") return } diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/daos/SessionDao.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/SessionDao.kt similarity index 93% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/daos/SessionDao.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/SessionDao.kt index 590e0361..9b642770 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/db/daos/SessionDao.kt +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/SessionDao.kt @@ -5,8 +5,8 @@ import androidx.room.Delete import androidx.room.Insert import androidx.room.Query import androidx.room.Update -import io.github.chrisimx.scanbridge.data.ui.ScanSettingsStateData import io.github.chrisimx.scanbridge.db.entities.Session +import io.github.chrisimx.scanbridge.model.ScanSettingsEnterableData import kotlin.uuid.Uuid import kotlinx.coroutines.flow.Flow @@ -37,7 +37,7 @@ interface SessionDao { suspend fun updateCurrentPage(sessionId: Uuid, pageIdx: Int) @Query("UPDATE sessions SET currentSettingsUIData = :uiData WHERE sessionId = :sessionId") - suspend fun updateScanSettingsUiData(sessionId: Uuid, uiData: ScanSettingsStateData?) + suspend fun updateScanSettingsUiData(sessionId: Uuid, uiData: ScanSettingsEnterableData?) @Delete suspend fun delete(session: Session) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/daos/TempFileDao.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/TempFileDao.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/daos/TempFileDao.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/daos/TempFileDao.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/entities/CustomScanner.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/CustomScanner.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/entities/CustomScanner.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/CustomScanner.kt diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/ExecutedMigrationToRoom.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/ExecutedMigrationToRoom.kt new file mode 100644 index 00000000..88d21686 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/ExecutedMigrationToRoom.kt @@ -0,0 +1,10 @@ +package io.github.chrisimx.scanbridge.db.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "executedmigrationtoroom") +data class ExecutedMigrationToRoom( + @PrimaryKey + val migrationId: String +) diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/LastRoute.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/LastRoute.kt new file mode 100644 index 00000000..7a233d28 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/LastRoute.kt @@ -0,0 +1,7 @@ +package io.github.chrisimx.scanbridge.db.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "lastroute") +data class LastRoute(val route: String, @PrimaryKey val id: Int = 1) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/entities/ScannedPage.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/ScannedPage.kt similarity index 93% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/entities/ScannedPage.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/ScannedPage.kt index 2c1da1c8..77601bb3 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/db/entities/ScannedPage.kt +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/ScannedPage.kt @@ -5,7 +5,7 @@ import androidx.room.ForeignKey import androidx.room.Index import androidx.room.PrimaryKey import io.github.chrisimx.esclkt.ScanSettings -import io.github.chrisimx.scanbridge.data.ui.ScanRelativeRotation +import io.github.chrisimx.scanbridge.model.ScanRelativeRotation import kotlin.uuid.Uuid @Entity( diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/entities/Session.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/Session.kt similarity index 76% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/entities/Session.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/Session.kt index d2161d54..76d4024c 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/db/entities/Session.kt +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/Session.kt @@ -4,7 +4,7 @@ import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import io.github.chrisimx.esclkt.ScanSettings -import io.github.chrisimx.scanbridge.data.ui.ScanSettingsStateData +import io.github.chrisimx.scanbridge.model.ScanSettingsEnterableData import kotlin.uuid.Uuid @Entity(tableName = "sessions") @@ -13,6 +13,6 @@ data class Session( val sessionId: Uuid, val currentScanSettings: ScanSettings?, @ColumnInfo(defaultValue = "null") - val currentSettingsUIData: ScanSettingsStateData?, + val currentSettingsUIData: ScanSettingsEnterableData?, val currentPage: Int = 0 ) diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/entities/TempFile.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/TempFile.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/entities/TempFile.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/entities/TempFile.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsTypeConverter.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsTypeConverter.kt similarity index 91% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsTypeConverter.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsTypeConverter.kt index bb0dcc94..761d2840 100644 --- a/app/src/main/java/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsTypeConverter.kt +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsTypeConverter.kt @@ -2,7 +2,7 @@ package io.github.chrisimx.scanbridge.db.typeconverters import androidx.room.TypeConverter import io.github.chrisimx.esclkt.ScanSettings -import io.github.chrisimx.scanbridge.util.ScanSettingsJson +import io.github.chrisimx.scanbridge.ScanSettingsJson class ScanSettingsTypeConverter { diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsUiDataTypeConverter.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsUiDataTypeConverter.kt new file mode 100644 index 00000000..0046b2fc --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/typeconverters/ScanSettingsUiDataTypeConverter.kt @@ -0,0 +1,22 @@ +package io.github.chrisimx.scanbridge.db.typeconverters + +import androidx.room.TypeConverter +import io.github.chrisimx.scanbridge.ScanSettingsJson +import io.github.chrisimx.scanbridge.model.ScanSettingsEnterableData + +class ScanSettingsUiDataTypeConverter { + + @TypeConverter + fun fromScanSettingsString(scanSettings: String): ScanSettingsEnterableData? = if (scanSettings == "null") { + null + } else { + ScanSettingsJson.json.decodeFromString(scanSettings) + } + + @TypeConverter + fun toScanSettingsString(scanSettings: ScanSettingsEnterableData?): String = if (scanSettings == null) { + "null" + } else { + ScanSettingsJson.json.encodeToString(scanSettings) + } +} diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/typeconverters/UrlTypeConverter.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/typeconverters/UrlTypeConverter.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/typeconverters/UrlTypeConverter.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/typeconverters/UrlTypeConverter.kt diff --git a/app/src/main/java/io/github/chrisimx/scanbridge/db/typeconverters/UuidTypeConverter.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/typeconverters/UuidTypeConverter.kt similarity index 100% rename from app/src/main/java/io/github/chrisimx/scanbridge/db/typeconverters/UuidTypeConverter.kt rename to core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/db/typeconverters/UuidTypeConverter.kt diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/infrastructure/KmLogScanBridgeLogger.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/infrastructure/KmLogScanBridgeLogger.kt new file mode 100644 index 00000000..5a4d04b2 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/infrastructure/KmLogScanBridgeLogger.kt @@ -0,0 +1,33 @@ +package io.github.chrisimx.scanbridge.infrastructure + +import com.diamondedge.logging.KmLog +import com.diamondedge.logging.logging +import io.github.chrisimx.scanbridge.ports.ScanBridgeLogger + +class KmLogScanBridgeLogger(tag: String) : ScanBridgeLogger { + private val logger: KmLog = logging(tag) + + override fun verbose(tag: String?, msg: () -> String) { + logger.v(tag, msg) + } + + override fun debug(tag: String?, msg: () -> String) { + logger.d(tag, msg) + } + + override fun info(tag: String?, msg: () -> String) { + logger.i(tag, msg) + } + + override fun warn(t: Throwable?, tag: String?, msg: () -> String) { + logger.w(t, tag, msg) + } + + override fun error(t: Throwable?, tag: String?, msg: () -> String) { + logger.e(t, tag, msg) + } + + override fun wtf(t: Throwable?, tag: String?, msg: () -> String) { + logger.e(t, tag, msg) + } +} diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/infrastructure/KmLogScanBridgeLoggerFactory.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/infrastructure/KmLogScanBridgeLoggerFactory.kt new file mode 100644 index 00000000..0e562d33 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/infrastructure/KmLogScanBridgeLoggerFactory.kt @@ -0,0 +1,17 @@ +package io.github.chrisimx.scanbridge.infrastructure + +import io.github.chrisimx.scanbridge.infrastructure.KmLogScanBridgeLogger +import io.github.chrisimx.scanbridge.ports.ScanBridgeLogger +import io.github.chrisimx.scanbridge.ports.ScanBridgeLoggerFactory +import kotlin.reflect.KClass + +class KmLogScanBridgeLoggerFactory : ScanBridgeLoggerFactory { + override fun withClass(clazz: KClass): ScanBridgeLogger { + val tag = clazz.simpleName ?: "Unknown" + return KmLogScanBridgeLogger( + tag + ) + } + + override fun withTag(tag: String): ScanBridgeLogger = KmLogScanBridgeLogger(tag) +} diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/DiscoveredScanner.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/DiscoveredScanner.kt new file mode 100644 index 00000000..4bdbfe85 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/DiscoveredScanner.kt @@ -0,0 +1,3 @@ +package io.github.chrisimx.scanbridge.model + +data class DiscoveredScanner(val name: String, val addresses: List) diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/HttpClientConfig.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/HttpClientConfig.kt new file mode 100644 index 00000000..16484b2e --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/HttpClientConfig.kt @@ -0,0 +1,3 @@ +package io.github.chrisimx.scanbridge.model + +data class HttpClientConfig(val disableCertValidation: Boolean, val debugLogging: Boolean, val timeoutInSeconds: ULong) diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/Locale.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/Locale.kt new file mode 100644 index 00000000..1e61000f --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/Locale.kt @@ -0,0 +1,8 @@ +package io.github.chrisimx.scanbridge.model + +data class Locale( + /** + * The two character country code in uppercase + */ + val country: String +) diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/NumberValidationResult.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/NumberValidationResult.kt new file mode 100644 index 00000000..d8440620 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/NumberValidationResult.kt @@ -0,0 +1,10 @@ +package io.github.chrisimx.scanbridge.model + +import kotlinx.serialization.Serializable + +@Serializable +sealed class NumberValidationResult { + data class Success(val value: Double) : NumberValidationResult() + data class OutOfRange(val min: Double, val max: Double) : NumberValidationResult() + data object NotANumber : NumberValidationResult() +} diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanBridgeFile.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanBridgeFile.kt new file mode 100644 index 00000000..4fe327c1 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanBridgeFile.kt @@ -0,0 +1,5 @@ +package io.github.chrisimx.scanbridge.model + +import kotlinx.io.files.Path + +data class ScanBridgeFile(val path: Path) diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanJob.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanJob.kt new file mode 100644 index 00000000..b4aa2563 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanJob.kt @@ -0,0 +1,13 @@ +package io.github.chrisimx.scanbridge.model + +import io.github.chrisimx.esclkt.ScanSettings +import io.ktor.http.Url +import kotlin.uuid.Uuid + +data class ScanJob( + val jobID: Uuid, + val ownerSessionId: Uuid, + val scanSettings: ScanSettings, + val scannerBaseUrl: Url, + val httpClientConfig: HttpClientConfig +) diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanRelativeRotation.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanRelativeRotation.kt new file mode 100644 index 00000000..559218e5 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanRelativeRotation.kt @@ -0,0 +1,11 @@ +package io.github.chrisimx.scanbridge.model + +enum class ScanRelativeRotation { + Rotated, + Original +} + +fun ScanRelativeRotation.toggleRotation() = when (this) { + ScanRelativeRotation.Rotated -> ScanRelativeRotation.Original + ScanRelativeRotation.Original -> ScanRelativeRotation.Rotated +} diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanSettingsEnterableData.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanSettingsEnterableData.kt new file mode 100644 index 00000000..71806903 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/model/ScanSettingsEnterableData.kt @@ -0,0 +1,16 @@ +package io.github.chrisimx.scanbridge.model + +import io.github.chrisimx.esclkt.ScannerCapabilities +import io.github.chrisimx.scanbridge.PaperFormat +import io.github.chrisimx.scanbridge.loadDefaultFormats +import kotlinx.serialization.Serializable + +@Serializable +data class ScanSettingsEnterableData( + val capabilities: ScannerCapabilities, + val paperFormats: List = loadDefaultFormats(), + val customMenuEnabled: Boolean = false, + val widthString: String = "", + val heightString: String = "", + val maximumSize: Boolean = true +) diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/HttpClientFactory.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/HttpClientFactory.kt new file mode 100644 index 00000000..6b74a1b4 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/HttpClientFactory.kt @@ -0,0 +1,8 @@ +package io.github.chrisimx.scanbridge.ports + +import io.github.chrisimx.scanbridge.model.HttpClientConfig +import io.ktor.client.HttpClient + +interface HttpClientFactory { + fun create(config: HttpClientConfig): HttpClient +} diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/LocaleProvider.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/LocaleProvider.kt new file mode 100644 index 00000000..903c7a32 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/LocaleProvider.kt @@ -0,0 +1,11 @@ +package io.github.chrisimx.scanbridge.ports + +import io.github.chrisimx.scanbridge.model.Locale +import kotlinx.coroutines.flow.StateFlow + +/** + * Provides the currently selected [io.github.chrisimx.scanbridge.model.Locale] as a reactive stream. + */ +interface LocaleProvider { + val locale: StateFlow +} diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/ScanBridgeLogger.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/ScanBridgeLogger.kt new file mode 100644 index 00000000..7c47afb8 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/ScanBridgeLogger.kt @@ -0,0 +1,21 @@ +package io.github.chrisimx.scanbridge.ports + +interface ScanBridgeLogger { + /** Log a verbose message */ + fun verbose(tag: String? = null, msg: () -> String) + + /** Log a debug message */ + fun debug(tag: String? = null, msg: () -> String) + + /** Log an info message */ + fun info(tag: String? = null, msg: () -> String) + + /** Log a warning message with optional throwable */ + fun warn(t: Throwable? = null, tag: String? = null, msg: () -> String) + + /** Log an error message with optional throwable */ + fun error(t: Throwable? = null, tag: String? = null, msg: () -> String) + + /** Log a critical/fatal message with optional throwable */ + fun wtf(t: Throwable? = null, tag: String? = null, msg: () -> String) +} diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/ScanBridgeLoggerFactory.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/ScanBridgeLoggerFactory.kt new file mode 100644 index 00000000..05f88004 --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/ScanBridgeLoggerFactory.kt @@ -0,0 +1,9 @@ +package io.github.chrisimx.scanbridge.ports + +import io.github.chrisimx.scanbridge.ports.ScanBridgeLogger +import kotlin.reflect.KClass + +interface ScanBridgeLoggerFactory { + fun withClass(clazz: KClass): ScanBridgeLogger + fun withTag(tag: String): ScanBridgeLogger +} diff --git a/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/ZipService.kt b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/ZipService.kt new file mode 100644 index 00000000..e58c298e --- /dev/null +++ b/core/src/commonMain/kotlin/io/github/chrisimx/scanbridge/ports/ZipService.kt @@ -0,0 +1,7 @@ +package io.github.chrisimx.scanbridge.ports + +import io.github.chrisimx.scanbridge.model.ScanBridgeFile + +interface ZipService { + fun zip(files: List, output: ScanBridgeFile, mapFileName: (ScanBridgeFile) -> String = { it.path.name }) +} diff --git a/app/src/test/java/org/github/chrisimx/scanbridge/PaperFormatTest.kt b/core/src/commonTest/kotlin/PaperFormatTest.kt similarity index 90% rename from app/src/test/java/org/github/chrisimx/scanbridge/PaperFormatTest.kt rename to core/src/commonTest/kotlin/PaperFormatTest.kt index ac6ecd0e..24d98aeb 100644 --- a/app/src/test/java/org/github/chrisimx/scanbridge/PaperFormatTest.kt +++ b/core/src/commonTest/kotlin/PaperFormatTest.kt @@ -17,11 +17,9 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -package org.github.chrisimx.scanbridge - -import io.github.chrisimx.scanbridge.data.model.loadDefaultFormats -import junit.framework.TestCase.assertEquals -import org.junit.Test +import io.github.chrisimx.scanbridge.loadDefaultFormats +import kotlin.test.Test +import kotlin.test.assertEquals class PaperFormatTest { diff --git a/core/src/iosMain/kotlin/IosScanBridgeDbBuilderFactory.kt b/core/src/iosMain/kotlin/IosScanBridgeDbBuilderFactory.kt new file mode 100644 index 00000000..561cafe2 --- /dev/null +++ b/core/src/iosMain/kotlin/IosScanBridgeDbBuilderFactory.kt @@ -0,0 +1,29 @@ +import androidx.room.Room +import androidx.room.RoomDatabase +import io.github.chrisimx.scanbridge.db.ScanBridgeDb +import io.github.chrisimx.scanbridge.db.ScanBridgeDbBuilderFactory +import kotlinx.cinterop.ExperimentalForeignApi +import platform.Foundation.NSDocumentDirectory +import platform.Foundation.NSFileManager +import platform.Foundation.NSUserDomainMask + +class IosScanBridgeDbBuilderFactory : ScanBridgeDbBuilderFactory { + override fun getBuilder(): RoomDatabase.Builder { + val dbFilePath = documentDirectory() + "/scanbridge.db" + return Room.databaseBuilder( + name = dbFilePath + ) + } + + @OptIn(ExperimentalForeignApi::class) + private fun documentDirectory(): String { + val documentDirectory = NSFileManager.defaultManager.URLForDirectory( + directory = NSDocumentDirectory, + inDomain = NSUserDomainMask, + appropriateForURL = null, + create = false, + error = null + ) + return requireNotNull(documentDirectory?.path) + } +} diff --git a/desktopApp/.gitignore b/desktopApp/.gitignore new file mode 100644 index 00000000..c795b054 --- /dev/null +++ b/desktopApp/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/desktopApp/appIcons/LinuxIcon.png b/desktopApp/appIcons/LinuxIcon.png new file mode 100644 index 00000000..a2a45177 Binary files /dev/null and b/desktopApp/appIcons/LinuxIcon.png differ diff --git a/desktopApp/appIcons/MacosIcon.icns b/desktopApp/appIcons/MacosIcon.icns new file mode 100644 index 00000000..083def59 Binary files /dev/null and b/desktopApp/appIcons/MacosIcon.icns differ diff --git a/desktopApp/appIcons/WindowsIcon.ico b/desktopApp/appIcons/WindowsIcon.ico new file mode 100644 index 00000000..7e9ab754 Binary files /dev/null and b/desktopApp/appIcons/WindowsIcon.ico differ diff --git a/desktopApp/build.gradle.kts b/desktopApp/build.gradle.kts new file mode 100644 index 00000000..52c51045 --- /dev/null +++ b/desktopApp/build.gradle.kts @@ -0,0 +1,33 @@ +import org.jetbrains.compose.desktop.application.dsl.TargetFormat + +plugins { + alias(libs.plugins.compose.compiler) + alias(libs.plugins.compose.multiplatform) + alias(libs.plugins.kotlin.jvm) +} +dependencies { + implementation(project(":composeUI")) +} + +compose.desktop { + application { + mainClass = "MainKt" + + nativeDistributions { + targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) + packageName = "ScanBridge" + packageVersion = "1.0.0" + + linux { + iconFile.set(project.file("appIcons/LinuxIcon.png")) + } + windows { + iconFile.set(project.file("appIcons/WindowsIcon.ico")) + } + macOS { + iconFile.set(project.file("appIcons/MacosIcon.icns")) + bundleID = "io.github.chrisimx.scanbridge.desktopApp" + } + } + } +} diff --git a/desktopApp/src/main/kotlin/Main.kt b/desktopApp/src/main/kotlin/Main.kt new file mode 100644 index 00000000..be251960 --- /dev/null +++ b/desktopApp/src/main/kotlin/Main.kt @@ -0,0 +1,17 @@ +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.application +import androidx.compose.ui.window.rememberWindowState +import io.github.chrisimx.scanbridge.App +import java.awt.Dimension + +fun main() = application { + Window( + title = "ScanBridge", + state = rememberWindowState(width = 800.dp, height = 600.dp), + onCloseRequest = ::exitApplication + ) { + window.minimumSize = Dimension(350, 600) + App() + } +} diff --git a/gradle.properties b/gradle.properties index 3ce09d6d..fa120c01 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,28 @@ +#Gradle +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx4G -Dfile.encoding=UTF-8 +org.gradle.caching=true +org.gradle.configuration-cache=true +org.gradle.daemon=true +org.gradle.parallel=true + +#Kotlin +kotlin.daemon.jvmargs=-Xmx4G +kotlin.native.binary.gc=cms +kotlin.incremental.wasm=true + +#https://youtrack.jetbrains.com/issue/KT-82395 +kotlin.incremental.js=false +kotlin.incremental.js.klib=false + # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 + # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. For more details, visit # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties index c4e7acbd..5c34300f 100644 --- a/gradle/gradle-daemon-jvm.properties +++ b/gradle/gradle-daemon-jvm.properties @@ -1,13 +1,13 @@ #This file is generated by updateDaemonJvm -toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/29ee363f71d060405f729a8f1b7f7aef/redirect -toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/67a0fee3c4236b6397dcbe8575ca2011/redirect -toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect -toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/67a0fee3c4236b6397dcbe8575ca2011/redirect -toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/0b98aec810298c2c1d7fdac5dac37910/redirect -toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/658299a896470fbb3103ba3a430ee227/redirect -toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/29ee363f71d060405f729a8f1b7f7aef/redirect -toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/67a0fee3c4236b6397dcbe8575ca2011/redirect -toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/248ffb1098f61659502d0c09aa348294/redirect -toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/ac151d55def6b6a9a159dc4cb4642851/redirect +toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/56a19bc915b9ba2eb62ba7554c61b919/redirect +toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/398ffe3949748bfb1d5636f023d228fd/redirect +toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/56a19bc915b9ba2eb62ba7554c61b919/redirect +toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/398ffe3949748bfb1d5636f023d228fd/redirect +toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e99bae143b75f9a10ead10248f02055e/redirect +toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/04e088f8677de3b384108493cc9481d0/redirect +toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/56a19bc915b9ba2eb62ba7554c61b919/redirect +toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/398ffe3949748bfb1d5636f023d228fd/redirect +toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e55dccbfe27cb97945148c61a39c89c5/redirect +toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/dbd05c4936d573642f94cd149e1356c8/redirect toolchainVendor=JETBRAINS toolchainVersion=21 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e546184f..5a5a28f9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,13 @@ [versions] + +compose-multiplatform = "1.10.3" +androidx-activityCompose = "1.12.0" + agp = "9.1.0" coilCompose = "3.3.0" +concurrentFutures = "1.2.0" constraintlayoutCompose = "1.1.1" +converterGson = "2.9.0" datastore = "1.2.0" esclkt = "2.0.6" escl-mock-server = "1.0.1" @@ -12,33 +18,54 @@ junit = "4.13.2" junitVersion = "1.3.0" espressoCore = "3.7.0" kotlinReflect = "2.1.20" +kotlinxCoroutinesAndroid = "1.7.3" kotlinxSerializationJson = "1.9.0" +kotlinxCoroutines = "1.10.2" lifecycleRuntimeKtx = "2.9.4" activityCompose = "1.11.0" -composeBom = "2025.10.00" +composeBom = "2026.03.01" +retrofit = "3.0.0" room = "2.8.4" timber = "5.0.1" zoomable = "0.18.0" -material3 = "1.5.0-alpha06" +material3 = "1.11.0-alpha05" +androidx-material3 = "1.5.0-alpha16" materialIcons = "1.7.8" navigationCompose = "2.9.5" versionsPlugin = "0.53.0" screengrab = "2.1.1" ktor = "3.4.0" -koin = "4.2.0-RC1" -koin-plugin = "0.3.0" +koin = "4.2.0" +koin-plugin = "0.6.2" protobuf-plugin = "0.9.6" protobuf-kotlin-lite = "4.33.5" rules = "1.7.0" +paraphrase-plugin = "0.4.1" +ksp = "2.3.6" +protoc = "4.33.5" +androidx-sqlite = "2.6.2" [libraries] +androidx-concurrent-futures = { module = "androidx.concurrent:concurrent-futures", version.ref = "concurrentFutures" } +compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose-multiplatform" } +compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-multiplatform" } +compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "compose-multiplatform" } +compose-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "compose-multiplatform" } +compose-ui-tooling-preview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "compose-multiplatform" } +compose-ui-tooling = { module = "org.jetbrains.compose.ui:ui-tooling", version.ref = "compose-multiplatform" } +compose-ui-test = { module = "org.jetbrains.compose.ui:ui-test", version.ref = "compose-multiplatform" } +compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "material3" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } + androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" } androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } +androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "androidx-sqlite" } +retrofit-converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converterGson" } koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin" } koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin" } @@ -57,7 +84,10 @@ koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", ver koin-compose-viewmodel-navigation = { module = "io.insert-koin:koin-compose-viewmodel-navigation", version.ref = "koin" } koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" } -ktor-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor"} +kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesAndroid" } +ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor"} +ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } +ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" } ktor-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor"} androidx-constraintlayout-compose = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "constraintlayoutCompose" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -71,7 +101,6 @@ junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } -androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } androidx-ui = { group = "androidx.compose.ui", name = "ui" } androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } @@ -79,22 +108,35 @@ androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } -androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } +androidx-material3 = { module = "androidx.compose.material3:material3", version.ref= "androidx-material3" } kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlinReflect" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } +kotlinx-coroutines = { module = " org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines"} +retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } screengrab = { module = "tools.fastlane:screengrab", version.ref = "screengrab" } timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } zoomable = { module = "me.saket.telephoto:zoomable", version.ref = "zoomable" } protobuf-kotlin-lite = { module = "com.google.protobuf:protobuf-kotlin-lite", version.ref = "protobuf-kotlin-lite"} androidx-rules = { group = "androidx.test", name = "rules", version.ref = "rules" } +protoc = { module = "com.google.protobuf:protoc", version.ref = "protoc" } escl-mock-server = { module = "io.github.chrisimx:escl-mock-server", version.ref = "escl-mock-server"} [plugins] + +kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +compose-multiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } android-application = { id = "com.android.application", version.ref = "agp" } +android-kmp-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" } +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } + kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } versions = { id = "com.github.ben-manes.versions", version.ref = "versionsPlugin" } koin = { id = "io.insert-koin.compiler.plugin", version.ref = "koin-plugin" } protobuf = { id = "com.google.protobuf", version.ref = "protobuf-plugin" } -room = { id = "androidx.room", version.ref = "room"} \ No newline at end of file +room = { id = "androidx.room", version.ref = "room"} +paraphrase = { id = "app.cash.paraphrase", version.ref = "paraphrase-plugin"} +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file diff --git a/http-requests/eSCL.http b/http-requests/eSCL.http new file mode 100644 index 00000000..88181234 --- /dev/null +++ b/http-requests/eSCL.http @@ -0,0 +1,4 @@ +### Retrieve the eSCL scanner capabilities +GET http://{{server}}/eSCL/ScannerCapabilities + +### \ No newline at end of file diff --git a/http-requests/wsd.http b/http-requests/wsd.http new file mode 100644 index 00000000..6ad54eb3 --- /dev/null +++ b/http-requests/wsd.http @@ -0,0 +1,164 @@ +### Retrieve scanner caps +POST http://{{server}}/WebServices/ScannerService +Content-Type: application/soap+xml +User-Agent: WSDAPI + + + + + urn:uuid:9c8c2edb-3ffc-b823-28e8-b4339548f743 + http://192.168.178.122:80/WebServices/ScannerService + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + http://schemas.microsoft.com/windows/2006/08/wdp/scan/GetScannerElements + + + + + sca:ScannerConfiguration + sca:ScannerDescription + sca:DefaultScanTicket + sca:ScannerStatus + + + + + + +### Get scanner status +POST http://{{server}}/WebServices/ScannerService +Content-Type: application/soap+xml +User-Agent: WSDAPI + + + + + urn:uuid:8af74e6f-1f8b-4d40-c36f-f10eee60221e + http://192.168.178.122:80/WebServices/ScannerService + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + http://schemas.microsoft.com/windows/2006/08/wdp/scan/GetScannerElements + + + + + sca:ScannerStatus + + + + + + +### Create scanjob +POST http://{{server}}/WebServices/ScannerService +Content-Type: application/soap+xml +User-Agent: WSDAPI + + + + + urn:uuid:e6d472bf-e3bd-a7a4-6066-cdea1f91e5fa + http://192.168.178.122:80/WebServices/ScannerService + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + http://schemas.microsoft.com/windows/2006/08/wdp/scan/CreateScanJob + + + + + + sane-airscan request + sane-airscan + sane-airscan + + + exif + 1 + + + 8500 + 11700 + + + Platen + + + RGB24 + + 300 + 300 + + + 0 + 0 + 8500 + 11700 + + + + + + + + + +### Retrieve scanned image +POST http://{{server}}/WebServices/ScannerService +Content-Type: application/soap+xml +User-Agent: WSDAPI + + + + + urn:uuid:dc1ff0f8-e4e2-b1ef-758f-b1e6186a5cc6 + http://192.168.178.122:80/WebServices/ScannerService + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + http://schemas.microsoft.com/windows/2006/08/wdp/scan/RetrieveImage + + + + + IMAGE000.JPG + + 2 + urn:uuid:81b7a2a1-f1ff-4504-84a2-3c2af46faf5d + + + + + +### Retrieve device info +POST http://{{server}}/WebServices/Device +Content-Type: application/soap+xml +User-Agent: WSDAPI + + + + + http://schemas.xmlsoap.org/ws/2004/09/transfer/Get + urn:uuid:414bbe9a-7059-e7c3-a856-a38029a53c1c + urn:uuid:e3248000-80ce-11db-8000-3c2af46faf5d + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + + + \ No newline at end of file diff --git a/libraries/play-licensing/lvl_library/build.gradle b/libraries/play-licensing/lvl_library/build.gradle index afaf0fa8..5f9aba84 100644 --- a/libraries/play-licensing/lvl_library/build.gradle +++ b/libraries/play-licensing/lvl_library/build.gradle @@ -5,6 +5,7 @@ android { compileSdk 34 defaultConfig { minSdk 4 + targetSdk 34 } buildTypes { release { @@ -15,10 +16,4 @@ android { buildFeatures { aidl true } - lint { - targetSdk 34 - } - testOptions { - targetSdk 34 - } } diff --git a/settings-gradle.lockfile b/settings-gradle.lockfile new file mode 100644 index 00000000..709a43f7 --- /dev/null +++ b/settings-gradle.lockfile @@ -0,0 +1,4 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +empty=incomingCatalogForLibs0 diff --git a/settings.gradle.kts b/settings.gradle.kts index ed52ce90..81296942 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,5 @@ +rootProject.name = "ScanBridge" + pluginManagement { repositories { google { @@ -30,7 +32,9 @@ dependencyResolutionManagement { } } -rootProject.name = "ScanBridge" -include(":app") +include(":composeUI") +include(":core") +include(":androidApp") +include(":desktopApp") include(":lvl_library") project(":lvl_library").projectDir = File(rootDir, "libraries/play-licensing/lvl_library/")