Add in-app language setting

This commit is contained in:
Matthieu 2020-12-11 16:53:12 +01:00
parent 271b9f310d
commit 689dffe7c1
35 changed files with 175 additions and 56 deletions

View File

@ -24,6 +24,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:replace="android:allowBackup">
<activity android:name=".BaseActivity"></activity>
<activity android:name=".CameraActivity" />
<activity
android:name=".ReportActivity"

View File

@ -5,7 +5,7 @@ import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_about.*
class AboutActivity : AppCompatActivity() {
class AboutActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_about)

View File

@ -0,0 +1,46 @@
package com.h.pixeldroid
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.os.Build
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import java.util.*
open class BaseActivity : AppCompatActivity() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(updateBaseContextLocale(base))
}
private fun updateBaseContextLocale(context: Context): Context {
val language = PreferenceManager.getDefaultSharedPreferences(context).getString("language", "").orEmpty()
if(language.isEmpty()){
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) }
)
@SuppressWarnings("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

@ -11,7 +11,7 @@ import com.h.pixeldroid.objects.Account.Companion.FOLLOWERS_TAG
import javax.inject.Inject
class FollowsActivity : AppCompatActivity() {
class FollowsActivity : BaseActivity() {
private var followsFragment = AccountListFragment()
@Inject
lateinit var db: AppDatabase

View File

@ -5,7 +5,7 @@ import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_licenses.*
class LicenseActivity : AppCompatActivity() {
class LicenseActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_licenses)

View File

@ -48,7 +48,7 @@ since they do not depend on each other)
*/
class LoginActivity : AppCompatActivity() {
class LoginActivity : BaseActivity() {
companion object {
private const val PACKAGE_ID = BuildConfig.APPLICATION_ID

View File

@ -45,7 +45,7 @@ import retrofit2.Response
import java.lang.IllegalArgumentException
import javax.inject.Inject
class MainActivity : AppCompatActivity() {
class MainActivity : BaseActivity() {
@Inject
lateinit var db: AppDatabase

View File

@ -59,7 +59,7 @@ private const val REQUEST_CODE_PERMISSIONS_SEND_PHOTO = 7
private val REQUIRED_PERMISSIONS = arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
class PhotoEditActivity : AppCompatActivity(), FilterListFragmentListener, EditImageFragmentListener {
class PhotoEditActivity : BaseActivity(), FilterListFragmentListener, EditImageFragmentListener {
internal var saving: Boolean = false
private val BITMAP_CONFIG = Bitmap.Config.ARGB_8888

View File

@ -20,7 +20,7 @@ import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
class PostActivity : AppCompatActivity() {
class PostActivity : BaseActivity() {
private lateinit var postFragment : PostFragment
lateinit var domain : String
private lateinit var accessToken : String

View File

@ -41,7 +41,7 @@ private val TAG = "Post Creation Activity"
private val MORE_PICTURES_REQUEST_CODE = 0xffff
class PostCreationActivity : AppCompatActivity(), PostCreationListener {
class PostCreationActivity : BaseActivity(), PostCreationListener {
private lateinit var recycler : RecyclerView
private lateinit var adapter : PostCreationAdapter

View File

@ -29,7 +29,7 @@ import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
class ProfileActivity : AppCompatActivity() {
class ProfileActivity : BaseActivity() {
private lateinit var pixelfedAPI : PixelfedAPI
private lateinit var adapter : ProfilePostsRecyclerViewAdapter
private lateinit var recycler : RecyclerView

View File

@ -14,7 +14,7 @@ import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
class ReportActivity : AppCompatActivity() {
class ReportActivity : BaseActivity() {
@Inject
lateinit var db: AppDatabase

View File

@ -15,7 +15,7 @@ import com.h.pixeldroid.fragments.feeds.uncachedFeeds.search.SearchHashtagFragme
import com.h.pixeldroid.fragments.feeds.uncachedFeeds.search.SearchPostsFragment
import com.h.pixeldroid.objects.Results
class SearchActivity : AppCompatActivity() {
class SearchActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View File

@ -3,14 +3,12 @@ package com.h.pixeldroid
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.h.pixeldroid.utils.ThemeUtils.Companion.setThemeFromPreferences
class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
private var restartActivitiesOnExit = false
class SettingsActivity : BaseActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
private var restartMainOnExit = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -21,11 +19,8 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
.replace(R.id.settings, SettingsFragment())
.commit()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
private fun restartCurrentActivity() {
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
super.startActivity(intent)
restartMainOnExit = intent.getBooleanExtra("restartMain", false)
}
override fun onResume() {
@ -42,16 +37,43 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
)
}
override fun onBackPressed() {
// If a setting (for example language or theme) was changed, the main activity should be
// started without history so that the change is applied to the whole back stack
if (restartMainOnExit) {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
super.startActivity(intent)
} else {
super.onBackPressed()
}
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
when (key) {
"theme" -> setThemeFromPreferences(sharedPreferences, resources)
"theme" -> {
setThemeFromPreferences(sharedPreferences, resources)
recreateWithRestartStatus()
}
"language" -> {
recreateWithRestartStatus()
}
}
restartActivitiesOnExit = true
restartCurrentActivity()
}
class SettingsFragment : PreferenceFragmentCompat() {
/**
* Mark main activity to be changed and recreate the current one
*/
private fun recreateWithRestartStatus() {
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
val savedInstanceState = Bundle().apply {
putBoolean("restartMain", true)
}
intent.putExtras(savedInstanceState)
super.startActivity(intent)
finish()
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}

View File

@ -23,10 +23,7 @@ interface ApplicationComponent {
fun inject(activity: ProfileActivity?)
fun inject(mainActivity: MainActivity?)
fun inject(activity: ReportActivity?)
fun inject(fragment: PostFragment)
fun inject(fragment: SearchDiscoverFragment)
fun inject(fragment: NotificationsFragment)
fun inject(feedFragment: BaseFragment)
fun inject(followsActivity: FollowsActivity)

View File

@ -43,7 +43,7 @@ import javax.inject.Inject
* This fragment lets you search and use Pixelfed's Discover feature
*/
class SearchDiscoverFragment : Fragment() {
class SearchDiscoverFragment : BaseFragment() {
private lateinit var api: PixelfedAPI
private lateinit var recycler : RecyclerView
private lateinit var adapter : DiscoverRecyclerViewAdapter
@ -51,14 +51,6 @@ class SearchDiscoverFragment : Fragment() {
private lateinit var discoverProgressBar: ProgressBar
private lateinit var discoverRefreshLayout: SwipeRefreshLayout
@Inject
lateinit var db: AppDatabase
@Inject
lateinit var apiHolder: PixelfedAPIHolder
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@ -66,9 +58,6 @@ class SearchDiscoverFragment : Fragment() {
val view = inflater.inflate(R.layout.fragment_search, container, false)
val search = view.findViewById<SearchView>(R.id.search)
(requireActivity().application as Pixeldroid).getAppComponent().inject(this)
//Configure the search widget (see https://developer.android.com/guide/topics/search/search-dialog#ConfiguringWidget)
val searchManager = requireActivity().getSystemService(Context.SEARCH_SERVICE) as SearchManager
search.setSearchableInfo(searchManager.getSearchableInfo(requireActivity().componentName))

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12.87,15.07l-2.54,-2.51 0.03,-0.03c1.74,-1.94 2.98,-4.17 3.71,-6.53L17,6L17,4h-7L10,2L8,2v2L1,4v1.99h11.17C11.5,7.92 10.44,9.75 9,11.35 8.07,10.32 7.3,9.19 6.69,8h-2c0.73,1.63 1.73,3.17 2.98,4.56l-5.09,5.02L4,19l5,-5 3.11,3.11 0.76,-2.04zM18.5,10h-2L12,22h2l1.12,-3h4.75L21,22h2l-4.5,-12zM15.88,17l1.62,-4.33L19.12,17h-3.24z"
android:fillColor="@color/colorDrawing"/>
</vector>

View File

@ -47,7 +47,7 @@
<string name="dark_theme">داكن</string>
<string name="light_theme">فاتح</string>
<string name="save_image_success">تم حفظ الصورة بنجاح</string>
<string name="default_theme">افتراضي (يتبع النظام)</string>
<string name="default_system">افتراضي (يتبع النظام)</string>
<string name="description_max_characters">يجب أن يحتوي الوصف على %1$s حرفًا على الأكثر.</string>
<string name="upload_post_success">تم تحميل المنشور بنجاح</string>
<string name="upload_post_failed">فشل في تحميل المنشور</string>

View File

@ -93,7 +93,7 @@
<string name="permission_denied">Permís denegat</string>
<string name="dark_theme">Fosc</string>
<string name="light_theme">Clar</string>
<string name="default_theme">Per defecte (seguint el sistema)</string>
<string name="default_system">Per defecte (seguint el sistema)</string>
<string name="media_upload_completed">{gmd_cloud_done} S\'ha completat l\'enviament multimèdia</string>
<string name="media_upload_failed">{gmd_cloud_off} L\'enviament multimèdia ha fallat, torna-ho a provar o comprova les condicions de la xarxa</string>
<string name="posting_image_accessibility_hint">Imatge que s\'està publicant</string>

View File

@ -41,7 +41,7 @@
<string name="registration_failed">Konnte die App nicht mit diesem Server verbinden</string>
<string name="instance_error">Konnte die Informationen der Instanz nicht abrufen</string>
<string name="upload_picture_failed">Fehler beim Hochladen!</string>
<string name="default_theme">Standard (Systemeinstellung)</string>
<string name="default_system">Standard (Systemeinstellung)</string>
<string name="permission_denied">Berechtigung verweigert</string>
<string name="save_image_failed">Bild kann nicht gespeichert werden</string>
<string name="description_max_characters">Die Beschreibung darf höchstens %1$s Zeichen enthalten.</string>

View File

@ -97,7 +97,7 @@
<string name="permission_denied">Permiso denegado</string>
<string name="dark_theme">Oscuro</string>
<string name="light_theme">Claro</string>
<string name="default_theme">Por defecto (Sistema)</string>
<string name="default_system">Por defecto (Sistema)</string>
<string name="crop_result_error">No se pudo recuperar la imagen después del recorte</string>
<string name="busy_dialog_ok_button">Bien, espera.</string>
<string name="busy_dialog_text">Procesando imagen, ¡Espera a que termine!</string>

View File

@ -59,7 +59,7 @@
<string name="save_image_failed">Ezinezkoa irudia gordetzea</string>
<string name="dark_theme">Iluna</string>
<string name="light_theme">Argia</string>
<string name="default_theme">Lehenetsia (Sistemaren lehentsia)</string>
<string name="default_system">Lehenetsia (Sistemaren lehentsia)</string>
<string name="no_description">Deskribapenik ez</string>
<string name="description_max_characters">Deskribapenak %1$s karaktere izan behar ditu gehienez.</string>
<string name="save_image_success">Irudia behar bezala gorde da</string>

View File

@ -45,7 +45,7 @@
<string name="permission_denied">ممنوعیت دسترسی</string>
<string name="save_image_failed">نتوانستیم تصویر را ذخیره کنیم</string>
<string name="description_max_characters">توضیحات حداکثر می‌توانند تا %1$s حرف داشته باشند.</string>
<string name="default_theme">پیش‌گزیده (پیروی از سامانه)</string>
<string name="default_system">پیش‌گزیده (پیروی از سامانه)</string>
<string name="light_theme">روشن</string>
<string name="dark_theme">تاریک</string>
<string name="upload_post_error">بارگذاری مطلب ناموفق بود</string>

View File

@ -51,7 +51,7 @@
<string name="permission_denied">Permission refusée</string>
<string name="dark_theme">Sombre</string>
<string name="light_theme">Clair</string>
<string name="default_theme">Par défaut (selon votre système)</string>
<string name="default_system">Par défaut (selon votre système)</string>
<string name="upload_post_failed">Échec du téléversement de la publication</string>
<string name="upload_post_success">Téléversement de la publication avec succès</string>
<string name="posted_on">Publié le %1$s</string>

View File

@ -93,7 +93,7 @@
<string name="permission_denied">Permiso denegado</string>
<string name="dark_theme">Escuro</string>
<string name="light_theme">Claro</string>
<string name="default_theme">Por omisión (do sistema)</string>
<string name="default_system">Por omisión (do sistema)</string>
<string name="media_upload_failed">{gmd_cloud_off} Fallou a subida do ficheiro, inténtao outra vez e comproba a conexión</string>
<string name="posting_image_accessibility_hint">Imaxe que se publicou</string>
<string name="media_upload_completed">{gmd_cloud_done} Subida do ficheiro completada</string>

View File

@ -97,7 +97,7 @@
<string name="media_upload_failed">{gmd_cloud_off} Caricamento dei contenuti non riuscito, riprovare o verificare le condizioni della rete</string>
<string name="follow_button_failed">Impossibile visualizzare il tasto segui</string>
<string name="follow_status_failed">Impossibile ottenere lo stato segui</string>
<string name="default_theme">Predefinito (Segue il sistema)</string>
<string name="default_system">Predefinito (Segue il sistema)</string>
<string name="crop_result_error">Impossibile recuperare l\'immagine dopo il ritaglio</string>
<string name="busy_dialog_ok_button">Ok, aspetta.</string>
<string name="busy_dialog_text">Elaborando ancora l\'immagine, attendi che finisca prima!</string>

View File

@ -97,7 +97,7 @@
<string name="permission_denied">権限がありません</string>
<string name="dark_theme">ダーク</string>
<string name="light_theme">ライト</string>
<string name="default_theme">デフォルト(システム設定)</string>
<string name="default_system">デフォルト(システム設定)</string>
<string name="busy_dialog_ok_button">お待ちください。</string>
<string name="busy_dialog_text">画像を処理しています。しばらくお待ちください。</string>
<string name="nothing_to_see_here">ここには何もありません!</string>

View File

@ -74,7 +74,7 @@
<string name="upload_post_failed">Kon post niet uploaden</string>
<string name="save_image_failed">Kon afbeelding niet opslaan</string>
<string name="permission_denied">Toestemming geweigerd</string>
<string name="default_theme">Standaard (systeem instelling)</string>
<string name="default_system">Standaard (systeem instelling)</string>
<string name="instance_error">Kon instance-informatie niet ophalen</string>
<string name="likes">%1$s Vind-ik-leuks</string>
<string name="request_format_error">Fout bij het uploaden: slecht verzoekformaat</string>

View File

@ -58,7 +58,7 @@
<string name="registration_failed">Nie udało się zarejestrować aplikacji na tym serwerze</string>
<string name="instance_error">Nie udało się pobrać informacji o instancji</string>
<string name="instance_not_pixelfed_warning">To chyba nie jest instancja Pixelfed. Aplikacja może zachowywać się nieprzewidywalnie.</string>
<string name="default_theme">Systemowy</string>
<string name="default_system">Systemowy</string>
<string name="followed_notification">%1$s obserwujących</string>
<string name="liked_notification">%1$s polubień</string>
<string name="whats_an_instance">Co to jest instancja\?</string>

View File

@ -74,7 +74,7 @@
<string name="permission_denied">Недостаточно прав</string>
<string name="dark_theme">Тёмная</string>
<string name="light_theme">Светлая</string>
<string name="default_theme">По умолчанию (как в системе)</string>
<string name="default_system">По умолчанию (как в системе)</string>
<string name="follow_status_failed">Не удалось получить статус подписки</string>
<string name="follow_error">Не удалось подписаться</string>
<string name="action_not_allowed">Это действие запрещено</string>

View File

@ -97,7 +97,7 @@
<string name="permission_denied">Åtkomst nekas</string>
<string name="dark_theme">Mörkt</string>
<string name="light_theme">Ljust</string>
<string name="default_theme">Standard (Följer systemet)</string>
<string name="default_system">Standard (Följer systemet)</string>
<string name="nothing_to_see_here">Det finns inget här!</string>
<string name="crop_result_error">Kunde inte hämta bilden efter beskärning</string>
<string name="busy_dialog_ok_button">OK, vänta på det.</string>

View File

@ -95,7 +95,7 @@
<string name="save_image_success">图片成功保存</string>
<string name="save_image_failed">无法保存图像</string>
<string name="permission_denied">没有权限</string>
<string name="default_theme">默认(跟随系统设置)</string>
<string name="default_system">默认(跟随系统设置)</string>
<string name="light_theme">浅色</string>
<string name="dark_theme">深色</string>
<string name="nothing_to_see_here">这里什么也没有!</string>

View File

@ -6,8 +6,53 @@
</string-array>
<string-array name="theme_entries">
<item>@string/default_theme</item>
<item>@string/default_system</item>
<item>@string/light_theme</item>
<item>@string/dark_theme</item>
</string-array>
<string-array name="languages_entries">
<item>@string/default_system</item>
<item>العربية</item>
<item>বাংলা (বাংলাদেশ)</item>
<item>Català</item>
<item>Deutsch</item>
<item>Esperanto</item>
<item>Euskara</item>
<item>فارسی</item>
<item>Français</item>
<item>Gaeilge</item>
<item>Italiano</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>de</item>
<item>es</item>
<item>eu</item>
<item>fa</item>
<item>fr</item>
<item>gl</item>
<item>it</item>
<item>ja</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>

View File

@ -16,7 +16,7 @@
<!-- Theme Preferences -->
<string name="theme_title">Application Theme</string>
<string name="theme_header">Theme</string>
<string name="default_theme">Default (Follows system)</string>
<string name="default_system">Default (Follows system)</string>
<string name="light_theme">Light</string>
<string name="dark_theme">Dark</string>
<string name="followed_notification">%1$s followed you</string>
@ -143,6 +143,7 @@
<string name="OK">OK</string>
<string name="delete_dialog">Delete this post?</string>
<string name="cancel">Cancel</string>
<string name="language">Language</string>
</resources>

View File

@ -18,4 +18,13 @@
android:targetPackage="com.h.pixeldroid"
android:targetClass="com.h.pixeldroid.AboutActivity"/>
</Preference>
<ListPreference
app:defaultValue="default"
app:entries="@array/languages_entries"
app:entryValues="@array/languages_values"
app:key="language"
app:title="@string/language"
app:useSimpleSummaryProvider="true"
app:icon="@drawable/translate_black_24dp" />
</PreferenceScreen>