Remove hardcoded strings

This commit is contained in:
Torsten Grote
2025-07-24 15:59:33 -03:00
parent d35e948952
commit 5eb9b3cd78
17 changed files with 124 additions and 47 deletions

View File

@@ -44,7 +44,10 @@ fun About(onBackClicked: () -> Unit) {
TopAppBar(
navigationIcon = {
IconButton(onClick = onBackClicked) {
Icon(Icons.AutoMirrored.Default.ArrowBack, "back")
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = stringResource(R.string.back),
)
}
},
title = {
@@ -69,12 +72,12 @@ fun About(onBackClicked: () -> Unit) {
Column(modifier = Modifier.padding(top = 24.dp, bottom = 16.dp)) {
val uriHandler = LocalUriHandler.current
Text(
text = "Links",
text = stringResource(R.string.links),
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.bodyLarge,
)
Text(
text = "Homepage",
text = stringResource(R.string.menu_website),
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.secondary,
modifier = Modifier
@@ -82,7 +85,7 @@ fun About(onBackClicked: () -> Unit) {
.clickable { uriHandler.openUriSafe("https://f-droid.org") }
)
Text(
text = "Gitlab",
text = stringResource(R.string.about_source),
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.secondary,
modifier = Modifier

View File

@@ -18,6 +18,7 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -31,6 +32,7 @@ import androidx.navigation3.ui.NavDisplay
import androidx.window.core.layout.WindowSizeClass.Companion.WIDTH_DP_MEDIUM_LOWER_BOUND
import org.fdroid.database.AppListSortOrder
import org.fdroid.fdroid.ui.theme.FDroidContent
import org.fdroid.next.R
import org.fdroid.ui.apps.MyApps
import org.fdroid.ui.apps.MyAppsViewModel
import org.fdroid.ui.details.AppDetails
@@ -80,7 +82,7 @@ fun Main(onListeningForIntent: () -> Unit = {}) {
entryProvider = entryProvider {
entry<NavigationKey.Discover>(
metadata = ListDetailSceneStrategy.listPane("appdetails") {
Text("No app selected")
Text(stringResource(R.string.no_app_selected))
},
) {
val viewModel = hiltViewModel<DiscoverViewModel>()
@@ -101,7 +103,7 @@ fun Main(onListeningForIntent: () -> Unit = {}) {
}
entry<NavigationKey.MyApps>(
metadata = ListDetailSceneStrategy.listPane("appdetails") {
Text("No app selected")
Text(stringResource(R.string.no_app_selected))
},
) {
val myAppsViewModel = hiltViewModel<MyAppsViewModel>()
@@ -139,7 +141,7 @@ fun Main(onListeningForIntent: () -> Unit = {}) {
}
entry<NavigationKey.AppList>(
metadata = ListDetailSceneStrategy.listPane("appdetails") {
Text("No app selected")
Text(stringResource(R.string.no_app_selected))
},
) {
val appListViewModel = hiltViewModel<AppListViewModel>()
@@ -174,7 +176,7 @@ fun Main(onListeningForIntent: () -> Unit = {}) {
}
entry<NavigationKey.Repos>(
metadata = ListDetailSceneStrategy.listPane("repos") {
Text(text = "No repository selected")
Text(text = stringResource(R.string.no_repository_selected))
},
) {
val viewModel = hiltViewModel<RepositoriesViewModel>()

View File

@@ -26,7 +26,10 @@ fun Settings(onBackClicked: () -> Unit) {
TopAppBar(
navigationIcon = {
IconButton(onClick = onBackClicked) {
Icon(Icons.AutoMirrored.Default.ArrowBack, "back")
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = stringResource(R.string.back),
)
}
},
title = {

View File

@@ -73,7 +73,7 @@ fun MyApps(
topBar = {
TopAppBar(
title = {
Text("My apps")
Text(stringResource(R.string.menu_apps_my))
},
actions = {
var sortByMenuExpanded by remember { mutableStateOf(false) }
@@ -85,7 +85,7 @@ fun MyApps(
onDismissRequest = { sortByMenuExpanded = false },
) {
DropdownMenuItem(
text = { Text("Sort by name") },
text = { Text(stringResource(R.string.sort_by_name)) },
leadingIcon = {
Icon(Icons.Filled.SortByAlpha, null)
},
@@ -101,7 +101,7 @@ fun MyApps(
},
)
DropdownMenuItem(
text = { Text("Sort by latest") },
text = { Text(stringResource(R.string.sort_by_latest)) },
leadingIcon = {
Icon(Icons.Filled.AccessTime, null)
},
@@ -149,7 +149,7 @@ fun MyApps(
onClick = {},
modifier = Modifier.padding(end = 16.dp),
) {
Text("Update all")
Text(stringResource(R.string.update_all))
}
}
}

View File

@@ -19,9 +19,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter.Companion.tint
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.fdroid.fdroid.ui.theme.FDroidContent
import org.fdroid.next.R
import org.fdroid.ui.utils.AsyncShimmerImage
import org.fdroid.ui.utils.testApp
@@ -40,7 +42,7 @@ fun AntiFeatures(
) {
ExpandableSection(
icon = rememberVectorPainter(Icons.Default.WarningAmber),
title = "This app has anti-features",
title = stringResource(R.string.anti_features_title),
modifier = Modifier.padding(horizontal = 16.dp),
) {
Column {

View File

@@ -112,7 +112,7 @@ fun AppDetails(
.padding(horizontal = 16.dp, vertical = 8.dp),
) {
Text(
text = "What's new",
text = stringResource(R.string.whats_new_title),
style = MaterialTheme.typography.titleMediumEmphasized,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
)
@@ -160,7 +160,11 @@ fun AppDetails(
}
TextButton(onClick = { descriptionExpanded = !descriptionExpanded }) {
Text(
text = if (descriptionExpanded) "Less" else "More",
text = if (descriptionExpanded) {
stringResource(R.string.less)
} else {
stringResource(R.string.more)
},
textAlign = Center,
maxLines = if (descriptionExpanded) Int.MAX_VALUE else 3,
modifier = Modifier
@@ -207,7 +211,7 @@ fun AppDetails(
.padding(horizontal = 16.dp, vertical = 8.dp),
) {
Text(
text = "Donate",
text = stringResource(R.string.donate_title),
style = MaterialTheme.typography.titleMediumEmphasized,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
)
@@ -244,7 +248,7 @@ fun AppDetails(
item.bitcoinUri?.let { bitcoinUri ->
AppDetailsLink(
icon = Icons.Default.CurrencyBitcoin,
title = "Bitcoin",
title = stringResource(R.string.menu_bitcoin),
url = bitcoinUri,
modifier = modifier
.padding(horizontal = 16.dp)
@@ -254,7 +258,7 @@ fun AppDetails(
item.litecoinUri?.let { litecoinUri ->
AppDetailsLink(
icon = Icons.Default.CurrencyBitcoin,
title = "Litecoin",
title = stringResource(R.string.menu_litecoin),
url = litecoinUri,
modifier = modifier
.padding(horizontal = 16.dp)
@@ -327,7 +331,7 @@ fun AppDetails(
// Developer contact
if (item.showAuthorContact) ExpandableSection(
icon = rememberVectorPainter(Icons.Default.Person),
title = "Developer contact",
title = stringResource(R.string.developer_contact),
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
) {
Column(modifier = Modifier.padding(start = 16.dp)) {

View File

@@ -106,7 +106,7 @@ fun AppDetailsHeader(
item.app.authorName?.let { authorName ->
SelectionContainer {
Text(
text = "By $authorName",
text = stringResource(R.string.author_by, authorName),
style = MaterialTheme.typography.bodyMedium,
)
}
@@ -119,9 +119,9 @@ fun AppDetailsHeader(
SelectionContainer {
Text(
text = if (size == null) {
"Last updated: $lastUpdated"
stringResource(R.string.last_updated, lastUpdated)
} else {
"Last updated: $lastUpdated ($size)"
stringResource(R.string.last_updated_with_size, lastUpdated, size)
},
style = MaterialTheme.typography.bodyMedium,
)

View File

@@ -18,8 +18,10 @@ import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import org.fdroid.next.R
import org.fdroid.ui.utils.openUriSafe
@Composable
@@ -43,7 +45,7 @@ fun AppDetailsLink(icon: ImageVector, title: String, url: String, modifier: Modi
clipboardManager.setClipEntry(entry)
}
},
onLongClickLabel = "Copy link",
onLongClickLabel = stringResource(R.string.copy_link),
),
) {
Icon(icon, null)

View File

@@ -63,7 +63,7 @@ fun AppDetailsTopAppBar(
IconButton(onClick = { expanded = !expanded }) {
Icon(
imageVector = Icons.Filled.MoreVert,
contentDescription = "Localized description",
contentDescription = stringResource(R.string.more),
)
}
AppDetailsMenu(item, expanded) { expanded = false }

View File

@@ -16,9 +16,11 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.fdroid.fdroid.ui.theme.FDroidContent
import org.fdroid.next.R
import org.fdroid.ui.utils.testApp
@Composable
@@ -39,7 +41,7 @@ fun AppDetailsWarnings(
) {
Icon(Icons.Default.WarningAmber, "")
Text(
"Can not update this app, because no compatible versions available in repository.",
text = stringResource(R.string.app_no_compatible_versions),
style = MaterialTheme.typography.bodyLarge,
)
}
@@ -51,7 +53,7 @@ fun AppDetailsWarnings(
) {
Icon(Icons.Default.WarningAmber, "")
Text(
"Auto-update not available, because app targets old version of Android.",
stringResource(R.string.app_no_auto_update),
style = MaterialTheme.typography.bodyLarge,
)
}

View File

@@ -33,9 +33,9 @@ import androidx.compose.ui.unit.dp
import org.fdroid.fdroid.ui.theme.FDroidContent
import org.fdroid.index.v2.PackageVersion
import org.fdroid.next.R
import org.fdroid.ui.utils.FDroidOutlineButton
import org.fdroid.ui.utils.asRelativeTimeString
import org.fdroid.ui.utils.testApp
import org.fdroid.ui.utils.FDroidOutlineButton
@Composable
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@@ -101,7 +101,10 @@ fun Version(
overflow = TextOverflow.Ellipsis,
)
Text(
text = "Added " + version.added.asRelativeTimeString(),
text = stringResource(
R.string.added_x_ago,
version.added.asRelativeTimeString(),
),
style = MaterialTheme.typography.bodyMedium,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@@ -135,7 +138,10 @@ fun Version(
Column(modifier = Modifier.weight(1f)) {
version.size?.let { size ->
Text(
text = "Size: " + Formatter.formatFileSize(LocalContext.current, size),
text = stringResource(
R.string.size_colon,
Formatter.formatFileSize(LocalContext.current, size)
),
style = MaterialTheme.typography.bodySmall,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@@ -144,7 +150,10 @@ fun Version(
version.packageManifest.nativecode?.let { nativeCode ->
if (nativeCode.isNotEmpty()) {
Text(
text = "Architectures: " + nativeCode.joinToString(", "),
text = stringResource(
R.string.architectures_colon,
nativeCode.joinToString(", ")
),
style = MaterialTheme.typography.bodySmall,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@@ -153,7 +162,10 @@ fun Version(
}
version.signer?.let { signer ->
Text(
text = "Signer: " + signer.sha256[0].substring(0..15),
text = stringResource(
R.string.signer_colon,
signer.sha256[0].substring(0..15)
),
style = MaterialTheme.typography.bodySmall,
maxLines = 1,
overflow = TextOverflow.Ellipsis,

View File

@@ -16,7 +16,9 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import kotlinx.coroutines.launch
import org.fdroid.next.R
@Composable
@OptIn(ExperimentalMaterial3Api::class)
@@ -32,13 +34,16 @@ fun AppSearchInputField(
onSearch = {
scope.launch { searchBarState.animateToCollapsed() }
},
placeholder = { Text("Search...") },
placeholder = { Text(stringResource(R.string.search_placeholder)) },
leadingIcon = {
if (searchBarState.currentValue == SearchBarValue.Expanded) {
IconButton(
onClick = { scope.launch { searchBarState.animateToCollapsed() } }
) {
Icon(Icons.AutoMirrored.Default.ArrowBack, contentDescription = "Back")
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = stringResource(R.string.back)
)
}
} else {
Icon(Icons.Default.Search, contentDescription = null)

View File

@@ -61,7 +61,7 @@ fun Discover(
topBar = {
TopAppBar(
title = {
Text("F-Droid")
Text(stringResource(R.string.app_name))
},
actions = {
topBarMenuItems.forEach { dest ->
@@ -104,7 +104,7 @@ fun Discover(
is LoadingDiscoverModel -> {
AnimatedVisibility(discoverModel.isFirstStart) {
Text(
"This is the first start, loading repositories...",
stringResource(R.string.first_start_loading),
textAlign = TextAlign.Center,
modifier = Modifier
.padding(16.dp)
@@ -147,7 +147,7 @@ fun Discover(
}
}
NoEnabledReposDiscoverModel -> {
Text("No repositories enabled.\nEnable at least one repository to see apps.")
Text(stringResource(R.string.no_repos_enabled))
}
}
AnimatedVisibility(discoverModel is LoadedDiscoverModel) {

View File

@@ -36,10 +36,12 @@ import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.fdroid.database.AppListSortOrder
import org.fdroid.fdroid.ui.theme.FDroidContent
import org.fdroid.next.R
import org.fdroid.ui.utils.BigLoadingIndicator
@Composable
@@ -61,7 +63,10 @@ fun AppList(
},
navigationIcon = {
IconButton(onClick = onBackClicked) {
Icon(Icons.AutoMirrored.Default.ArrowBack, "back")
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = stringResource(R.string.back),
)
}
},
actions = {

View File

@@ -25,8 +25,10 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import org.fdroid.database.AppListSortOrder
import org.fdroid.next.R
interface AppListInfo {
val model: AppListModel
@@ -67,8 +69,8 @@ fun ColumnScope.AppsFilter(
},
label = {
val s = when (info.model.sortBy) {
AppListSortOrder.NAME -> "Sort by name"
AppListSortOrder.LAST_UPDATED -> "Sort by latest"
AppListSortOrder.NAME -> stringResource(R.string.sort_by_name)
AppListSortOrder.LAST_UPDATED -> stringResource(R.string.sort_by_latest)
}
Text(s)
DropdownMenu(
@@ -76,7 +78,7 @@ fun ColumnScope.AppsFilter(
onDismissRequest = { sortByMenuExpanded = false },
) {
DropdownMenuItem(
text = { Text("Sort by name") },
text = { Text(stringResource(R.string.sort_by_name)) },
leadingIcon = {
Icon(Icons.Filled.SortByAlpha, null)
},
@@ -86,9 +88,12 @@ fun ColumnScope.AppsFilter(
},
)
DropdownMenuItem(
text = { Text("Sort by latest") },
text = { Text(stringResource(R.string.sort_by_latest)) },
leadingIcon = {
Icon(Icons.Filled.AccessTime, null)
Icon(
imageVector = Icons.Filled.AccessTime,
contentDescription = null,
)
},
onClick = {
info.sortBy(AppListSortOrder.LAST_UPDATED)
@@ -109,7 +114,7 @@ fun ColumnScope.AppsFilter(
)
},
label = {
Text("Category")
Text(stringResource(R.string.category))
DropdownMenu(
expanded = categoryMenuExpanded,
onDismissRequest = { categoryMenuExpanded = false },
@@ -137,7 +142,7 @@ fun ColumnScope.AppsFilter(
)
},
label = {
Text("Repository")
Text(stringResource(R.string.repo_details))
DropdownMenu(
expanded = repoMenuExpanded,
onDismissRequest = { repoMenuExpanded = false },

View File

@@ -41,7 +41,10 @@ fun Repositories(
TopAppBar(
navigationIcon = {
IconButton(onClick = onBackClicked) {
Icon(Icons.AutoMirrored.Default.ArrowBack, "back")
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = stringResource(R.string.back),
)
}
},
title = {
@@ -54,7 +57,10 @@ fun Repositories(
onClick = onAddRepo,
modifier = Modifier.padding(16.dp)
) {
Icon(Icons.Default.Add, contentDescription = "Add repo")
Icon(
imageVector = Icons.Default.Add,
contentDescription = stringResource(R.string.menu_add_repo),
)
}
}
) { paddingValues ->

View File

@@ -8,9 +8,35 @@
<string name="menu_discover">Discover</string>
<string name="menu_apps_my">My apps</string>
<string name="first_start_loading">Retrieving apps…\n\nThis may take some time.</string>
<string name="no_repos_enabled">No repositories enabled.\nEnable at least one repository to see apps.</string>
<string name="no_app_selected">No app selected</string>
<string name="no_repository_selected">No repository selected</string>
<string name="app_list_new">New apps</string>
<string name="app_list_recently_updated">Recently updated</string>
<string name="app_list_all">All apps</string>
<string name="app_list_author">Apps by %s</string>
<string name="search_placeholder">Search…</string>
<string name="sort_by_name">Sort by name</string>
<string name="sort_by_latest">Sort by latest</string>
<string name="category">Category</string>
<string name="author_by">By %1$s</string>
<string name="last_updated">Last updated: %1$s</string>
<!-- The placeholder in round brackets will be replaced with the size of the app -->
<string name="last_updated_with_size">Last updated: %1$s (%2$s)</string>
<string name="whats_new_title">What\'s new</string>
<string name="donate_title">Donate</string>
<string name="anti_features_title">This app has anti-features</string>
<string name="developer_contact">Developer contact</string>
<string name="copy_link">Copy link</string>
<string name="app_no_compatible_versions">Can not update this app, because no compatible versions available in repository.</string>
<string name="app_no_auto_update">Auto-update not available, because app targets old version of Android.</string>
<string name="added_x_ago">Added %1$s</string>
<string name="size_colon">Size: %1$s</string>
<string name="signer_colon">Signer: %1$s</string>
<string name="architectures_colon">Architectures: %1$s</string>
</resources>