Skip to content

Commit

Permalink
Merge pull request #54 from IamRezaMousavi/add-locale
Browse files Browse the repository at this point in the history
add en locale
  • Loading branch information
IamRezaMousavi authored Nov 21, 2024
2 parents 24a63c8 + 3b6d251 commit f4861eb
Show file tree
Hide file tree
Showing 14 changed files with 481 additions and 102 deletions.
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package com.github.iamrezamousavi.mafia

import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import com.github.iamrezamousavi.mafia.data.local.PREF_APP_LANGUAGE
import com.github.iamrezamousavi.mafia.data.local.preferences
import com.github.iamrezamousavi.mafia.databinding.ActivityMainBinding
import com.github.iamrezamousavi.mafia.utils.getContextWrapper

class MainActivity : AppCompatActivity() {
class MainActivity :
AppCompatActivity(),
SharedPreferences.OnSharedPreferenceChangeListener {
private lateinit var binding: ActivityMainBinding

private val mainViewModel: MainViewModel by viewModels()

private lateinit var navHostFragment: NavHostFragment
private lateinit var navController: NavController

override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(getContextWrapper(newBase))
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
Expand All @@ -23,5 +31,18 @@ class MainActivity : AppCompatActivity() {
navHostFragment =
supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
navController = navHostFragment.navController

preferences.registerOnSharedPreferenceChangeListener(this)
}

override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key == PREF_APP_LANGUAGE) {
recreate()
}
}

override fun onDestroy() {
super.onDestroy()
preferences.unregisterOnSharedPreferenceChangeListener(this)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.github.iamrezamousavi.mafia.data.local

import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import com.github.iamrezamousavi.mafia.data.model.Language
import com.github.iamrezamousavi.mafia.data.model.toLanguage

const val PREF_APP_LANGUAGE = "AppLanguage"

val Context.preferences: SharedPreferences
get() = getSharedPreferences("${packageName}_preferences", Context.MODE_PRIVATE)

fun SharedPreferences.saveLanguage(language: Language) = edit {
putString(PREF_APP_LANGUAGE, language.code)
}

fun SharedPreferences.getLanguage() = getString(PREF_APP_LANGUAGE, Language.FA.code).toLanguage()!!
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.github.iamrezamousavi.mafia.data.model

import java.util.Locale

enum class Language(
val code: String,
val nativeName: String
) {
FA("fa", "فارسی"),
EN("en", "English");

fun asSystemLocale() = Locale(code)
}

fun String?.toLanguage() = Language.entries.find { it.code == this }

fun String?.toNativeLanguage() = Language.entries.find { it.nativeName == this }
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.github.iamrezamousavi.mafia.utils

import android.os.Build
import androidx.annotation.ChecksSdkIntAtLeast

@get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
inline val isAtLeastAndroid13
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU

@get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N)
inline val isAtLeastAndroid7
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.github.iamrezamousavi.mafia.utils

import android.content.Context
import android.content.ContextWrapper
import com.github.iamrezamousavi.mafia.data.local.getLanguage
import com.github.iamrezamousavi.mafia.data.local.preferences
import java.util.Locale

@Suppress("DEPRECATION")
fun getContextWrapper(context: Context): ContextWrapper {
val resources = context.resources
val configuration = resources.configuration

val language = context.preferences.getLanguage()
val locale = Locale(language.code)
Locale.setDefault(locale)

val currentLocale =
if (isAtLeastAndroid7) {
configuration.locales.get(0)
} else {
configuration.locale
}

if (currentLocale.language == language.code) {
return ContextWrapper(context)
}

configuration.setLocale(locale)

if (isAtLeastAndroid7) {
context.createConfigurationContext(configuration)
}
resources.updateConfiguration(configuration, resources.displayMetrics)

return ContextWrapper(context)
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ class MainFragment : Fragment() {
}
}

binding.mainToolBar.setNavigationOnClickListener {
findNavController().navigate(R.id.action_mainFragment_to_settingsFragment)
}

binding.mainToolBar.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) {
R.id.menuItemSelectAll -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.github.iamrezamousavi.mafia.view

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import androidx.fragment.app.Fragment
import com.github.iamrezamousavi.mafia.data.local.getLanguage
import com.github.iamrezamousavi.mafia.data.local.preferences
import com.github.iamrezamousavi.mafia.data.local.saveLanguage
import com.github.iamrezamousavi.mafia.data.model.Language
import com.github.iamrezamousavi.mafia.data.model.toNativeLanguage
import com.github.iamrezamousavi.mafia.databinding.FragmentSettingsBinding

class SettingsFragment : Fragment() {

private lateinit var binding: FragmentSettingsBinding

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentSettingsBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupLanguageSpinner()
}

private fun setupLanguageSpinner() {
val currentLanguage = requireContext().preferences.getLanguage()
val items = Language
.entries
.map { it.nativeName }
.sorted()
.let { languages ->
listOf(currentLanguage.nativeName) +
languages.filter { it != currentLanguage.nativeName }
}
val arrayAdapter = ArrayAdapter(
requireContext(),
android.R.layout.simple_spinner_item,
items
).also { adapter ->
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
}

binding.langSpinner.apply {
adapter = arrayAdapter
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>,
view: View?,
position: Int,
id: Long
) {
val selectedItem = parent.getItemAtPosition(position).toString()
val newLanguage = selectedItem.toNativeLanguage()
val currentLang = requireContext().preferences.getLanguage()
if (newLanguage != currentLang) {
if (newLanguage != null) {
requireContext().preferences.saveLanguage(newLanguage)
setSelection(0)
}
}
}

@Suppress("EmptyFunctionBlock")
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
}
}
}
1 change: 0 additions & 1 deletion app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutDirection="rtl"
tools:context=".MainActivity">

<androidx.fragment.app.FragmentContainerView
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/fragment_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
android:id="@+id/playersList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layoutDirection="rtl"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toTopOf="@id/textField"
app:layout_constraintEnd_toEndOf="parent"
Expand Down
73 changes: 73 additions & 0 deletions app/src/main/res/layout/fragment_settings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.SettingsFragment">

<com.google.android.material.appbar.AppBarLayout
android:id="@+id/settingsAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">

<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/settingsToolBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:title="@string/settings"
app:titleCentered="true" />

</com.google.android.material.appbar.AppBarLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/settingsAppBar">

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:cardBackgroundColor="@color/md_theme_secondaryContainer"
app:cardCornerRadius="5dp">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="@string/language"
android:textColor="@color/md_theme_onSecondaryContainer"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Spinner
android:id="@+id/langSpinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
10 changes: 9 additions & 1 deletion app/src/main/res/navigation/nav_graph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
app:exitAnim="@anim/slide_to_previous"
app:popEnterAnim="@anim/slide_from_previous"
app:popExitAnim="@anim/slide_to_next" />
<action
android:id="@+id/action_mainFragment_to_settingsFragment"
app:destination="@id/settingsFragment" />
</fragment>
<fragment
android:id="@+id/roleFragment"
Expand Down Expand Up @@ -49,4 +52,9 @@
android:name="com.github.iamrezamousavi.mafia.view.NarratorFragment"
android:label="fragment_narrator"
tools:layout="@layout/fragment_narrator" />
</navigation>
<fragment
android:id="@+id/settingsFragment"
android:name="com.github.iamrezamousavi.mafia.view.SettingsFragment"
android:label="fragment_settings"
tools:layout="@layout/fragment_settings" />
</navigation>
Loading

0 comments on commit f4861eb

Please # to comment.