From 2eaede07135458e811d38b61234f1fb9cff6ad76 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Nicolas <6371790+pynicolas@users.noreply.github.com>
Date: Sat, 17 Jan 2026 14:43:16 +0100
Subject: [PATCH] AboutScreen: new button to send the last captured image (#88)
---
.../main/java/org/fairscan/app/FairScanApp.kt | 1 -
.../java/org/fairscan/app/MainActivity.kt | 28 +++++++++--
.../org/fairscan/app/data/ImageRepository.kt | 8 ++++
.../main/java/org/fairscan/app/ui/FileUris.kt | 25 ++++++++++
.../app/ui/screens/about/AboutScreen.kt | 45 ++++++++++++++----
.../app/ui/screens/about/AboutUiState.kt | 22 +++++++++
.../app/ui/screens/about/AboutViewModel.kt | 21 ++++++++-
.../fairscan/app/ui/screens/about/Emails.kt | 46 +++++++++++++++++++
app/src/main/res/values-cs/strings.xml | 2 +
app/src/main/res/values-de/strings.xml | 2 +
app/src/main/res/values-es/strings.xml | 2 +
app/src/main/res/values-fr/strings.xml | 2 +
app/src/main/res/values-it/strings.xml | 2 +
app/src/main/res/values-pt-rBR/strings.xml | 2 +
app/src/main/res/values-ru/strings.xml | 2 +
app/src/main/res/values-zh-rTW/strings.xml | 2 +
app/src/main/res/values-zh/strings.xml | 2 +
app/src/main/res/values/strings.xml | 2 +
app/src/main/res/xml/file_paths.xml | 4 ++
.../fairscan/app/data/ImageRepositoryTest.kt | 23 ++++++++++
20 files changed, 228 insertions(+), 15 deletions(-)
create mode 100644 app/src/main/java/org/fairscan/app/ui/FileUris.kt
create mode 100644 app/src/main/java/org/fairscan/app/ui/screens/about/AboutUiState.kt
create mode 100644 app/src/main/java/org/fairscan/app/ui/screens/about/Emails.kt
diff --git a/app/src/main/java/org/fairscan/app/FairScanApp.kt b/app/src/main/java/org/fairscan/app/FairScanApp.kt
index 7348b7f..b3cb446 100644
--- a/app/src/main/java/org/fairscan/app/FairScanApp.kt
+++ b/app/src/main/java/org/fairscan/app/FairScanApp.kt
@@ -70,7 +70,6 @@ class AppContainer(context: Context) {
val homeViewModelFactory = viewModelFactory { HomeViewModel(it, context) }
val cameraViewModelFactory = viewModelFactory { CameraViewModel(it) }
- val aboutViewModelFactory = viewModelFactory { AboutViewModel(it) }
val settingsViewModelFactory = viewModelFactory { SettingsViewModel(it) }
fun cleanOrphanSessions() {
diff --git a/app/src/main/java/org/fairscan/app/MainActivity.kt b/app/src/main/java/org/fairscan/app/MainActivity.kt
index 51e83da..54f13ce 100644
--- a/app/src/main/java/org/fairscan/app/MainActivity.kt
+++ b/app/src/main/java/org/fairscan/app/MainActivity.kt
@@ -50,6 +50,7 @@ import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.fairscan.app.data.FileLogger
+import org.fairscan.app.data.ImageRepository
import org.fairscan.app.ui.Navigation
import org.fairscan.app.ui.Screen
import org.fairscan.app.ui.components.rememberCameraPermissionState
@@ -58,6 +59,7 @@ import org.fairscan.app.ui.screens.LibrariesScreen
import org.fairscan.app.ui.screens.about.AboutEvent
import org.fairscan.app.ui.screens.about.AboutScreen
import org.fairscan.app.ui.screens.about.AboutViewModel
+import org.fairscan.app.ui.screens.about.createEmailWithImageIntent
import org.fairscan.app.ui.screens.camera.CameraEvent
import org.fairscan.app.ui.screens.camera.CameraScreen
import org.fairscan.app.ui.screens.camera.CameraViewModel
@@ -101,9 +103,14 @@ class MainActivity : ComponentActivity() {
ExportViewModel(appContainer, sessionContainer.imageRepository)
}
}
+ val aboutViewModel: AboutViewModel by viewModels {
+ appContainer.viewModelFactory {
+ AboutViewModel(appContainer, sessionContainer.imageRepository)
+ }
+ }
val homeViewModel: HomeViewModel by viewModels { appContainer.homeViewModelFactory }
val cameraViewModel: CameraViewModel by viewModels { appContainer.cameraViewModelFactory }
- val aboutViewModel: AboutViewModel by viewModels { appContainer.aboutViewModelFactory }
+
val settingsViewModel: SettingsViewModel
by viewModels { appContainer.settingsViewModelFactory }
lifecycleScope.launch(Dispatchers.IO) {
@@ -119,7 +126,7 @@ class MainActivity : ComponentActivity() {
val cameraPermission = rememberCameraPermissionState()
CollectCameraEvents(cameraViewModel, viewModel)
CollectExportEvents(context, exportViewModel)
- CollectAboutEvents(context, aboutViewModel)
+ CollectAboutEvents(context, aboutViewModel, sessionContainer.imageRepository)
FairScanTheme {
val navigation = navigation(viewModel, launchMode)
@@ -187,9 +194,16 @@ class MainActivity : ComponentActivity() {
)
}
is Screen.Overlay.About -> {
+ LaunchedEffect(Unit) {
+ aboutViewModel.refreshLastCapturedImageState()
+ }
+ val aboutUiState by aboutViewModel.uiState.collectAsStateWithLifecycle()
AboutScreen(
+ aboutUiState = aboutUiState,
onBack = navigation.back,
onCopyLogs = { aboutViewModel.onCopyLogsClicked() },
+ onContactWithLastImageClicked =
+ { aboutViewModel.onContactWithLastImageClicked() },
onViewLibraries = navigation.toLibrariesScreen)
}
is Screen.Overlay.Libraries -> {
@@ -262,6 +276,7 @@ class MainActivity : ComponentActivity() {
private fun CollectAboutEvents(
context: Context,
aboutViewModel: AboutViewModel,
+ imageRepository: ImageRepository,
) {
val clipboard = LocalClipboard.current
val msgCopiedLogs = stringResource(R.string.copied_logs)
@@ -274,6 +289,12 @@ class MainActivity : ComponentActivity() {
)
Toast.makeText(context, msgCopiedLogs, Toast.LENGTH_SHORT).show()
}
+ is AboutEvent.PrepareEmailWithLastImage -> {
+ val file = imageRepository.lastAddedSourceFile()
+ if (file != null) {
+ startActivity(createEmailWithImageIntent(context, file))
+ }
+ }
}
}
}
@@ -370,8 +391,7 @@ class MainActivity : ComponentActivity() {
}
private fun uriForFile(file: File): Uri {
- val authority = "${applicationContext.packageName}.fileprovider"
- return FileProvider.getUriForFile(this, authority, file)
+ return org.fairscan.app.ui.uriForFile(this, file)
}
private fun checkPermissionThen(
diff --git a/app/src/main/java/org/fairscan/app/data/ImageRepository.kt b/app/src/main/java/org/fairscan/app/data/ImageRepository.kt
index d982246..f82c777 100644
--- a/app/src/main/java/org/fairscan/app/data/ImageRepository.kt
+++ b/app/src/main/java/org/fairscan/app/data/ImageRepository.kt
@@ -298,6 +298,14 @@ class ImageRepository(
}
}
}
+
+ fun lastAddedSourceFile(): File? {
+ val sourceFiles = sourceDir.listFiles()?.filter { it.extension == "jpg" }
+ if (sourceFiles.isNullOrEmpty()) {
+ return null
+ }
+ return sourceFiles.maxByOrNull { it.lastModified() }
+ }
}
fun Quad.toSerializable(): NormalizedQuad =
diff --git a/app/src/main/java/org/fairscan/app/ui/FileUris.kt b/app/src/main/java/org/fairscan/app/ui/FileUris.kt
new file mode 100644
index 0000000..531bb08
--- /dev/null
+++ b/app/src/main/java/org/fairscan/app/ui/FileUris.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2025 Pierre-Yves Nicolas
+ *
+ * This program 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.
+ * This program 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
+ * this program. If not, see .
+ */
+package org.fairscan.app.ui
+
+import android.content.Context
+import android.net.Uri
+import androidx.core.content.FileProvider
+import java.io.File
+
+fun uriForFile(context: Context, file: File): Uri {
+ val authority = "${context.packageName}.fileprovider"
+ return FileProvider.getUriForFile(context, authority, file)
+}
diff --git a/app/src/main/java/org/fairscan/app/ui/screens/about/AboutScreen.kt b/app/src/main/java/org/fairscan/app/ui/screens/about/AboutScreen.kt
index a354e8e..f4bd213 100644
--- a/app/src/main/java/org/fairscan/app/ui/screens/about/AboutScreen.kt
+++ b/app/src/main/java/org/fairscan/app/ui/screens/about/AboutScreen.kt
@@ -57,6 +57,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
@@ -76,8 +77,10 @@ import org.fairscan.app.ui.theme.FairScanTheme
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AboutScreen(
+ aboutUiState: AboutUiState,
onBack: () -> Unit,
onCopyLogs: () -> Unit,
+ onContactWithLastImageClicked: () -> Unit,
onViewLibraries: () -> Unit,
) {
val showLicenseDialog = rememberSaveable { mutableStateOf(false) }
@@ -93,7 +96,9 @@ fun AboutScreen(
) { paddingValues ->
AboutContent(
modifier = Modifier.padding(paddingValues),
+ aboutUiState,
onCopyLogs,
+ onContactWithLastImageClicked,
showLicenseDialog,
onViewLibraries)
}
@@ -105,7 +110,9 @@ fun AboutScreen(
@Composable
fun AboutContent(
modifier: Modifier = Modifier,
+ aboutUiState: AboutUiState,
onCopyLogs: () -> Unit,
+ onContactWithLastImageClicked: () -> Unit,
showLicenseDialog: MutableState,
onViewLibraries: () -> Unit,
) {
@@ -145,16 +152,10 @@ fun AboutContent(
}
Section(title = stringResource(R.string.contact)) {
- val emailAddress = "contact@fairscan.org"
ContactLink(
icon = Icons.Default.Email,
- text = emailAddress,
- onClick = {
- val intent = Intent(Intent.ACTION_SENDTO).apply {
- data = "mailto:$emailAddress".toUri()
- }
- context.startActivity(intent)
- }
+ text = EMAIL_ADDRESS,
+ onClick = { context.startActivity(createContactEmailIntent()) }
)
val websiteUrl = "https://fairscan.org"
ContactLink(
@@ -165,6 +166,10 @@ fun AboutContent(
context.startActivity(intent)
}
)
+ }
+
+ Section(title = stringResource(R.string.support)) {
+ EmailImageButton(aboutUiState, onContactWithLastImageClicked)
CopyLogsButton (onClick = onCopyLogs)
}
@@ -295,11 +300,33 @@ fun CopyLogsButton(onClick: () -> Unit) {
}
}
+@Composable
+fun EmailImageButton(
+ aboutUiState: AboutUiState,
+ onContactWithLastImageClicked: () -> Unit,
+) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable(
+ enabled = aboutUiState.hasLastCapturedImage,
+ onClick = onContactWithLastImageClicked
+ )
+ .alpha(if (aboutUiState.hasLastCapturedImage) 1f else 0.5f)
+ .padding(vertical = 8.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(Icons.Default.Email, contentDescription = null)
+ Spacer(Modifier.width(16.dp))
+ Text(stringResource(R.string.support_last_image))
+ }
+}
@Preview
@Composable
fun AboutScreenPreview() {
FairScanTheme {
- AboutScreen(onBack = {}, onCopyLogs = {}, onViewLibraries = {})
+ val state = AboutUiState(true)
+ AboutScreen(state, {}, {}, {}, {})
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/fairscan/app/ui/screens/about/AboutUiState.kt b/app/src/main/java/org/fairscan/app/ui/screens/about/AboutUiState.kt
new file mode 100644
index 0000000..b82d379
--- /dev/null
+++ b/app/src/main/java/org/fairscan/app/ui/screens/about/AboutUiState.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2025 Pierre-Yves Nicolas
+ *
+ * This program 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.
+ * This program 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
+ * this program. If not, see .
+ */
+package org.fairscan.app.ui.screens.about
+
+import androidx.compose.runtime.Immutable
+
+@Immutable
+data class AboutUiState(
+ val hasLastCapturedImage: Boolean = false,
+)
diff --git a/app/src/main/java/org/fairscan/app/ui/screens/about/AboutViewModel.kt b/app/src/main/java/org/fairscan/app/ui/screens/about/AboutViewModel.kt
index 7135cc6..d3a9d22 100644
--- a/app/src/main/java/org/fairscan/app/ui/screens/about/AboutViewModel.kt
+++ b/app/src/main/java/org/fairscan/app/ui/screens/about/AboutViewModel.kt
@@ -18,23 +18,31 @@ import android.os.Build
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.fairscan.app.AppContainer
import org.fairscan.app.BuildConfig
+import org.fairscan.app.data.ImageRepository
import java.time.LocalDateTime
sealed interface AboutEvent {
data class CopyLogs(val logs: String) : AboutEvent
+ object PrepareEmailWithLastImage : AboutEvent
}
-class AboutViewModel(container: AppContainer): ViewModel() {
+class AboutViewModel(container: AppContainer, val imageRepository: ImageRepository): ViewModel() {
private val logRepository = container.logRepository
private val _events = MutableSharedFlow()
val events = _events.asSharedFlow()
+ private val _uiState = MutableStateFlow(AboutUiState())
+ val uiState = _uiState.asStateFlow()
+
fun onCopyLogsClicked() {
viewModelScope.launch {
val logs = buildFullLogs()
@@ -55,4 +63,15 @@ class AboutViewModel(container: AppContainer): ViewModel() {
return header + logRepository.getLogs()
}
+ fun refreshLastCapturedImageState() {
+ _uiState.update {
+ it.copy(hasLastCapturedImage = imageRepository.lastAddedSourceFile() != null)
+ }
+ }
+
+ fun onContactWithLastImageClicked() {
+ viewModelScope.launch {
+ _events.emit(AboutEvent.PrepareEmailWithLastImage)
+ }
+ }
}
diff --git a/app/src/main/java/org/fairscan/app/ui/screens/about/Emails.kt b/app/src/main/java/org/fairscan/app/ui/screens/about/Emails.kt
new file mode 100644
index 0000000..29d7aba
--- /dev/null
+++ b/app/src/main/java/org/fairscan/app/ui/screens/about/Emails.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2025 Pierre-Yves Nicolas
+ *
+ * This program 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.
+ * This program 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
+ * this program. If not, see .
+ */
+package org.fairscan.app.ui.screens.about
+
+import android.content.Context
+import android.content.Intent
+import androidx.core.net.toUri
+import org.fairscan.app.BuildConfig
+import org.fairscan.app.ui.uriForFile
+import java.io.File
+
+const val EMAIL_ADDRESS = "contact@fairscan.org"
+
+fun createContactEmailIntent(): Intent =
+ Intent(Intent.ACTION_SENDTO).apply {
+ data = "mailto:$EMAIL_ADDRESS".toUri()
+ }
+
+fun createEmailWithImageIntent(context: Context, imageFile: File?): Intent {
+ val intent = Intent(Intent.ACTION_SEND).apply {
+ type = "image/jpeg"
+ putExtra(Intent.EXTRA_EMAIL, arrayOf(EMAIL_ADDRESS))
+ putExtra(
+ Intent.EXTRA_SUBJECT,
+ "FairScan ${BuildConfig.VERSION_NAME}"
+ )
+ if (imageFile != null) {
+ val uri = uriForFile(context, imageFile)
+ putExtra(Intent.EXTRA_STREAM, uri)
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ }
+ }
+ return Intent.createChooser(intent, null)
+}
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 10de839..939cbfc 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -52,6 +52,8 @@
Sdílet
Sdílet dokument
Nelze uložit soubor: oprávnění bylo odmítnuto
+ Podpora
+ Nahlásit problém s posledním zachyceným obrázkem
Vypnout svítilnu
Zapnout svítilnu
Neznámá velikost
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index ba5eb16..82fad44 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -52,6 +52,8 @@
Teilen
Dokument teilen
Datei kann nicht gespeichert werden: Berechtigung verweigert
+ Support
+ Problem mit dem zuletzt aufgenommenen Bild melden
Taschenlampe ausschalten
Taschenlampe einschalten
Unbekannte Größe
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 6684f84..30a90ca 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -52,6 +52,8 @@
Compartir
Compartir documento
No se puede guardar el archivo: permiso denegado
+ Soporte
+ Informar de un problema con la última imagen capturada
Apagar linterna
Encender linterna
Tamaño desconocido
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 2b4dbe4..8b21965 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -52,6 +52,8 @@
Partager
Partager le document
Impossible d’enregistrer le fichier : permission refusée
+ Support
+ Signaler un problème avec la dernière image capturée
Éteindre la torche
Allumer la torche
Taille inconnue
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index b4406af..ac9b1fe 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -52,6 +52,8 @@
Condividi
Condividi documento
Impossibile salvare il file: permesso negato
+ Supporto
+ Segnala un problema con l’ultima immagine acquisita
Spegni la torcia
Accendi la torcia
Dimensione sconosciuta
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 3e4b013..882ac37 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -52,6 +52,8 @@
Compartilhar
Compartilhar documento
Não foi possível salvar o arquivo: permissão negada
+ Suporte
+ Relatar um problema com a última imagem capturada
Desligar lanterna
Ligar lanterna
Tamanho desconhecido
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 7bbc9a8..59a0ffb 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -52,6 +52,8 @@
Поделиться
Поделиться документом
Невозможно сохранить файл: доступ запрещён
+ Поддержка
+ Сообщить о проблеме с последним сделанным изображением
Выключить фонарик
Включить фонарик
Неизвестный размер
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index a095506..393243f 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -52,6 +52,8 @@
分享
分享文件
無法儲存檔案:權限遭拒
+ 支援
+ 回報最近拍攝影像的問題
關閉閃光燈
開啟閃光燈
未知大小
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index da54a55..7bc1244 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -52,6 +52,8 @@
共享
分享文档
无法保存文件:权限被拒绝
+ 支持
+ 报告最近拍摄图像的问题
关闭手电筒
打开手电筒
未知大小
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 380d383..126cff6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -56,6 +56,8 @@
Share
Share document
Cannot save file: permission was denied
+ Support
+ Report a problem with last captured image
Turn off torch
Turn on torch
Unknown size
diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml
index a4dae74..763b0d4 100644
--- a/app/src/main/res/xml/file_paths.xml
+++ b/app/src/main/res/xml/file_paths.xml
@@ -6,4 +6,8 @@
+
+
diff --git a/app/src/test/java/org/fairscan/app/data/ImageRepositoryTest.kt b/app/src/test/java/org/fairscan/app/data/ImageRepositoryTest.kt
index 4deab91..9524d18 100644
--- a/app/src/test/java/org/fairscan/app/data/ImageRepositoryTest.kt
+++ b/app/src/test/java/org/fairscan/app/data/ImageRepositoryTest.kt
@@ -242,6 +242,29 @@ class ImageRepositoryTest {
assertThat(PageV2("1", 42, 0, quad, true).toMetadata()).isNull()
}
+ @Test
+ fun last_added_source_file() {
+ val repo = repo()
+ assertThat(repo.lastAddedSourceFile()).isNull()
+ repo.add(byteArrayOf(101), byteArrayOf(51), metadata1)
+ assertThat(repo.lastAddedSourceFile()).hasBinaryContent(byteArrayOf(51))
+ Thread.sleep(1)
+ repo.add(byteArrayOf(102), byteArrayOf(52), metadata1)
+ assertThat(repo.lastAddedSourceFile()).hasBinaryContent(byteArrayOf(52))
+
+ val id = repo.imageIds().last()
+ repo.movePage(id, 0)
+ assertThat(repo.lastAddedSourceFile()).hasBinaryContent(byteArrayOf(52))
+ repo.delete(id)
+ assertThat(repo.lastAddedSourceFile()).hasBinaryContent(byteArrayOf(51))
+
+ val repo2 = repo()
+ assertThat(repo2.lastAddedSourceFile()).hasBinaryContent(byteArrayOf(51))
+
+ repo2.clear()
+ assertThat(repo2.lastAddedSourceFile()).isNull()
+ }
+
private fun scanDir(): File = File(getFilesDir(), SCAN_DIR_NAME)
private fun sourceDir(): File = File(getFilesDir(), SOURCE_DIR_NAME)