Extract strings
This commit is contained in:
@@ -20,7 +20,6 @@ import android.content.pm.PackageManager
|
|||||||
import android.media.MediaScannerConnection
|
import android.media.MediaScannerConnection
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
@@ -30,7 +29,6 @@ import androidx.activity.viewModels
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.net.toFile
|
import androidx.core.net.toFile
|
||||||
import androidx.core.net.toUri
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -44,7 +42,6 @@ import org.mydomain.myscan.view.CameraScreen
|
|||||||
import org.mydomain.myscan.view.DocumentScreen
|
import org.mydomain.myscan.view.DocumentScreen
|
||||||
import org.mydomain.myscan.view.LibrariesScreen
|
import org.mydomain.myscan.view.LibrariesScreen
|
||||||
import org.opencv.android.OpenCVLoader
|
import org.opencv.android.OpenCVLoader
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
private const val PDF_MIME_TYPE = "application/pdf"
|
private const val PDF_MIME_TYPE = "application/pdf"
|
||||||
|
|
||||||
@@ -123,7 +120,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
}
|
}
|
||||||
|
|
||||||
val chooser = Intent.createChooser(shareIntent, "Share PDF")
|
val chooser = Intent.createChooser(shareIntent, getString(R.string.share_pdf))
|
||||||
val resInfoList = packageManager.queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY)
|
val resInfoList = packageManager.queryIntentActivities(chooser, PackageManager.MATCH_DEFAULT_ONLY)
|
||||||
for (resInfo in resInfoList) {
|
for (resInfo in resInfoList) {
|
||||||
val packageName = resInfo.activityInfo.packageName
|
val packageName = resInfo.activityInfo.packageName
|
||||||
@@ -151,7 +148,8 @@ class MainActivity : ComponentActivity() {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("MyScan", "Failed to save PDF", e)
|
Log.e("MyScan", "Failed to save PDF", e)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
Toast.makeText(context, "Failed to save PDF", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context,
|
||||||
|
getString(R.string.error_save), Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,9 +167,9 @@ class MainActivity : ComponentActivity() {
|
|||||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
startActivity(Intent.createChooser(openIntent, "Open PDF"))
|
startActivity(Intent.createChooser(openIntent, getString(R.string.open_pdf)))
|
||||||
} catch (_: ActivityNotFoundException) {
|
} catch (_: ActivityNotFoundException) {
|
||||||
Toast.makeText(this, "No app found to open PDF", Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, getString(R.string.error_no_pdf_app), Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import org.mydomain.myscan.BuildConfig
|
import org.mydomain.myscan.BuildConfig
|
||||||
@@ -63,10 +64,11 @@ fun AboutScreen(onBack: () -> Unit, onViewLibraries: () -> Unit) {
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text("About") },
|
title = { Text(stringResource(R.string.about)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
Icon(Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
|
contentDescription = stringResource(R.string.back))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -92,13 +94,13 @@ fun AboutContent(
|
|||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
"MyScan",
|
stringResource(R.string.app_name),
|
||||||
style = MaterialTheme.typography.headlineSmall
|
style = MaterialTheme.typography.headlineSmall
|
||||||
)
|
)
|
||||||
Spacer(Modifier.height(8.dp))
|
Spacer(Modifier.height(8.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
"A simple and respectful application to scan your documents.",
|
stringResource(R.string.app_tagline),
|
||||||
style = MaterialTheme.typography.bodyMedium
|
style = MaterialTheme.typography.bodyMedium
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -107,7 +109,7 @@ fun AboutContent(
|
|||||||
Spacer(Modifier.height(16.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
"Version",
|
stringResource(R.string.version),
|
||||||
style = MaterialTheme.typography.titleMedium
|
style = MaterialTheme.typography.titleMedium
|
||||||
)
|
)
|
||||||
Text(BuildConfig.VERSION_NAME)
|
Text(BuildConfig.VERSION_NAME)
|
||||||
@@ -115,15 +117,15 @@ fun AboutContent(
|
|||||||
Spacer(Modifier.height(16.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
"License",
|
stringResource(R.string.license),
|
||||||
style = MaterialTheme.typography.titleMedium
|
style = MaterialTheme.typography.titleMedium
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
"This application is licensed under the GNU General Public License v3.0.",
|
stringResource(R.string.licensed_under),
|
||||||
style = MaterialTheme.typography.bodyMedium
|
style = MaterialTheme.typography.bodyMedium
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "View the full license",
|
text = stringResource(R.string.view_the_full_license),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
modifier = Modifier.clickable { showLicenseDialog.value = true },
|
modifier = Modifier.clickable { showLicenseDialog.value = true },
|
||||||
color = MaterialTheme.colorScheme.primary
|
color = MaterialTheme.colorScheme.primary
|
||||||
@@ -132,15 +134,15 @@ fun AboutContent(
|
|||||||
Spacer(Modifier.height(16.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
"Libraries",
|
stringResource(R.string.libraries),
|
||||||
style = MaterialTheme.typography.titleMedium
|
style = MaterialTheme.typography.titleMedium
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
"This application uses several open-source libraries, including:\n" +
|
stringResource(R.string.libraries_intro) +
|
||||||
"• CameraX\n• Jetpack Compose\n• LiteRT\n• OpenCV\n• PDFBox",
|
"\n• CameraX\n• Jetpack Compose\n• LiteRT\n• OpenCV\n• PDFBox",
|
||||||
style = MaterialTheme.typography.bodyMedium)
|
style = MaterialTheme.typography.bodyMedium)
|
||||||
Text(
|
Text(
|
||||||
text = "View full list",
|
text = stringResource(R.string.view_full_list),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
modifier = Modifier.clickable(onClick = onViewLibraries),
|
modifier = Modifier.clickable(onClick = onViewLibraries),
|
||||||
color = MaterialTheme.colorScheme.primary
|
color = MaterialTheme.colorScheme.primary
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import org.mydomain.myscan.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MainActionButton(
|
fun MainActionButton(
|
||||||
@@ -81,7 +83,7 @@ fun AboutScreenNavButton(
|
|||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Outlined.Info,
|
imageVector = Icons.Outlined.Info,
|
||||||
contentDescription = "About",
|
contentDescription = stringResource(R.string.about),
|
||||||
tint = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f))
|
tint = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
|
|||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import org.mydomain.myscan.LiveAnalysisState
|
import org.mydomain.myscan.LiveAnalysisState
|
||||||
import org.mydomain.myscan.Point
|
import org.mydomain.myscan.Point
|
||||||
|
import org.mydomain.myscan.R
|
||||||
import org.mydomain.myscan.scaledTo
|
import org.mydomain.myscan.scaledTo
|
||||||
import java.util.concurrent.ExecutorService
|
import java.util.concurrent.ExecutorService
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
@@ -74,7 +75,8 @@ fun CameraPreview(
|
|||||||
ActivityResultContracts.RequestPermission()
|
ActivityResultContracts.RequestPermission()
|
||||||
) { isGranted: Boolean ->
|
) { isGranted: Boolean ->
|
||||||
if (!isGranted) {
|
if (!isGranted) {
|
||||||
Toast.makeText(context, "Camera permission was denied", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context,
|
||||||
|
context.getString(R.string.camera_permission_denied), Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ import androidx.compose.ui.layout.onGloballyPositioned
|
|||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@@ -79,6 +80,7 @@ import kotlinx.coroutines.delay
|
|||||||
import org.mydomain.myscan.LiveAnalysisState
|
import org.mydomain.myscan.LiveAnalysisState
|
||||||
import org.mydomain.myscan.MainViewModel
|
import org.mydomain.myscan.MainViewModel
|
||||||
import org.mydomain.myscan.MainViewModel.CaptureState
|
import org.mydomain.myscan.MainViewModel.CaptureState
|
||||||
|
import org.mydomain.myscan.R
|
||||||
import org.mydomain.myscan.Screen
|
import org.mydomain.myscan.Screen
|
||||||
import org.mydomain.myscan.ui.theme.MyScanTheme
|
import org.mydomain.myscan.ui.theme.MyScanTheme
|
||||||
|
|
||||||
@@ -203,7 +205,9 @@ private fun CameraScreenScaffold(
|
|||||||
) {
|
) {
|
||||||
CameraPreviewWithOverlay(cameraPreview, cameraUiState, Modifier.align(Alignment.BottomCenter))
|
CameraPreviewWithOverlay(cameraPreview, cameraUiState, Modifier.align(Alignment.BottomCenter))
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize().padding(innerPadding)
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(innerPadding)
|
||||||
) {
|
) {
|
||||||
AboutScreenNavButton(
|
AboutScreenNavButton(
|
||||||
onClick = toAboutScreen,
|
onClick = toAboutScreen,
|
||||||
@@ -356,7 +360,7 @@ private fun CameraPreviewWithOverlay(
|
|||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "No document detected",
|
text = stringResource(R.string.error_no_document),
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontSize = 16.sp
|
fontSize = 16.sp
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.geometry.Size
|
import androidx.compose.ui.geometry.Size
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -67,6 +68,7 @@ import net.engawapg.lib.zoomable.rememberZoomState
|
|||||||
import net.engawapg.lib.zoomable.zoomable
|
import net.engawapg.lib.zoomable.zoomable
|
||||||
import org.mydomain.myscan.Navigation
|
import org.mydomain.myscan.Navigation
|
||||||
import org.mydomain.myscan.PdfGenerationActions
|
import org.mydomain.myscan.PdfGenerationActions
|
||||||
|
import org.mydomain.myscan.R
|
||||||
import org.mydomain.myscan.ui.PdfGenerationUiState
|
import org.mydomain.myscan.ui.PdfGenerationUiState
|
||||||
import org.mydomain.myscan.ui.theme.MyScanTheme
|
import org.mydomain.myscan.ui.theme.MyScanTheme
|
||||||
|
|
||||||
@@ -102,10 +104,11 @@ fun DocumentScreen(
|
|||||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||||
titleContentColor = MaterialTheme.colorScheme.onSurface,
|
titleContentColor = MaterialTheme.colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
title = { Text("Document") },
|
title = { Text(stringResource(R.string.document)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = navigation.toCameraScreen) {
|
IconButton(onClick = navigation.toCameraScreen) {
|
||||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
Icon(Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
|
contentDescription = stringResource(R.string.back))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
@@ -161,7 +164,9 @@ private fun DocumentPreview(
|
|||||||
LaunchedEffect(imageId) {
|
LaunchedEffect(imageId) {
|
||||||
zoomState.reset()
|
zoomState.reset()
|
||||||
}
|
}
|
||||||
Box(modifier = Modifier.fillMaxSize(0.92f).align(Alignment.Center)) {
|
Box(modifier = Modifier
|
||||||
|
.fillMaxSize(0.92f)
|
||||||
|
.align(Alignment.Center)) {
|
||||||
Image(
|
Image(
|
||||||
bitmap = imageBitmap,
|
bitmap = imageBitmap,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
@@ -174,7 +179,7 @@ private fun DocumentPreview(
|
|||||||
}
|
}
|
||||||
SecondaryActionButton(
|
SecondaryActionButton(
|
||||||
Icons.Outlined.Delete,
|
Icons.Outlined.Delete,
|
||||||
contentDescription = "Delete page",
|
contentDescription = stringResource(R.string.delete_page),
|
||||||
onClick = { onDeleteImage(imageId) },
|
onClick = { onDeleteImage(imageId) },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.TopEnd)
|
.align(Alignment.TopEnd)
|
||||||
@@ -212,7 +217,7 @@ private fun PageList(
|
|||||||
SecondaryActionButton(
|
SecondaryActionButton(
|
||||||
icon = Icons.Default.Add,
|
icon = Icons.Default.Add,
|
||||||
onClick = toCameraScreen,
|
onClick = toCameraScreen,
|
||||||
contentDescription = "Add page",
|
contentDescription = stringResource(R.string.add_page),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.CenterEnd)
|
.align(Alignment.CenterEnd)
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
@@ -236,12 +241,12 @@ private fun BottomBar(
|
|||||||
MainActionButton(
|
MainActionButton(
|
||||||
onClick = { showPdfDialog.value = true },
|
onClick = { showPdfDialog.value = true },
|
||||||
icon = Icons.Default.PictureAsPdf,
|
icon = Icons.Default.PictureAsPdf,
|
||||||
text = "Export PDF",
|
text = stringResource(R.string.export_pdf),
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
SecondaryActionButton(
|
SecondaryActionButton(
|
||||||
icon = Icons.Default.RestartAlt,
|
icon = Icons.Default.RestartAlt,
|
||||||
contentDescription = "Restart",
|
contentDescription = stringResource(R.string.restart),
|
||||||
onClick = { showNewDocDialog.value = true },
|
onClick = { showNewDocDialog.value = true },
|
||||||
modifier = Modifier.padding(vertical = 8.dp)
|
modifier = Modifier.padding(vertical = 8.dp)
|
||||||
)
|
)
|
||||||
@@ -252,19 +257,19 @@ private fun BottomBar(
|
|||||||
@Composable
|
@Composable
|
||||||
fun NewDocumentDialog(onConfirm: () -> Unit, showDialog: MutableState<Boolean>) {
|
fun NewDocumentDialog(onConfirm: () -> Unit, showDialog: MutableState<Boolean>) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
title = { Text("New document") },
|
title = { Text(stringResource(R.string.new_document)) },
|
||||||
text = { Text("The current document will be lost if you haven't saved it. Do you want to continue?") },
|
text = { Text(stringResource(R.string.new_document_warning)) },
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton (onClick = {
|
TextButton (onClick = {
|
||||||
showDialog.value = false
|
showDialog.value = false
|
||||||
onConfirm()
|
onConfirm()
|
||||||
}) {
|
}) {
|
||||||
Text("Yes", fontWeight = FontWeight.Bold)
|
Text(stringResource(R.string.yes), fontWeight = FontWeight.Bold)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
TextButton(onClick = { showDialog.value = false }) {
|
TextButton(onClick = { showDialog.value = false }) {
|
||||||
Text("Cancel", fontWeight = FontWeight.Bold)
|
Text(stringResource(R.string.cancel), fontWeight = FontWeight.Bold)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDismissRequest = { showDialog.value = false },
|
onDismissRequest = { showDialog.value = false },
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import androidx.compose.material3.TopAppBar
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
|
import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.android.rememberLibraries
|
import com.mikepenz.aboutlibraries.ui.compose.android.rememberLibraries
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
|
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
|
||||||
@@ -40,10 +41,11 @@ fun LibrariesScreen(onBack: () -> Unit) {
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text("Open-source libraries") },
|
title = { Text(stringResource(R.string.libraries_open_source)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(Icons.AutoMirrored.Default.ArrowBack, contentDescription = "Back")
|
Icon(Icons.AutoMirrored.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(R.string.back))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -51,11 +51,13 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import org.mydomain.myscan.GeneratedPdf
|
import org.mydomain.myscan.GeneratedPdf
|
||||||
import org.mydomain.myscan.PdfGenerationActions
|
import org.mydomain.myscan.PdfGenerationActions
|
||||||
|
import org.mydomain.myscan.R
|
||||||
import org.mydomain.myscan.ui.PdfGenerationUiState
|
import org.mydomain.myscan.ui.PdfGenerationUiState
|
||||||
import org.mydomain.myscan.ui.theme.MyScanTheme
|
import org.mydomain.myscan.ui.theme.MyScanTheme
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -124,7 +126,7 @@ fun PdfGenerationBottomSheet(
|
|||||||
.size(34.dp)
|
.size(34.dp)
|
||||||
.padding(end = 8.dp)
|
.padding(end = 8.dp)
|
||||||
)
|
)
|
||||||
Text("Export PDF", style = MaterialTheme.typography.headlineSmall)
|
Text(stringResource(R.string.export_pdf), style = MaterialTheme.typography.headlineSmall)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(Modifier.height(16.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
@@ -132,7 +134,7 @@ fun PdfGenerationBottomSheet(
|
|||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = filename,
|
value = filename,
|
||||||
onValueChange = onFilenameChange,
|
onValueChange = onFilenameChange,
|
||||||
label = { Text("Filename") },
|
label = { Text(stringResource(R.string.filename)) },
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
@@ -180,16 +182,16 @@ private fun MainActions(
|
|||||||
onClick = onShare,
|
onClick = onShare,
|
||||||
enabled = pdf != null,
|
enabled = pdf != null,
|
||||||
icon = Icons.Default.Share,
|
icon = Icons.Default.Share,
|
||||||
iconDescription = "Share",
|
iconDescription = stringResource(R.string.share),
|
||||||
text = "Share",
|
text = stringResource(R.string.share),
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
MainActionButton(
|
MainActionButton(
|
||||||
onClick = onSave,
|
onClick = onSave,
|
||||||
enabled = pdf != null,
|
enabled = pdf != null,
|
||||||
icon = Icons.Default.Download,
|
icon = Icons.Default.Download,
|
||||||
iconDescription = "Save",
|
iconDescription = stringResource(R.string.save),
|
||||||
text = "Save",
|
text = stringResource(R.string.save),
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -206,12 +208,12 @@ private fun SavePdfBar(onOpen: () -> Unit, saveDirectoryName: String) {
|
|||||||
.padding(vertical = 8.dp, horizontal = 16.dp),
|
.padding(vertical = 8.dp, horizontal = 16.dp),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "PDF saved to $saveDirectoryName",
|
text = stringResource(R.string.pdf_saved_to, saveDirectoryName),
|
||||||
style = MaterialTheme.typography.bodyMedium
|
style = MaterialTheme.typography.bodyMedium
|
||||||
)
|
)
|
||||||
MainActionButton(
|
MainActionButton(
|
||||||
onClick = onOpen,
|
onClick = onOpen,
|
||||||
text = "Open",
|
text = stringResource(R.string.open),
|
||||||
icon = Icons.AutoMirrored.Filled.OpenInNew,
|
icon = Icons.AutoMirrored.Filled.OpenInNew,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -220,7 +222,7 @@ private fun SavePdfBar(onOpen: () -> Unit, saveDirectoryName: String) {
|
|||||||
@Composable
|
@Composable
|
||||||
private fun ErrorBar(errorMessage: String) {
|
private fun ErrorBar(errorMessage: String) {
|
||||||
Text(
|
Text(
|
||||||
text = "Error: $errorMessage",
|
text = stringResource(R.string.error, errorMessage),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = MaterialTheme.colorScheme.error,
|
color = MaterialTheme.colorScheme.error,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -239,7 +241,7 @@ private fun CloseButton(onDismiss: () -> Unit) {
|
|||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Close,
|
imageVector = Icons.Default.Close,
|
||||||
contentDescription = "Close"
|
contentDescription = stringResource(R.string.close)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +253,7 @@ fun defaultFilename(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun formatFileSize(sizeInBytes: Long?, context: Context): String {
|
fun formatFileSize(sizeInBytes: Long?, context: Context): String {
|
||||||
return if (sizeInBytes == null) "Unknown size"
|
return if (sizeInBytes == null) context.getString(R.string.unknown_size)
|
||||||
else Formatter.formatShortFileSize(context, sizeInBytes)
|
else Formatter.formatShortFileSize(context, sizeInBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,39 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
<string name="about">About</string>
|
||||||
|
<string name="add_page">Add page</string>
|
||||||
<string name="app_name">MyScan</string>
|
<string name="app_name">MyScan</string>
|
||||||
|
<string name="app_tagline">A simple and respectful application to scan your documents.</string>
|
||||||
|
<string name="back">Back</string>
|
||||||
|
<string name="camera_permission_denied">Camera permission was denied</string>
|
||||||
|
<string name="cancel">Cancel</string>
|
||||||
|
<string name="close">Close</string>
|
||||||
|
<string name="delete_page">Delete page</string>
|
||||||
|
<string name="document">Document</string>
|
||||||
|
<string name="error">Error: %1$s</string>
|
||||||
|
<string name="error_no_document">No document detected</string>
|
||||||
|
<string name="error_no_pdf_app">No app found to open PDF</string>
|
||||||
|
<string name="error_save">Failed to save PDF</string>
|
||||||
|
<string name="export_pdf">Export PDF</string>
|
||||||
|
<string name="filename">Filename</string>
|
||||||
|
<string name="libraries">Libraries</string>
|
||||||
|
<string name="libraries_intro">This application uses several open-source libraries, including:</string>
|
||||||
|
<string name="libraries_open_source">Open-source libraries</string>
|
||||||
|
<string name="license">License</string>
|
||||||
|
<string name="licensed_under">This application is licensed under the GNU General Public License v3.0.</string>
|
||||||
|
<string name="new_document">New document</string>
|
||||||
|
<string name="new_document_warning">The current document will be lost if you haven\'t saved it. Do you want to continue?</string>
|
||||||
|
<string name="open">Open</string>
|
||||||
|
<string name="open_pdf">Open PDF</string>
|
||||||
|
<string name="pdf_saved_to">PDF saved to %1$s</string>
|
||||||
|
<string name="restart">Restart</string>
|
||||||
|
<string name="save">Save</string>
|
||||||
|
<string name="share">Share</string>
|
||||||
|
<string name="share_pdf">Share PDF</string>
|
||||||
|
<string name="unknown_size">Unknown size</string>
|
||||||
|
<string name="version">Version</string>
|
||||||
|
<string name="view_the_full_license">View the full license</string>
|
||||||
|
<string name="view_full_list">View full list</string>
|
||||||
|
<string name="yes">Yes</string>
|
||||||
<plurals name="page_count">
|
<plurals name="page_count">
|
||||||
<item quantity="one">%d page</item>
|
<item quantity="one">%d page</item>
|
||||||
<item quantity="other">%d pages</item>
|
<item quantity="other">%d pages</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user