Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f936298
Create datastore using create function instead of Kotlin get
Chrisimx Apr 6, 2026
f7f942a
Add ScanBridge (android) to a multiplatform skeleton
Chrisimx Apr 3, 2026
07877c3
Make changes for multi-platform compatability
Chrisimx Apr 3, 2026
57aef80
Remove old theme files from skeleton
Chrisimx Apr 3, 2026
aae6b3a
Move theme to composeUI module
Chrisimx Apr 3, 2026
745faf0
Fix import in Typography.kt
Chrisimx Apr 6, 2026
09ca8ff
Migrate last route store to Room and abstract to repository, shown me…
Chrisimx Apr 4, 2026
f05d4a8
Move all deps from androidApp build.gradle.kts to version catalog
Chrisimx Apr 4, 2026
653a536
Put some Koin factories in create functions
Chrisimx Apr 9, 2026
25b0716
Upgarde Koin and enable compile time safety
Chrisimx Apr 9, 2026
2bc1644
Add build folder of desktopApp to gitignore
Chrisimx Apr 6, 2026
32327d9
Move LocaleProvider interface to core
Chrisimx Apr 9, 2026
6990eae
Remove unnecessary import in ScanBridgeApplication.kt
Chrisimx Apr 9, 2026
e2b68dc
Move PaperFormat model to core
Chrisimx Apr 9, 2026
f046e26
Prepare Room db for KMP migration
Chrisimx Apr 9, 2026
b9eed58
Use KMP-compatible transaction methods
Chrisimx Apr 9, 2026
3d774fc
Fully migrate to KMP Room
Chrisimx Apr 9, 2026
42df48e
Move ScanJob and DiscoveredScanner to core because they are platform …
Chrisimx Apr 9, 2026
2b594f0
Refactor ScanJob to be pure domain model
Chrisimx Apr 9, 2026
c68dcf4
Move LoggerFactory, ZipService, HttpClientFactory and other things to…
Chrisimx Apr 11, 2026
c7d276c
Rename ScanSettingsStateData to ScanSettingsEnterableData
Chrisimx Apr 11, 2026
6f8a06d
Remove basic README.MD
Chrisimx May 13, 2026
7be8c80
Add HTTP requests for testing escl and WSD
Chrisimx May 13, 2026
cc2b25b
Remove unused iosApp
Chrisimx May 13, 2026
2c0f8e4
Try to fix CI
Chrisimx May 13, 2026
9607e08
Fix format
Chrisimx May 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ 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
if: ${{ github.event_name != 'pull_request' }}
# 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 }}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/create-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ app/src/androidTest/native-libs
/app/debug
/app/release
/app/play
/fastlane/report.xml
/fastlane/report.xml
/http-requests/http-client.private.env.json
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

<p align="center" style="text-align: center;">
<a href='https://f-droid.org/packages/io.github.chrisimx.scanbridge/' target="_blank">
<img src="assets/get-it-on-fdroid.svg"
<img src="androidApp/assets/get-it-on-fdroid.svg"
align="center"
alt="Get it on F-Droid"
style="height: 50px"
height="50">
</a>

<a href='https://play.google.com/store/apps/details?id=io.github.chrisimx.scanbridge.play' target="_blank">
<img src='assets/GetItOnGooglePlay_Badge_Web_color_English.svg'
<img src='androidApp/assets/GetItOnGooglePlay_Badge_Web_color_English.svg'
align="center"
alt='Get it on Google Play'
style="height: 50px"
Expand All @@ -31,9 +31,9 @@ scanners.
It is written in Kotlin and uses Jetpack Compose.

<div style="display: flex; flex-wrap: wrap; gap: 10px;">
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/01-scannedPageScreen_1773391873581.png" alt="Discover scanners in your network" style="width: 30%; height: auto;" />
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/02-scanSettings_1773391870896.png" alt="Scan multiple pages" style="width: 30%; height: auto;" />
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/03-discoveryScreen_1773391871298.png" alt="Use your scanner to the maximum of its abilities" style="width: 30%; height: auto;" />
<img src="androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/01-scannedPageScreen_1773391873581.png" alt="Discover scanners in your network" style="width: 30%; height: auto;" />
<img src="androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/02-scanSettings_1773391870896.png" alt="Scan multiple pages" style="width: 30%; height: auto;" />
<img src="androidApp/fastlane/metadata/android/en-US/images/phoneScreenshots/03-discoveryScreen_1773391871298.png" alt="Use your scanner to the maximum of its abilities" style="width: 30%; height: auto;" />
</div>

## Features
Expand Down Expand Up @@ -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

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
69 changes: 31 additions & 38 deletions app/build.gradle.kts → androidApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().all {
compilerOptions {
Expand All @@ -53,10 +37,6 @@ android {
generateLocaleConfig = true
}

room {
schemaDirectory("$projectDir/schemas")
}

defaultConfig {
applicationId = "io.github.chrisimx.scanbridge"
minSdk = 28
Expand All @@ -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"
Expand All @@ -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
Expand All @@ -107,29 +87,36 @@ 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)
implementation(libs.koin.compose)
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)
Expand All @@ -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)

Expand All @@ -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 ->
Expand All @@ -182,6 +171,10 @@ protobuf {
}
}

koinCompiler {
compileSafety = true
}

afterEvaluate {
tasks.named("clean") {
doLast {
Expand Down
File renamed without changes.
8 changes: 4 additions & 4 deletions fastlane/Fastfile → androidApp/fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions androidApp/gradle/gradle-daemon-jvm.properties
Original file line number Diff line number Diff line change
@@ -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
100 changes: 100 additions & 0 deletions androidApp/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -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"}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
Loading
Loading