Skip to content

Commit ede7e86

Browse files
authored
Merge pull request #100 from winstonsung/dev-100
Add in-app language picker for languages not listed in Android system's app language settings
2 parents 137c135 + ae077da commit ede7e86

File tree

8 files changed

+210
-1
lines changed

8 files changed

+210
-1
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@
6464
<activity
6565
android:name=".ui.AboutActivity"
6666
android:parentActivityName=".ui.MainActivity" />
67+
68+
<service
69+
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
70+
android:enabled="false"
71+
android:exported="false">
72+
<meta-data
73+
android:name="autoStoreLocales"
74+
android:value="true" />
75+
</service>
6776
</application>
6877

6978
</manifest>

app/src/main/java/app/opass/ccip/ui/DrawerMenuAdapter.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ class DrawerMenuAdapter(
112112
merged.addAll(features.map(FeatureItem.Companion::fromFeature))
113113
merged.addAll(arrayOf(
114114
DividerItem,
115+
MenuAction.LAUNCH_LANGUAGE_PREFERENCE_FRAGMENT,
115116
MenuAction.LAUNCH_ABOUT_SCREEN
116117
))
117118
return merged
@@ -120,12 +121,14 @@ class DrawerMenuAdapter(
120121
private fun getTitleByAction(action: MenuAction): String {
121122
return when (action) {
122123
MenuAction.SWITCH_EVENT -> context.resources.getString(R.string.switch_event)
124+
MenuAction.LAUNCH_LANGUAGE_PREFERENCE_FRAGMENT -> context.getString(R.string.switch_language)
123125
MenuAction.LAUNCH_ABOUT_SCREEN -> context.getString(R.string.about_app)
124126
}
125127
}
126128

127129
private fun getIconByAction(action: MenuAction): Int = when (action) {
128130
MenuAction.SWITCH_EVENT -> R.drawable.ic_swap_horiz_black_24dp
131+
MenuAction.LAUNCH_LANGUAGE_PREFERENCE_FRAGMENT -> R.drawable.ic_languages_black_24dp
129132
MenuAction.LAUNCH_ABOUT_SCREEN -> R.drawable.ic_info_black_24dp
130133
}
131134

@@ -192,6 +195,7 @@ object DividerItem
192195

193196
enum class MenuAction {
194197
SWITCH_EVENT,
198+
LAUNCH_LANGUAGE_PREFERENCE_FRAGMENT,
195199
LAUNCH_ABOUT_SCREEN
196200
}
197201

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package app.opass.ccip.ui
2+
3+
import android.app.Dialog
4+
import android.os.Bundle
5+
import android.view.LayoutInflater
6+
import android.view.View
7+
import android.view.ViewGroup
8+
import android.widget.TextView
9+
import androidx.appcompat.app.AppCompatDelegate
10+
import androidx.core.os.LocaleListCompat
11+
import androidx.fragment.app.DialogFragment
12+
import androidx.fragment.app.FragmentManager
13+
import androidx.recyclerview.widget.LinearLayoutManager
14+
import androidx.recyclerview.widget.RecyclerView
15+
import app.opass.ccip.R
16+
import com.google.android.material.dialog.MaterialAlertDialogBuilder
17+
18+
class LanguagePreferenceFragment : DialogFragment() {
19+
20+
companion object {
21+
private const val TAG = "LanguagePreferenceFragment"
22+
23+
fun show(fragmentManager: FragmentManager) {
24+
LanguagePreferenceFragment().show(fragmentManager, TAG)
25+
}
26+
}
27+
28+
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
29+
val recyclerView = RecyclerView(requireContext()).apply {
30+
layoutParams = RecyclerView.LayoutParams(
31+
RecyclerView.LayoutParams.MATCH_PARENT,
32+
RecyclerView.LayoutParams.MATCH_PARENT
33+
)
34+
layoutManager = LinearLayoutManager(requireContext())
35+
adapter = LanguagePreferenceAdapter(
36+
items = listOf(
37+
LanguageOptionItem(
38+
key = "en-US",
39+
localName = requireContext().getString(R.string.lang_local_name_en_us),
40+
translatedName = requireContext().getString(R.string.lang_translated_name_en_us)
41+
),
42+
LanguageOptionItem(
43+
key = "nan-Hant-TW",
44+
localName = requireContext().getString(R.string.lang_local_name_nan_hant_tw),
45+
translatedName = requireContext().getString(R.string.lang_translated_name_nan_hant_tw)
46+
),
47+
LanguageOptionItem(
48+
key = "nan-Latn-TW-pehoeji",
49+
localName = requireContext().getString(R.string.lang_local_name_nan_latn_tw_pehoeji),
50+
translatedName = requireContext().getString(R.string.lang_translated_name_nan_latn_tw_pehoeji)
51+
),
52+
LanguageOptionItem(
53+
key = "nan-Latn-TW-tailo",
54+
localName = requireContext().getString(R.string.lang_local_name_nan_latn_tw_tailo),
55+
translatedName = requireContext().getString(R.string.lang_translated_name_nan_latn_tw_tailo)
56+
),
57+
LanguageOptionItem(
58+
key = "hi-IN",
59+
localName = requireContext().getString(R.string.lang_local_name_hi_in),
60+
translatedName = requireContext().getString(R.string.lang_translated_name_hi_in)
61+
),
62+
LanguageOptionItem(
63+
key = "nb-NO",
64+
localName = requireContext().getString(R.string.lang_local_name_nb_no),
65+
translatedName = requireContext().getString(R.string.lang_translated_name_nb_no)
66+
),
67+
LanguageOptionItem(
68+
key = "ta-IN",
69+
localName = requireContext().getString(R.string.lang_local_name_ta_in),
70+
translatedName = requireContext().getString(R.string.lang_translated_name_ta_in)
71+
),
72+
LanguageOptionItem(
73+
key = "zh-Hant-TW",
74+
localName = requireContext().getString(R.string.lang_local_name_zh_hant_tw),
75+
translatedName = requireContext().getString(R.string.lang_translated_name_zh_hant_tw)
76+
)
77+
)
78+
) { item ->
79+
dialog?.dismiss()
80+
AppCompatDelegate.setApplicationLocales(
81+
LocaleListCompat.forLanguageTags(item.key)
82+
)
83+
}
84+
}
85+
86+
return MaterialAlertDialogBuilder(requireContext())
87+
.setTitle(R.string.choose_app_language)
88+
.setView(recyclerView)
89+
.create()
90+
}
91+
}
92+
93+
data class LanguageOptionItem(
94+
val key: String,
95+
val localName: String,
96+
val translatedName: String
97+
)
98+
99+
class LanguagePreferenceAdapter(
100+
private val items: List<LanguageOptionItem>,
101+
private val onItemClick: (LanguageOptionItem) -> Unit
102+
) : RecyclerView.Adapter<LanguagePreferenceViewHolder>() {
103+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LanguagePreferenceViewHolder =
104+
LayoutInflater.from(parent.context)
105+
.inflate(R.layout.item_option_language, parent, false)
106+
.let(::LanguagePreferenceViewHolder)
107+
.apply {
108+
itemView.setOnClickListener {
109+
val pos = getBindingAdapterPosition()
110+
if (pos != RecyclerView.NO_POSITION) onItemClick(items[pos])
111+
}
112+
}
113+
114+
override fun getItemCount() = items.size
115+
116+
override fun onBindViewHolder(holder: LanguagePreferenceViewHolder, position: Int) {
117+
val item = items[position]
118+
holder.localName.text = item.localName
119+
holder.translatedName.text = item.translatedName
120+
}
121+
}
122+
123+
class LanguagePreferenceViewHolder(view: View) : RecyclerView.ViewHolder(view) {
124+
val localName: TextView = view.findViewById(R.id.option_local_name)
125+
val translatedName: TextView = view.findViewById(R.id.option_translated_name)
126+
}

app/src/main/java/app/opass/ccip/ui/MainActivity.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
262262
this.startActivity(Intent(this, EventActivity::class.java))
263263
finish()
264264
}
265+
MenuAction.LAUNCH_LANGUAGE_PREFERENCE_FRAGMENT -> {
266+
LanguagePreferenceFragment.show(supportFragmentManager)
267+
mDrawerLayout.closeDrawers()
268+
return
269+
}
265270
MenuAction.LAUNCH_ABOUT_SCREEN -> {
266271
this.startActivity(Intent(this, AboutActivity::class.java))
267272
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="20.0"
5+
android:viewportHeight="20.0">
6+
<path
7+
android:fillColor="#FF000000"
8+
android:pathData="M20,18h-1.44a0.6,0.6 0,0 1,-0.4 -0.12,0.8 0.8,0 0,1 -0.23,-0.31L17,15h-5l-1,2.54a0.8,0.8 0,0 1,-0.22 0.3,0.6 0.6,0 0,1 -0.4,0.14L9,17.98l4.55,-11.47h1.89zM16.47,13.69L14.89,9.5a12,12 0,0 1,-0.39 -1.24q-0.09,0.37 -0.19,0.69l-0.19,0.56 -1.58,4.19zM10.17,12.11a13.4,13.4 0,0 1,-2.91 -1.41,11.46 11.46,0 0,0 2.81,-5.37L12,5.33L12,4L7.31,4a4,4 0,0 0,-0.2 -0.56C6.87,2.79 6.6,2 6.6,2l-1.47,0.5s0.4,0.89 0.6,1.5L0,4v1.33h2.15A11.23,11.23 0,0 0,5 10.7a17.2,17.2 0,0 1,-5 2.1q0.56,0.82 0.87,1.38a23.3,23.3 0,0 0,5.22 -2.51,15.6 15.6,0 0,0 3.56,1.77zM3.63,5.33h4.91a8.1,8.1 0,0 1,-2.45 4.45,9.1 9.1,0 0,1 -2.46,-4.45"/>
9+
</vector>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
android:layout_width="match_parent"
5+
android:layout_height="wrap_content"
6+
android:background="?attr/selectableItemBackground"
7+
android:focusable="true"
8+
android:orientation="vertical"
9+
android:paddingStart="32dp"
10+
android:paddingTop="16dp"
11+
android:paddingEnd="8dp"
12+
android:paddingBottom="16dp">
13+
14+
<TextView
15+
android:id="@+id/option_local_name"
16+
style="@style/TextAppearance.MaterialComponents.Body1"
17+
android:layout_width="wrap_content"
18+
android:layout_height="wrap_content"
19+
android:textColor="@color/textColorPrimary"
20+
tools:text="繁體中文" />
21+
22+
<TextView
23+
android:id="@+id/option_translated_name"
24+
android:layout_width="wrap_content"
25+
android:layout_height="wrap_content"
26+
android:layout_marginTop="4dp"
27+
tools:text="Mandarin - Traditional Han script" />
28+
</LinearLayout>

app/src/main/res/values-zh-rTW/strings.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,16 @@
9393
<string name="wifi_saved">已儲存 Wi-Fi 網路資訊</string>
9494
<string name="failed_to_save_wifi">無法儲存 Wi-Fi 網路資訊</string>
9595
<string name="failed_to_save_wifi_copied_to_clipboard">無法儲存 Wi-Fi 網路資訊。網路密碼已複製到剪貼簿。</string>
96+
<string name="switch_language">切換語言</string>
97+
<string name="choose_app_language">選擇應用程式語言</string>
98+
<string name="lang_translated_name_en_us">英語</string>
99+
<string name="lang_translated_name_nan_hant_tw">閩南語 - 傳統漢字</string>
100+
<string name="lang_translated_name_nan_latn_tw_pehoeji">閩南語 - 白話字</string>
101+
<string name="lang_translated_name_nan_latn_tw_tailo">閩南語 - 臺羅拼音</string>
102+
<string name="lang_translated_name_hi_in">印地語</string>
103+
<string name="lang_translated_name_nb_no">書面挪威語</string>
104+
<string name="lang_translated_name_ta_in">坦米爾語</string>
105+
<string name="lang_translated_name_zh_hant_tw">繁體中文</string>
96106
<string name="about_app">關於 &appname;</string>
97107
<string name="version">版本 %s</string>
98108
<string name="privacy_policy">隱私權政策</string>

app/src/main/res/values/strings.xml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
<string name="bookmark_channel_name">Session bookmark</string>
6262
<string name="notification_session_start">%1$s will start in 10 minutes at %2$s</string>
6363
<string name="invalid_token">Invalid QR code, invite link, or token</string>
64-
<string name="tap_here_to_scan">Tap here to scan the KKTIX QR Code ticket via the camera or gallery
64+
<string name="tap_here_to_scan">Tap here to scan the KKTIX QR code ticket via the camera or gallery
6565
</string>
6666
<string name="enter_token_button">I have a token</string>
6767
<string name="enter_your_token">Enter your token</string>
@@ -94,6 +94,24 @@
9494
<string name="wifi_saved">Wi-Fi network saved</string>
9595
<string name="failed_to_save_wifi">Failed to save Wi-Fi network</string>
9696
<string name="failed_to_save_wifi_copied_to_clipboard">Failed to save the Wi-Fi information. Password copied to clipboard.</string>
97+
<string name="switch_language">Switch language</string>
98+
<string name="choose_app_language">Choose app language</string>
99+
<string name="lang_local_name_en_us" translatable="false">English</string>
100+
<string name="lang_translated_name_en_us">English</string>
101+
<string name="lang_local_name_nan_hant_tw" translatable="false">閩南語 - 傳統漢字</string>
102+
<string name="lang_translated_name_nan_hant_tw">Hokkien - Traditional Han script</string>
103+
<string name="lang_local_name_nan_latn_tw_pehoeji" translatable="false">Bân-lâm-gú - Pe̍h-ōe-jī</string>
104+
<string name="lang_translated_name_nan_latn_tw_pehoeji">Hokkien - Pe̍h-ōe-jī</string>
105+
<string name="lang_local_name_nan_latn_tw_tailo" translatable="false">Bân-lâm-gú - Tâi-lô</string>
106+
<string name="lang_translated_name_nan_latn_tw_tailo">Hokkien - Tâi-lô</string>
107+
<string name="lang_local_name_hi_in" translatable="false">हिन्दी</string>
108+
<string name="lang_translated_name_hi_in">Hindi</string>
109+
<string name="lang_local_name_nb_no" translatable="false">norsk bokmål</string>
110+
<string name="lang_translated_name_nb_no">Norwegian Bokmål</string>
111+
<string name="lang_local_name_ta_in" translatable="false">தமிழ்</string>
112+
<string name="lang_translated_name_ta_in">Tamil</string>
113+
<string name="lang_local_name_zh_hant_tw" translatable="false">繁體中文</string>
114+
<string name="lang_translated_name_zh_hant_tw">Mandarin - Traditional Han script</string>
97115
<string name="about_app">About &appname;</string>
98116
<string name="version">Version %s</string>
99117
<string name="privacy_policy">Privacy Policy</string>

0 commit comments

Comments
 (0)