String extraction (#174)

* Refactored the EPUB reader to use localized string resources instead of hardcoded strings across multiple components.

* Refactored the PDF viewer and annotation components to use centralized string resources instead of hardcoded text.

* Updated `strings.xml` with extensive translation hints and localization metadata.
This commit is contained in:
Aryan 2026-04-12 16:34:47 +05:30 committed by GitHub
parent 17a0097d4a
commit b027331bd1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 716 additions and 313 deletions

View file

@ -72,6 +72,7 @@ import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize
@ -81,6 +82,7 @@ import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupPositionProvider
import androidx.core.net.toUri
import com.aryan.reader.R
import com.aryan.reader.ReaderTexture
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@ -415,8 +417,8 @@ fun ChapterWebView(
val urlToShow = showExternalLinkDialog!!
AlertDialog(
onDismissRequest = { showExternalLinkDialog = null },
title = { Text("External Link") },
text = { Text("You clicked on an external link:\n\n$urlToShow\n\nWhat would you like to do?") },
title = { Text(stringResource(R.string.dialog_external_link_title)) },
text = { Text(stringResource(R.string.dialog_external_link_desc, urlToShow)) },
confirmButton = {
Row(horizontalArrangement = Arrangement.End) {
TextButton(onClick = {
@ -425,23 +427,21 @@ fun ChapterWebView(
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
Timber.e(e, "No activity found to handle intent for URL: $urlToShow")
Toast.makeText(
context, "No browser found to open the link.", Toast.LENGTH_LONG
).show()
Toast.makeText(context, context.getString(R.string.error_no_browser), Toast.LENGTH_LONG).show()
}
showExternalLinkDialog = null
}) { Text("Open") }
}) { Text(stringResource(R.string.action_open)) }
TextButton(onClick = {
val clipboard =
context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Copied Link", urlToShow)
clipboard.setPrimaryClip(clip)
showExternalLinkDialog = null
}) { Text("Copy") }
}) { Text(stringResource(R.string.action_copy)) }
}
},
dismissButton = {
TextButton(onClick = { showExternalLinkDialog = null }) { Text("Cancel") }
TextButton(onClick = { showExternalLinkDialog = null }) { Text(stringResource(R.string.action_cancel)) }
})
}

View file

@ -68,7 +68,6 @@ import com.aryan.reader.epub.EpubChapter
import org.json.JSONArray
import org.json.JSONObject
import java.util.UUID
import kotlin.math.min
private const val BOOKMARK_PREFS_NAME = "epub_reader_bookmarks"
@ -445,10 +444,10 @@ fun PaletteManagerDialog(
}
},
confirmButton = {
TextButton(onClick = { onSave(tempPalette) }) { Text("Save") }
TextButton(onClick = { onSave(tempPalette) }) { Text(stringResource(R.string.action_save)) }
},
dismissButton = {
TextButton(onClick = onDismiss) { Text("Cancel") }
TextButton(onClick = onDismiss) { Text(stringResource(R.string.action_cancel)) }
}
)
}
@ -528,10 +527,10 @@ fun AnnotationBottomSheet(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
BottomSheetToolButton(icon = R.drawable.copy, label = "Copy", onClick = onCopy, effectiveText = effectiveText)
BottomSheetToolButton(icon = R.drawable.dictionary, label = "Dict", onClick = onDictionary, effectiveText = effectiveText)
BottomSheetToolButton(icon = R.drawable.translate, label = "Translate", onClick = onTranslate, effectiveText = effectiveText)
BottomSheetToolButton(icon = R.drawable.search, label = "Search", onClick = onSearch, effectiveText = effectiveText)
BottomSheetToolButton(icon = R.drawable.copy, label = stringResource(R.string.action_copy), onClick = onCopy, effectiveText = effectiveText)
BottomSheetToolButton(icon = R.drawable.dictionary, label = stringResource(R.string.label_dict), onClick = onDictionary, effectiveText = effectiveText)
BottomSheetToolButton(icon = R.drawable.translate, label = stringResource(R.string.dict_translate), onClick = onTranslate, effectiveText = effectiveText)
BottomSheetToolButton(icon = R.drawable.search, label = stringResource(R.string.action_search), onClick = onSearch, effectiveText = effectiveText)
}
Spacer(Modifier.height(16.dp))
@ -540,7 +539,7 @@ fun AnnotationBottomSheet(
OutlinedTextField(
value = noteText,
onValueChange = { noteText = it },
placeholder = { Text("Add a note...", color = effectiveText.copy(alpha = 0.5f)) },
placeholder = { Text(stringResource(R.string.placeholder_add_note), color = effectiveText.copy(alpha = 0.5f)) },
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 100.dp),
@ -652,23 +651,23 @@ fun PaginatedTextSelectionMenu(
}
val actions = mutableListOf<MenuActionItem>()
actions.add(MenuActionItem(iconRes = R.drawable.copy, label = "Copy", onClick = onCopy))
actions.add(MenuActionItem(iconRes = R.drawable.copy, label = stringResource(R.string.action_copy), onClick = onCopy))
if (onTts != null) {
actions.add(MenuActionItem(imageVector = Icons.AutoMirrored.Filled.VolumeUp, label = "Speak", onClick = onTts))
actions.add(MenuActionItem(imageVector = Icons.AutoMirrored.Filled.VolumeUp, label = stringResource(R.string.label_speak), onClick = onTts))
}
actions.add(MenuActionItem(iconRes = R.drawable.dictionary, label = "Dict", onClick = onDictionary))
actions.add(MenuActionItem(iconRes = R.drawable.translate, label = "Translate", onClick = onTranslate))
actions.add(MenuActionItem(iconRes = R.drawable.search, label = "Search", onClick = onSearch))
actions.add(MenuActionItem(iconRes = R.drawable.dictionary, label = stringResource(R.string.label_dict), onClick = onDictionary))
actions.add(MenuActionItem(iconRes = R.drawable.translate, label = stringResource(R.string.dict_translate), onClick = onTranslate))
actions.add(MenuActionItem(iconRes = R.drawable.search, label = stringResource(R.string.action_search), onClick = onSearch))
if (onNote != null) {
actions.add(MenuActionItem(imageVector = Icons.Default.Edit, label = "Note", onClick = onNote))
actions.add(MenuActionItem(imageVector = Icons.Default.Edit, label = stringResource(R.string.label_note), onClick = onNote))
}
if (onSelectAll != null) {
actions.add(MenuActionItem(iconRes = R.drawable.select_all, label = "Select All", onClick = onSelectAll))
actions.add(MenuActionItem(iconRes = R.drawable.select_all, label = stringResource(R.string.select_all), onClick = onSelectAll))
}
if (onDelete != null) {
actions.add(MenuActionItem(imageVector = Icons.Default.Delete, label = "Remove", onClick = onDelete, isError = true))
actions.add(MenuActionItem(imageVector = Icons.Default.Delete, label = stringResource(R.string.action_remove), onClick = onDelete, isError = true))
}
Column(modifier = Modifier.padding(bottom = 4.dp)) {
@ -753,7 +752,7 @@ fun HighlightColorRow(
if (selectedColor == colorEnum) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = "Selected",
contentDescription = stringResource(R.string.content_desc_selected),
tint = if (colorEnum == HighlightColor.WHITE || colorEnum == HighlightColor.YELLOW) Color.Black else Color.White,
modifier = Modifier.size(18.dp)
)
@ -825,13 +824,13 @@ fun PaginatedTextSelectionMenu(
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
imageVector = Icons.Default.Edit,
contentDescription = "Note",
contentDescription = stringResource(R.string.label_note),
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(14.dp)
)
Spacer(Modifier.width(6.dp))
Text(
"Note",
stringResource(R.string.label_note),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold
@ -851,24 +850,24 @@ fun PaginatedTextSelectionMenu(
}
val actions = mutableListOf<MenuActionItem>()
actions.add(MenuActionItem(iconRes = R.drawable.copy, label = "Copy", onClick = onCopy))
actions.add(MenuActionItem(iconRes = R.drawable.copy, label = stringResource(R.string.action_copy), onClick = onCopy))
if (onTts != null) {
actions.add(MenuActionItem(imageVector = Icons.AutoMirrored.Filled.VolumeUp, label = "Speak", onClick = onTts))
actions.add(MenuActionItem(imageVector = Icons.AutoMirrored.Filled.VolumeUp, label = stringResource(R.string.label_speak), onClick = onTts))
}
actions.add(MenuActionItem(iconRes = R.drawable.dictionary, label = "Dict", onClick = onDictionary))
actions.add(MenuActionItem(iconRes = R.drawable.translate, label = "Translate", onClick = onTranslate))
actions.add(MenuActionItem(iconRes = R.drawable.search, label = "Search", onClick = onSearch))
actions.add(MenuActionItem(iconRes = R.drawable.dictionary, label = stringResource(R.string.label_dict), onClick = onDictionary))
actions.add(MenuActionItem(iconRes = R.drawable.translate, label = stringResource(R.string.dict_translate), onClick = onTranslate))
actions.add(MenuActionItem(iconRes = R.drawable.search, label = stringResource(R.string.action_search), onClick = onSearch))
if (onNote != null) {
val noteLabel = if (existingNote.isNullOrBlank()) "Note" else "Edit"
val noteLabel = if (existingNote.isNullOrBlank()) stringResource(R.string.label_note) else stringResource(R.string.label_edit)
actions.add(MenuActionItem(imageVector = Icons.Default.Edit, label = noteLabel, onClick = onNote))
}
if (onSelectAll != null) {
actions.add(MenuActionItem(iconRes = R.drawable.select_all, label = "Select All", onClick = onSelectAll))
actions.add(MenuActionItem(iconRes = R.drawable.select_all, label = stringResource(R.string.select_all), onClick = onSelectAll))
}
if (onDelete != null) {
actions.add(MenuActionItem(imageVector = Icons.Default.Delete, label = "Remove", onClick = onDelete, isError = true))
actions.add(MenuActionItem(imageVector = Icons.Default.Delete, label = stringResource(R.string.action_remove), onClick = onDelete, isError = true))
}
Column(modifier = Modifier.padding(bottom = 4.dp)) {

View file

@ -19,6 +19,8 @@
*/
package com.aryan.reader.epubreader
import android.content.Context
import com.aryan.reader.R
import timber.log.Timber
import com.aryan.reader.epub.EpubBook
import com.aryan.reader.paginatedreader.LocatorConverter
@ -40,6 +42,7 @@ data class ChapterLoadingResult(
* the initial chunk to display based on navigation state (CFI, overrides, etc.).
*/
suspend fun loadChapterContent(
context: Context,
epubBook: EpubBook,
chapterIndex: Int,
chunkTargetOverride: Int?,
@ -64,12 +67,12 @@ suspend fun loadChapterContent(
chunkOfElements.joinToString(separator = "\n") { it.outerHtml() }
}
if (chunkedList.isEmpty()) {
head to listOf("<body><p>This chapter is empty.</p></body>")
head to listOf("<body><p>${context.getString(R.string.chapter_empty)}</p></body>")
} else {
head to chunkedList
}
} else {
"" to listOf("<h1>Chapter not found</h1>")
"" to listOf("<h1>${context.getString(R.string.chapter_not_found)}</h1>")
}
var targetChunk = 0
@ -104,7 +107,7 @@ suspend fun loadChapterContent(
Timber.e(e, "Failed to parse chapter")
ChapterLoadingResult(
head = "",
chunks = listOf("<h1>Error loading chapter</h1><p>${e.message}</p>"),
chunks = listOf("<h1>${context.getString(R.string.error_loading_chapter)}</h1><p>${e.message}</p>"),
startChunkIndex = 0,
isSuccess = false,
errorMessage = e.message

View file

@ -277,7 +277,7 @@ fun EpubReaderTopBar(
onDismissRequest = { showMoreMenu = false }
) {
DropdownMenuItem(
text = { Text("Customize Toolbar") },
text = { Text(stringResource(R.string.title_customize_toolbar)) },
onClick = {
showMoreMenu = false
onCustomizeTools()
@ -1078,7 +1078,7 @@ fun AutoScrollControls(
) {
Icon(
imageVector = if (isPlaying) Icons.Default.Pause else Icons.Default.PlayArrow,
contentDescription = if (isPlaying) stringResource(R.string.content_desc_pause_playback) else stringResource(R.string.content_desc_start_playback),
contentDescription = if (isPlaying) stringResource(R.string.tooltip_tts_pause) else stringResource(R.string.content_desc_start_playback),
modifier = Modifier.size(20.dp)
)
}
@ -1395,7 +1395,7 @@ fun CustomizeToolsSheet(
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Select the tools you want to keep visible. Unchecking a tool hides it from the UI to give you a distraction-free reading space.",
text = stringResource(R.string.desc_customize_toolbar),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
@ -1495,17 +1495,19 @@ fun TtsControlsSheet(
ttsController.sliceAndRetainPosition()
}
val ttsSample = stringResource(R.string.tts_sample_text)
ModalBottomSheet(
onDismissRequest = onDismiss,
contentWindowInsets = { WindowInsets.navigationBars }
) {
Column(modifier = Modifier.padding(horizontal = 24.dp).padding(bottom = 24.dp)) {
Text("Voice Adjustments", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
Text(stringResource(R.string.tts_voice_adjustments), style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
Spacer(Modifier.height(16.dp))
// Rate Slider
Row(verticalAlignment = Alignment.CenterVertically) {
Text("Speed (${"%.1f".format(rate)}x)", modifier = Modifier.weight(1f), style = MaterialTheme.typography.bodyMedium)
Text(stringResource(R.string.tts_speed_label, "%.1f".format(rate)), modifier = Modifier.weight(1f), style = MaterialTheme.typography.bodyMedium)
IconButton(onClick = {
rate = 1.0f
ttsController.pause()
@ -1534,7 +1536,7 @@ fun TtsControlsSheet(
// Pitch Slider
Row(verticalAlignment = Alignment.CenterVertically) {
Text("Pitch (${"%.1f".format(pitch)}x)", modifier = Modifier.weight(1f), style = MaterialTheme.typography.bodyMedium)
Text(stringResource(R.string.tts_pitch_label, "%.1f".format(pitch)), modifier = Modifier.weight(1f), style = MaterialTheme.typography.bodyMedium)
IconButton(onClick = {
pitch = 1.0f
ttsController.pause()
@ -1568,7 +1570,7 @@ fun TtsControlsSheet(
if (ttsState.isPlaying) ttsController.pause()
tts?.setSpeechRate(rate)
tts?.setPitch(pitch)
tts?.speak("This is how your current voice settings sound.", TextToSpeech.QUEUE_FLUSH, null, null)
tts?.speak(ttsSample, TextToSpeech.QUEUE_FLUSH, null, null)
},
modifier = Modifier.fillMaxWidth(),
enabled = isTtsReady,
@ -1611,14 +1613,14 @@ fun TtsControlsSheet(
} else {
Icon(
painter = painterResource(if (ttsState.isPlaying) R.drawable.pause else R.drawable.play),
contentDescription = if (ttsState.isPlaying) "Pause Book" else "Play Book",
contentDescription = if (ttsState.isPlaying) stringResource(R.string.tts_pause_book) else stringResource(R.string.tts_resume_book),
modifier = Modifier.size(32.dp)
)
}
}
Spacer(Modifier.height(8.dp))
Text(
text = if (ttsState.isPlaying) "Pause Book" else "Resume Book",
text = if (ttsState.isPlaying) stringResource(R.string.tts_pause_book) else stringResource(R.string.tts_resume_book),
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
@ -1635,7 +1637,7 @@ fun TtsControlsSheet(
) {
Icon(Icons.Default.Settings, contentDescription = null)
Spacer(Modifier.width(8.dp))
Text("System Voice / Engine Settings")
Text(stringResource(R.string.tts_system_settings))
}
}
}

View file

@ -551,7 +551,7 @@ private fun BookmarksList(
onDismissRequest = { bookmarkMenuExpandedFor = null }
) {
DropdownMenuItem(
text = { Text(stringResource(R.string.menu_rename)) },
text = { Text(stringResource(R.string.action_rename)) },
onClick = {
showRenameBookmarkDialog = bookmark
bookmarkMenuExpandedFor = null
@ -680,12 +680,12 @@ private fun HighlightsList(
androidx.compose.material3.FilterChip(
selected = !filterWithNotesOnly,
onClick = { filterWithNotesOnly = false },
label = { Text("All") }
label = { Text(stringResource(R.string.filter_all)) }
)
androidx.compose.material3.FilterChip(
selected = filterWithNotesOnly,
onClick = { filterWithNotesOnly = true },
label = { Text("With Notes") }
label = { Text(stringResource(R.string.filter_with_notes)) }
)
}
@ -773,7 +773,7 @@ private fun HighlightsList(
)
HorizontalDivider()
DropdownMenuItem(
text = { Text(if (highlight.note.isNullOrBlank()) "Add Note" else "Edit Note") },
text = { Text(if (highlight.note.isNullOrBlank()) stringResource(R.string.menu_add_note) else stringResource(R.string.menu_edit_note)) },
onClick = {
onEditNote(highlight)
highlightMenuExpandedFor = null

View file

@ -702,7 +702,7 @@ fun EpubReaderHost(
if (!selectedDictPackage.isNullOrEmpty()) {
ExternalDictionaryHelper.launchDictionary(context, selectedDictPackage!!, word)
} else {
Toast.makeText(context, "Please select a dictionary app first.", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.toast_select_dictionary_first), Toast.LENGTH_SHORT).show()
showDictionarySettingsSheet = true
}
}
@ -712,7 +712,7 @@ fun EpubReaderHost(
if (!selectedTranslatePackage.isNullOrEmpty()) {
ExternalDictionaryHelper.launchTranslate(context, selectedTranslatePackage!!, text)
} else {
Toast.makeText(context, "Please select a translate app first.", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.toast_select_translate_first), Toast.LENGTH_SHORT).show()
showDictionarySettingsSheet = true
}
}
@ -721,7 +721,7 @@ fun EpubReaderHost(
if (!selectedSearchPackage.isNullOrEmpty()) {
ExternalDictionaryHelper.launchSearch(context, selectedSearchPackage!!, text)
} else {
Toast.makeText(context, "Please select a search app first.", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.toast_select_search_first), Toast.LENGTH_SHORT).show()
showDictionarySettingsSheet = true
}
}
@ -1371,6 +1371,7 @@ fun EpubReaderHost(
activeFragmentId = null
val result = loadChapterContent(
context = context,
epubBook = epubBook,
chapterIndex = currentChapterIndex,
chunkTargetOverride = chunkTargetOverride,
@ -2835,7 +2836,7 @@ fun EpubReaderHost(
if (pullToTurnEnabled && currentChapterIndex > 0) {
ChapterChangeIndicator(
text = "Release for Previous Chapter",
text = stringResource(R.string.release_for_previous_chapter),
progress = pullToPrevProgress,
isPullingDown = true,
modifier = Modifier
@ -2846,7 +2847,7 @@ fun EpubReaderHost(
if (pullToTurnEnabled && currentChapterIndex < chapters.size - 1) {
ChapterChangeIndicator(
text = "Release for Next Chapter",
text = stringResource(R.string.release_for_next_chapter),
progress = pullToNextProgress,
isPullingDown = false,
modifier = Modifier

View file

@ -481,7 +481,7 @@ fun ReaderTextFormatPanel(
// FONT & ALIGNMENT SECTION
Text(
text = "FONT & ALIGNMENT",
text = stringResource(R.string.section_font_alignment),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
@ -504,7 +504,7 @@ fun ReaderTextFormatPanel(
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = "Aa",
text = stringResource(R.string.label_aa_preview),
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onSecondaryContainer,
@ -570,7 +570,7 @@ fun ReaderTextFormatPanel(
// LAYOUT & SPACING SECTION
Text(
text = "LAYOUT & SPACING",
text = stringResource(R.string.section_layout_spacing),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
@ -581,7 +581,7 @@ fun ReaderTextFormatPanel(
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
// Size
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp)) {
Text("Font Size", style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp))
Text(stringResource(R.string.label_font_size), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp))
Slider(
value = currentFontSize,
onValueChange = onFontSizeChange,
@ -589,11 +589,11 @@ fun ReaderTextFormatPanel(
steps = 24,
modifier = Modifier.weight(1f)
)
Text(if (currentFontSize in 0.99f..1.01f) "Orig" else "%.1fx".format(currentFontSize), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp), textAlign = TextAlign.End)
Text(if (currentFontSize in 0.99f..1.01f) stringResource(R.string.label_original) else "%.1fx".format(currentFontSize), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp), textAlign = TextAlign.End)
}
// Lines
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp)) {
Text("Line Height", style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp))
Text(stringResource(R.string.label_line_height), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp))
Slider(
value = currentLineHeight,
onValueChange = onLineHeightChange,
@ -601,11 +601,11 @@ fun ReaderTextFormatPanel(
steps = 19,
modifier = Modifier.weight(1f)
)
Text(if (currentLineHeight <= 1.01f) "Orig" else "%.1fx".format(currentLineHeight), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp), textAlign = TextAlign.End)
Text(if (currentLineHeight <= 1.01f) stringResource(R.string.label_original) else "%.1fx".format(currentLineHeight), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp), textAlign = TextAlign.End)
}
// Paragraph Gap
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp)) {
Text("Paragraph Gap", style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp))
Text(stringResource(R.string.label_paragraph_gap), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp))
Slider(
value = currentParagraphGap,
onValueChange = onParagraphGapChange,
@ -613,7 +613,7 @@ fun ReaderTextFormatPanel(
steps = 29,
modifier = Modifier.weight(1f)
)
Text(if (currentParagraphGap in 0.99f..1.01f) "Orig" else "%.1fx".format(currentParagraphGap), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp), textAlign = TextAlign.End)
Text(if (currentParagraphGap in 0.99f..1.01f) stringResource(R.string.label_original) else "%.1fx".format(currentParagraphGap), style = MaterialTheme.typography.labelMedium, modifier = Modifier.width(40.dp), textAlign = TextAlign.End)
}
}
Spacer(Modifier.height(8.dp))

View file

@ -11,6 +11,7 @@ import android.os.Build
import android.widget.Toast
import timber.log.Timber
import androidx.core.net.toUri
import com.aryan.reader.R
data class ExternalDictionaryApp(
val label: String,
@ -72,7 +73,7 @@ object ExternalDictionaryHelper {
sortedApps.add(
0,
ExternalDictionaryApp(
label = "Search",
label = context.getString(R.string.dict_app_label_search),
packageName = GOOGLE_SEARCH_PKG,
icon = null
)
@ -127,7 +128,7 @@ object ExternalDictionaryHelper {
} catch (e: Exception) {
Timber.e(e, "Failed to launch dictionary app: $packageName")
Toast.makeText(context, "Error opening dictionary", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.error_opening_dictionary), Toast.LENGTH_SHORT).show()
}
}
@ -172,7 +173,7 @@ object ExternalDictionaryHelper {
launchGenericSend(context, packageName, query)
} catch (e: Exception) {
Timber.e(e, "Failed to launch translate app: $packageName")
Toast.makeText(context, "Error opening translate app", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.error_opening_translate), Toast.LENGTH_SHORT).show()
}
}
@ -210,7 +211,7 @@ object ExternalDictionaryHelper {
launchGenericSend(context, packageName, query)
} catch (e: Exception) {
Timber.e(e, "Failed to launch search app: $packageName")
Toast.makeText(context, "Error opening search app", Toast.LENGTH_SHORT).show()
Toast.makeText(context, context.getString(R.string.error_opening_search), Toast.LENGTH_SHORT).show()
}
}