diff --git a/mobile-kotlin/app/build.gradle.kts b/mobile-kotlin/app/build.gradle.kts
index c9f0a78..ca88392 100644
--- a/mobile-kotlin/app/build.gradle.kts
+++ b/mobile-kotlin/app/build.gradle.kts
@@ -15,9 +15,18 @@ android {
defaultConfig {
applicationId = "com.vaultdrop.mobile"
minSdk = 26
- targetSdk = 35
+ // targetSdk 35 exige des .so alignés en 16K ; les libs précompilées
+ // OpenCV/CameraX sont en 4K (warning de compatibilité sur devices
+ // 16K-pages). On reste en 34 tant qu'elles ne sont pas mises à jour.
+ targetSdk = 34
versionCode = 1
versionName = "0.1.0"
+
+ // OpenCV natif : on conserve uniquement les ABIs ciblés
+ // (arm64 = devices, x86_64 = émulateur) pour garder l'APK raisonnable.
+ ndk {
+ abiFilters += listOf("arm64-v8a", "x86_64")
+ }
}
buildTypes {
@@ -73,6 +82,11 @@ dependencies {
ksp(libs.androidx.hilt.compiler)
implementation(libs.androidx.work.runtime.ktx)
+ implementation(libs.androidx.camera.camera2)
+ implementation(libs.androidx.camera.lifecycle)
+ implementation(libs.androidx.camera.view)
+ implementation(libs.opencv)
+
implementation(libs.retrofit)
implementation(libs.retrofit.converter.moshi)
implementation(libs.okhttp)
diff --git a/mobile-kotlin/app/src/main/AndroidManifest.xml b/mobile-kotlin/app/src/main/AndroidManifest.xml
index 0a189f1..366dbec 100644
--- a/mobile-kotlin/app/src/main/AndroidManifest.xml
+++ b/mobile-kotlin/app/src/main/AndroidManifest.xml
@@ -3,6 +3,11 @@
xmlns:tools="http://schemas.android.com/tools">
+
+
+
= arrayOf(
- MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, MIGRATION_6_7,
+ MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6, MIGRATION_6_7, MIGRATION_7_8,
)
}
\ No newline at end of file
diff --git a/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/di/DatabaseModule.kt b/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/di/DatabaseModule.kt
index af2921e..59070e4 100644
--- a/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/di/DatabaseModule.kt
+++ b/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/di/DatabaseModule.kt
@@ -6,6 +6,7 @@ import com.vaultdrop.mobile.data.local.AppDatabase
import com.vaultdrop.mobile.data.local.dao.FileDao
import com.vaultdrop.mobile.data.local.dao.FolderDao
import com.vaultdrop.mobile.data.local.dao.PendingOperationDao
+import com.vaultdrop.mobile.data.local.dao.ScanDao
import com.vaultdrop.mobile.data.local.dao.UserPreferenceDao
import com.vaultdrop.mobile.data.local.migration.Migrations
import dagger.Module
@@ -37,4 +38,7 @@ object DatabaseModule {
@Provides
fun providePendingOperationDao(db: AppDatabase): PendingOperationDao = db.pendingOperationDao()
+
+ @Provides
+ fun provideScanDao(db: AppDatabase): ScanDao = db.scanDao()
}
\ No newline at end of file
diff --git a/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/dashboard/DashboardScreen.kt b/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/dashboard/DashboardScreen.kt
index 816527e..8cd39d9 100644
--- a/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/dashboard/DashboardScreen.kt
+++ b/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/dashboard/DashboardScreen.kt
@@ -11,11 +11,14 @@ import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.CheckCircle
+import androidx.compose.material.icons.filled.DocumentScanner
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
+import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
@@ -43,6 +46,7 @@ fun DashboardScreen(
connectionStatusViewModel: ConnectionStatusViewModel,
syncViewModel: SyncViewModel,
onOpenReview: () -> Unit,
+ onOpenScan: () -> Unit,
viewModel: DashboardViewModel = hiltViewModel(),
) {
val connectionStatus by connectionStatusViewModel.status.collectAsStateWithLifecycle()
@@ -64,6 +68,18 @@ fun DashboardScreen(
bottomBar = {
FloatingNavBar(selected = selectedTab, onSelect = onTabSelected)
},
+ floatingActionButton = {
+ SmallFloatingActionButton(
+ onClick = onOpenScan,
+ containerColor = MaterialTheme.colorScheme.primary,
+ contentColor = MaterialTheme.colorScheme.onPrimary,
+ ) {
+ Icon(
+ imageVector = Icons.Filled.DocumentScanner,
+ contentDescription = stringResource(R.string.scan_title),
+ )
+ }
+ },
) { padding ->
Column(
modifier = Modifier
diff --git a/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/navigation/NavGraph.kt b/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/navigation/NavGraph.kt
index 47bbd95..6899992 100644
--- a/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/navigation/NavGraph.kt
+++ b/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/navigation/NavGraph.kt
@@ -25,6 +25,7 @@ import com.vaultdrop.mobile.ui.folderdetail.FolderDetailScreen
import com.vaultdrop.mobile.ui.folderlist.FolderListScreen
import com.vaultdrop.mobile.ui.pdfbuilder.PdfBuilderScreen
import com.vaultdrop.mobile.ui.review.SwipeReviewScreen
+import com.vaultdrop.mobile.ui.scan.ScanFlowScreen
import com.vaultdrop.mobile.ui.search.SearchScreen
import com.vaultdrop.mobile.ui.settings.SettingsScreen
import com.vaultdrop.mobile.ui.watchedfolders.WatchedFoldersScreen
@@ -42,6 +43,7 @@ object Routes {
const val ARG_DOCUMENT = "documentResourceId"
const val PDF_BUILDER = "pdfbuilder/{ids}"
const val ARG_BUILDER_IDS = "ids"
+ const val SCAN = "scan"
fun folder(folderResourceId: String): String = "folder/$folderResourceId"
fun document(documentResourceId: String): String = "document/$documentResourceId"
@@ -126,6 +128,12 @@ fun NavGraph(
connectionStatusViewModel = connectionStatusViewModel,
syncViewModel = syncViewModel,
onOpenReview = { navController.navigate(Routes.REVIEW) },
+ onOpenScan = { navController.navigate(Routes.SCAN) },
+ )
+ }
+ composable(Routes.SCAN) {
+ ScanFlowScreen(
+ onBack = { navController.popBackStack() },
)
}
composable(Routes.REVIEW) {
diff --git a/mobile-kotlin/app/src/main/res/values/strings.xml b/mobile-kotlin/app/src/main/res/values/strings.xml
index b3cb9b9..96ac86b 100644
--- a/mobile-kotlin/app/src/main/res/values/strings.xml
+++ b/mobile-kotlin/app/src/main/res/values/strings.xml
@@ -179,4 +179,37 @@
Aperçu
Fermer l\'aperçu
PDF générés
+
+
+ Scanner
+ Capturer
+ %1$d page(s)
+ Voir les pages
+ Cadre le document puis capture.
+ Autorise la caméra pour scanner des documents.
+ Autoriser la caméra
+ Recadrer
+ Valider la page
+ Reprendre
+ Couleur
+ N&B
+ N&B contrasté
+ Ajouter une page
+ Pages scannées
+ Supprimer
+ Monter
+ Descendre
+ Aucune page pour le moment.\nCapture ta première page.
+ Exporter vers le dossier VaultDrop
+ Export en cours…
+ Abandonner
+ Abandonner le scan ?
+ Les pages capturées seront supprimées.
+ Confirmer
+ Annuler
+ Session de scan indisponible.
+ Impossible d\'utiliser cette capture.
+ Impossible d\'enregistrer la page.
+ Impossible d\'exporter les pages.
+ Pages exportées
\ No newline at end of file
diff --git a/mobile-kotlin/gradle/libs.versions.toml b/mobile-kotlin/gradle/libs.versions.toml
index 12a6e9e..f49ed0d 100644
--- a/mobile-kotlin/gradle/libs.versions.toml
+++ b/mobile-kotlin/gradle/libs.versions.toml
@@ -17,6 +17,8 @@ moshi = "1.15.1"
securityCrypto = "1.0.0"
timber = "5.0.1"
coil = "2.7.0"
+cameraX = "1.3.4"
+opencv = "4.14.0"
junit = "4.13.2"
robolectric = "4.14.1"
androidxTestCore = "1.6.1"
@@ -29,6 +31,10 @@ androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecyc
androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" }
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
+androidx-camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "cameraX" }
+androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "cameraX" }
+androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "cameraX" }
+opencv = { group = "org.opencv", name = "opencv", version.ref = "opencv" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }