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