From 4eb33d7e4aa329615d800fc1b53c845a4fa949c6 Mon Sep 17 00:00:00 2001 From: Verlintas Date: Thu, 12 Nov 2026 16:38:42 +0800 Subject: [PATCH 1/4] Use Locale.ROOT for country-code uppercasing in flag emoji --- .../kotlin/com/ounben/amaradio/utils/EmojiUtils.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/com/ounben/amaradio/utils/EmojiUtils.kt b/app/src/main/kotlin/com/ounben/amaradio/utils/EmojiUtils.kt index f172e514..cb7bdded 100644 --- a/app/src/main/kotlin/com/ounben/amaradio/utils/EmojiUtils.kt +++ b/app/src/main/kotlin/com/ounben/amaradio/utils/EmojiUtils.kt @@ -1,5 +1,7 @@ package com.ounben.amaradio.utils +import java.util.Locale + object EmojiUtils { /** * Converts a 2-letter country code to a flag emoji. @@ -7,9 +9,11 @@ object EmojiUtils { */ fun getFlagEmoji(countryCode: String?): String? { if (countryCode == null || countryCode.length != 2) return null - - val firstChar = Character.codePointAt(countryCode.uppercase(), 0) - 0x41 + 0x1F1E6 - val secondChar = Character.codePointAt(countryCode.uppercase(), 1) - 0x41 + 0x1F1E6 + // Country codes are ASCII identifiers: never let the device locale turn 'i' into 'İ'. + val code = countryCode.uppercase(Locale.ROOT) + + val firstChar = Character.codePointAt(code, 0) - 0x41 + 0x1F1E6 + val secondChar = Character.codePointAt(code, 1) - 0x41 + 0x1F1E6 return String(Character.toChars(firstChar)) + String(Character.toChars(secondChar)) } From 04b19a9d71624bb6960f98e8c7ac4863c0b0f3d4 Mon Sep 17 00:00:00 2001 From: Verlintas Date: Thu, 12 Nov 2026 16:38:50 +0800 Subject: [PATCH 2/4] Use Locale.ROOT for country codes --- app/src/main/kotlin/com/ounben/amaradio/ui/TabsScreen.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/ounben/amaradio/ui/TabsScreen.kt b/app/src/main/kotlin/com/ounben/amaradio/ui/TabsScreen.kt index 7828a0ea..34a00c5f 100644 --- a/app/src/main/kotlin/com/ounben/amaradio/ui/TabsScreen.kt +++ b/app/src/main/kotlin/com/ounben/amaradio/ui/TabsScreen.kt @@ -26,6 +26,7 @@ import com.ounben.amaradio.R import com.ounben.amaradio.Utils import com.ounben.amaradio.station.DataRadioStation import kotlinx.coroutines.launch +import java.util.Locale private sealed class MainTab { object Local : MainTab() @@ -122,8 +123,8 @@ fun TabsScreen( val title = when (tab) { is MainTab.Local -> { if (manualCountry.isNotEmpty() && manualCountry != "SYSTEM") { - val flag = com.ounben.amaradio.utils.EmojiUtils.getFlagEmoji(manualCountry.uppercase()) ?: "" - if (flag.isNotEmpty()) "$flag ${manualCountry.uppercase()}" else manualCountry.uppercase() + val flag = com.ounben.amaradio.utils.EmojiUtils.getFlagEmoji(manualCountry.uppercase(Locale.ROOT)) ?: "" + if (flag.isNotEmpty()) "$flag ${manualCountry.uppercase(Locale.ROOT)}" else manualCountry.uppercase(Locale.ROOT) } else { stringResource(R.string.action_local) } From 9cac9024f0954192ba17a03c8bc3a0b981883933 Mon Sep 17 00:00:00 2001 From: Verlintas Date: Thu, 12 Nov 2026 16:38:57 +0800 Subject: [PATCH 3/4] Use Locale.ROOT for station country codes --- app/src/main/kotlin/com/ounben/amaradio/ui/SettingsScreen.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/ounben/amaradio/ui/SettingsScreen.kt b/app/src/main/kotlin/com/ounben/amaradio/ui/SettingsScreen.kt index e599a3db..10514feb 100644 --- a/app/src/main/kotlin/com/ounben/amaradio/ui/SettingsScreen.kt +++ b/app/src/main/kotlin/com/ounben/amaradio/ui/SettingsScreen.kt @@ -34,6 +34,7 @@ import com.ounben.amaradio.AMARadioApp import com.ounben.amaradio.R import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json +import java.util.Locale @Serializable private data class CountryJson( @@ -254,7 +255,7 @@ fun SettingsScreen( val json = Json { ignoreUnknownKeys = true } val countries = json.decodeFromString>(jsonContent) val categories = countries.mapNotNull { item -> - val code = item.code?.uppercase() ?: return@mapNotNull null + val code = item.code?.uppercase(Locale.ROOT) ?: return@mapNotNull null val rawName = item.name ?: code val label = com.ounben.amaradio.CountryCodeDictionary.instance.getCountryByCode(code) ?: rawName val emoji = com.ounben.amaradio.utils.EmojiUtils.getFlagEmoji(code) ?: "" From 01c62612c99a738d22d77282d8fddb9164303d62 Mon Sep 17 00:00:00 2001 From: Verlintas Date: Thu, 12 Nov 2026 16:39:05 +0800 Subject: [PATCH 4/4] Use Locale.ROOT for recording format labels --- .../kotlin/com/ounben/amaradio/recorder/RecordingsTab.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/com/ounben/amaradio/recorder/RecordingsTab.kt b/app/src/main/kotlin/com/ounben/amaradio/recorder/RecordingsTab.kt index 27771ae6..efc6bab5 100644 --- a/app/src/main/kotlin/com/ounben/amaradio/recorder/RecordingsTab.kt +++ b/app/src/main/kotlin/com/ounben/amaradio/recorder/RecordingsTab.kt @@ -419,7 +419,7 @@ fun RecordingListItem( color = MaterialTheme.colorScheme.onSurface ) Text( - text = "$dateStr • $durationStr • $sizeStr (${record.format.uppercase()})", + text = "$dateStr • $durationStr • $sizeStr (${record.format.uppercase(Locale.ROOT)})", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurface, maxLines = 1 @@ -510,7 +510,7 @@ fun RecordingOptionsDialog( overflow = TextOverflow.Ellipsis ) Text( - text = "$dateStr • $durationStr • $sizeStr (${record.format.uppercase()})", + text = "$dateStr • $durationStr • $sizeStr (${record.format.uppercase(Locale.ROOT)})", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -639,7 +639,7 @@ private fun shareRecordingFile(context: Context, record: RecordEntity) { type = "audio/*" putExtra(Intent.EXTRA_STREAM, uri) putExtra(Intent.EXTRA_SUBJECT, record.Name) - putExtra(Intent.EXTRA_TEXT, "${record.Name}\nRecording: ${record.format.uppercase()}") + putExtra(Intent.EXTRA_TEXT, "${record.Name}\nRecording: ${record.format.uppercase(Locale.ROOT)}") addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } val chooser = Intent.createChooser(shareIntent, context.getString(R.string.action_station_share))