Merge branch 'language_chooser_native' into 'master'

Use native language chooser

See merge request pixeldroid/PixelDroid!507
This commit is contained in:
Matthieu 2022-11-25 21:10:22 +00:00
commit 3d4e32cf4b
10 changed files with 455 additions and 768 deletions

View File

@ -35,6 +35,8 @@ android {
versionCode 19 versionCode 19
versionName "1.0.beta" + versionCode versionName "1.0.beta" + versionCode
//TODO add resConfigs("en", "fr", "ja",...) ?
testInstrumentationRunner "org.pixeldroid.app.testUtility.TestRunner" testInstrumentationRunner "org.pixeldroid.app.testUtility.TestRunner"
testInstrumentationRunnerArguments clearPackageData: 'true' testInstrumentationRunnerArguments clearPackageData: 'true'
} }
@ -130,7 +132,7 @@ dependencies {
/** /**
* AndroidX dependencies: * AndroidX dependencies:
*/ */
implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'androidx.appcompat:appcompat:1.6.0-rc01'
implementation 'androidx.core:core-splashscreen:1.0.0' implementation 'androidx.core:core-splashscreen:1.0.0'
implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.preference:preference-ktx:1.2.0' implementation 'androidx.preference:preference-ktx:1.2.0'

View File

@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-feature <uses-feature
@ -25,7 +26,17 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:localeConfig="@xml/locales_config"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
<activity <activity
android:name=".posts.AlbumActivity" android:name=".posts.AlbumActivity"
android:exported="false" android:exported="false"

View File

@ -257,8 +257,9 @@ class LoginActivity : BaseThemedWithoutBarActivity() {
//Successful authorization //Successful authorization
pixelfedAPI = PixelfedAPI.createFromUrl(domain) pixelfedAPI = PixelfedAPI.createFromUrl(domain)
val nodeInfo: NodeInfo? = Gson().fromJson(preferences.getString("nodeInfo", null), NodeInfo::class.java) val gson = Gson()
val instance: Instance? = Gson().fromJson(preferences.getString("instance", null), Instance::class.java) val nodeInfo: NodeInfo? = gson.fromJson(preferences.getString("nodeInfo", null), NodeInfo::class.java)
val instance: Instance? = gson.fromJson(preferences.getString("instance", null), Instance::class.java)
lifecycleScope.launch { lifecycleScope.launch {
try { try {

View File

@ -9,6 +9,7 @@ import android.content.pm.PackageManager
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.MediaStore import android.provider.MediaStore
import android.util.DisplayMetrics import android.util.DisplayMetrics
@ -204,14 +205,19 @@ class CameraFragment : BaseFragment() {
// Update gallery thumbnail // Update gallery thumbnail
if (ContextCompat.checkSelfPermission( if (ContextCompat.checkSelfPermission(
requireContext(), requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) Manifest.permission.READ_MEDIA_IMAGES
else Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED ) == PackageManager.PERMISSION_GRANTED
) { ) {
updateGalleryThumbnail() updateGalleryThumbnail()
} }
else if (!filePermissionDialogLaunched) { else if (!filePermissionDialogLaunched) {
// Ask for external storage permission. // Ask for external storage permission.
updateGalleryThumbnailPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE) updateGalleryThumbnailPermissionLauncher.launch(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Manifest.permission.READ_MEDIA_IMAGES
} else Manifest.permission.READ_EXTERNAL_STORAGE
)
} }
cameraLifecycleOwner.resume() cameraLifecycleOwner.resume()
@ -273,14 +279,14 @@ class CameraFragment : BaseFragment() {
// Find the last picture // Find the last picture
val projection = arrayOf( val projection = arrayOf(
MediaStore.Images.ImageColumns._ID, MediaStore.Images.ImageColumns._ID,
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) MediaStore.Images.ImageColumns.DATE_TAKEN if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) MediaStore.Images.ImageColumns.DATE_TAKEN
else MediaStore.Images.ImageColumns.DATE_MODIFIED, else MediaStore.Images.ImageColumns.DATE_MODIFIED,
) )
val cursor = requireContext().contentResolver val cursor = requireContext().contentResolver
.query( .query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null,
null, null,
(if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) MediaStore.Images.ImageColumns.DATE_TAKEN (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) MediaStore.Images.ImageColumns.DATE_TAKEN
else MediaStore.Images.ImageColumns.DATE_MODIFIED) + " DESC" else MediaStore.Images.ImageColumns.DATE_MODIFIED) + " DESC"
) )
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {

View File

@ -1,10 +1,16 @@
package org.pixeldroid.app.settings package org.pixeldroid.app.settings
import android.app.Dialog
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.res.XmlResourceParser
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
@ -13,6 +19,7 @@ import org.pixeldroid.app.R
import org.pixeldroid.app.utils.BaseThemedWithBarActivity import org.pixeldroid.app.utils.BaseThemedWithBarActivity
import org.pixeldroid.app.utils.setThemeFromPreferences import org.pixeldroid.app.utils.setThemeFromPreferences
class SettingsActivity : BaseThemedWithBarActivity(), SharedPreferences.OnSharedPreferenceChangeListener { class SettingsActivity : BaseThemedWithBarActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
private var restartMainOnExit = false private var restartMainOnExit = false
@ -57,9 +64,6 @@ class SettingsActivity : BaseThemedWithBarActivity(), SharedPreferences.OnShared
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
when (key) { when (key) {
"language" -> {
recreateWithRestartStatus()
}
"theme" -> { "theme" -> {
setThemeFromPreferences(sharedPreferences, resources) setThemeFromPreferences(sharedPreferences, resources)
recreateWithRestartStatus() recreateWithRestartStatus()
@ -88,6 +92,8 @@ class SettingsActivity : BaseThemedWithBarActivity(), SharedPreferences.OnShared
var dialogFragment: DialogFragment? = null var dialogFragment: DialogFragment? = null
if (preference is ColorPreference) { if (preference is ColorPreference) {
dialogFragment = ColorPreferenceDialog((preference as ColorPreference?)!!) dialogFragment = ColorPreferenceDialog((preference as ColorPreference?)!!)
} else if(preference.key == "language"){
dialogFragment = LanguageSettingFragment()
} }
if (dialogFragment != null) { if (dialogFragment != null) {
dialogFragment.setTargetFragment(this, 0) dialogFragment.setTargetFragment(this, 0)
@ -100,12 +106,62 @@ class SettingsActivity : BaseThemedWithBarActivity(), SharedPreferences.OnShared
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey) setPreferencesFromResource(R.xml.root_preferences, rootKey)
findPreference<ListPreference>("language")?.let {
it.setSummaryProvider {
val locale = AppCompatDelegate.getApplicationLocales().get(0)
locale?.getDisplayName(locale) ?: getString(R.string.default_system)
}
}
//Hide Notification setting for Android versions where it doesn't work //Hide Notification setting for Android versions where it doesn't work
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
preferenceManager.findPreference<Preference>("notification") findPreference<Preference>("notification")
?.let { preferenceScreen.removePreference(it) } ?.let { preferenceScreen.removePreference(it) }
} }
} }
} }
} }
class LanguageSettingFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val list: MutableList<String> = mutableListOf()
resources.getXml(R.xml.locales_config).use {
var eventType = it.eventType
while (eventType != XmlResourceParser.END_DOCUMENT) {
when (eventType) {
XmlResourceParser.START_TAG -> {
if (it.name == "locale") {
list.add(it.getAttributeValue(0))
}
}
}
eventType = it.next()
}
}
val locales = AppCompatDelegate.getApplicationLocales()
val checkedItem: Int =
if(locales.isEmpty) 0
else {
// For some reason we get a bit inconsistent language tags. This normalises it for
// the currently used languages, but it might break in the future if we add some
val index = list.indexOf(locales.get(0)?.toLanguageTag()?.lowercase()?.replace('_', '-'))
// If found, we want to compensate for the first in the list being the default
if(index == -1) -1
else index + 1
}
return AlertDialog.Builder(requireContext()).apply {
setIcon(R.drawable.translate_black_24dp)
setTitle(R.string.language)
setSingleChoiceItems((mutableListOf(getString(R.string.default_system)) + list.map {
val appLocale = LocaleListCompat.forLanguageTags(it)
appLocale.get(0)!!.getDisplayName(appLocale.get(0)!!)
}).toTypedArray(), checkedItem) { dialog, which ->
val languageTag = if(which in 1..list.size) list[which - 1] else null
dialog.dismiss()
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(languageTag))
}
setNegativeButton(android.R.string.ok) { _, _ -> }
}.create()
}
}

View File

@ -1,15 +1,9 @@
package org.pixeldroid.app.utils package org.pixeldroid.app.utils
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import org.pixeldroid.app.utils.db.AppDatabase import org.pixeldroid.app.utils.db.AppDatabase
import org.pixeldroid.app.utils.di.PixelfedAPIHolder import org.pixeldroid.app.utils.di.PixelfedAPIHolder
import java.util.*
import javax.inject.Inject import javax.inject.Inject
open class BaseActivity : AppCompatActivity() { open class BaseActivity : AppCompatActivity() {
@ -24,40 +18,8 @@ open class BaseActivity : AppCompatActivity() {
(this.application as PixelDroidApplication).getAppComponent().inject(this) (this.application as PixelDroidApplication).getAppComponent().inject(this)
} }
override fun attachBaseContext(base: Context) {
super.attachBaseContext(updateBaseContextLocale(base))
}
override fun onSupportNavigateUp(): Boolean { override fun onSupportNavigateUp(): Boolean {
onBackPressed() onBackPressed()
return true return true
} }
private fun updateBaseContextLocale(context: Context): Context {
val language = PreferenceManager.getDefaultSharedPreferences(context).getString("language", "default") ?: "default"
if(language == "default"){
return context
}
val locale = Locale.forLanguageTag(language)
Locale.setDefault(locale)
return if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
updateResourcesLocale(context, locale)
} else updateResourcesLocaleLegacy(context, locale)
}
private fun updateResourcesLocale(context: Context, locale: Locale): Context =
context.createConfigurationContext(
Configuration(context.resources.configuration)
.apply { setLocale(locale) }
)
@Suppress("DEPRECATION")
private fun updateResourcesLocaleLegacy(context: Context, locale: Locale): Context {
val resources: Resources = context.resources
val configuration: Configuration = resources.configuration
configuration.locale = locale
resources.updateConfiguration(configuration, resources.displayMetrics)
return context
}
} }

View File

@ -10,61 +10,4 @@
<item>@string/light_theme</item> <item>@string/light_theme</item>
<item>@string/dark_theme</item> <item>@string/dark_theme</item>
</string-array> </string-array>
<string-array name="languages_entries">
<item>@string/default_system</item>
<item>العربية</item>
<item>বাংলা (বাংলাদেশ)</item>
<item>Català</item>
<item>Čeština</item>
<item>Deutsch</item>
<item>Español</item>
<item>Euskara</item>
<item>English</item>
<item>فارسی</item>
<item>Suomi</item>
<item>Français</item>
<item>Gaeilge</item>
<item>Magyar</item>
<item>bahasa Indonesia</item>
<item>Italiano</item>
<item>日本語</item>
<item>മലയാളം</item>
<item>Nederlands</item>
<item>Polski</item>
<item>Português (Brasil)</item>
<item>Русский</item>
<item>Svenska</item>
<item>Українська</item>
<item>中文(简体)</item>
</string-array>
<string-array name="languages_values">
<item>default</item>
<item>ar</item>
<item>bn-bd</item>
<item>ca</item>
<item>cs</item>
<item>de</item>
<item>es</item>
<item>eu</item>
<item>en</item>
<item>fa</item>
<item>fi</item>
<item>fr</item>
<item>gl</item>
<item>hu</item>
<item>id</item>
<item>it</item>
<item>ja</item>
<item>ml</item>
<item>nl</item>
<item>pl</item>
<item>pt-br</item>
<item>ru</item>
<item>sv</item>
<item>uk</item>
<item>zh-CN</item>
</string-array>
</resources> </resources>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="en"/>
<locale android:name="ar"/>
<locale android:name="bn-bd"/>
<locale android:name="ca"/>
<locale android:name="cs"/>
<locale android:name="de"/>
<locale android:name="es"/>
<locale android:name="eu"/>
<locale android:name="fa"/>
<locale android:name="fi"/>
<locale android:name="fr"/>
<locale android:name="gl"/>
<locale android:name="hu"/>
<locale android:name="id"/>
<locale android:name="it"/>
<locale android:name="ja"/>
<locale android:name="ml"/>
<locale android:name="nl"/>
<locale android:name="pl"/>
<locale android:name="pt-br"/>
<locale android:name="ru"/>
<locale android:name="sv"/>
<locale android:name="uk"/>
<locale android:name="zh-CN"/>
</locale-config>

View File

@ -19,12 +19,8 @@
</PreferenceCategory> </PreferenceCategory>
<ListPreference <ListPreference
app:defaultValue="default"
app:entries="@array/languages_entries"
app:entryValues="@array/languages_values"
app:key="language" app:key="language"
app:title="@string/language" app:title="@string/language"
app:useSimpleSummaryProvider="true"
app:icon="@drawable/translate_black_24dp" /> app:icon="@drawable/translate_black_24dp" />
<Preference android:title="@string/notifications_settings" <Preference android:title="@string/notifications_settings"
@ -40,8 +36,7 @@
<EditTextPreference android:title="@string/description_template" <EditTextPreference android:title="@string/description_template"
android:key="prefill_description" android:key="prefill_description"
android:summary="@string/description_template_summary" android:summary="@string/description_template_summary"
app:icon="@drawable/note" app:icon="@drawable/note" />
/>
<Preference android:title="@string/about" <Preference android:title="@string/about"
android:key="about" android:key="about"

File diff suppressed because it is too large Load Diff