Skip to content

Commit 47d8923

Browse files
committed
Add font size option
1 parent 5f6d1ba commit 47d8923

11 files changed

Lines changed: 241 additions & 4 deletions

File tree

‎app/src/main/java/com/mg4/control/ui/SettingsFragment.kt‎

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import com.mg4.control.util.FirmwareInfo
5151
import com.mg4.control.service.MG4ControlService
5252
import com.mg4.control.util.GarageMode
5353
import com.mg4.control.util.LocaleHelper
54+
import com.mg4.control.util.TextSize
5455
import kotlinx.coroutines.CoroutineScope
5556
import kotlinx.coroutines.Dispatchers
5657
import kotlinx.coroutines.launch
@@ -61,6 +62,13 @@ class SettingsFragment : Fragment() {
6162
private val githubUrl = "https://github.com/SliDeeN/MG4Control"
6263
private val gitlabUrl = "https://gitlab.com/SliDeeN/mg4control"
6364

65+
/** Index, dans le rail, de l'onglet ouvert — sauvegardé pour survivre à un recreate(). */
66+
private var selectedCategory = 0
67+
68+
private companion object {
69+
const val STATE_CATEGORY = "settings_category"
70+
}
71+
6472
override fun onCreateView(
6573
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
6674
): View = inflater.inflate(R.layout.fragment_settings, container, false)
@@ -165,6 +173,31 @@ class SettingsFragment : Fragment() {
165173
btnThemeDark.setOnClickListener { applyThemeMode("dark") }
166174
btnThemeLight.setOnClickListener { applyThemeMode("light") }
167175

176+
// ── Taille du texte : Standard / Grand / Très grand ─────────────────
177+
// Appliquée par LocaleHelper au contexte de l'activité : il faut la recréer pour que les
178+
// écrans se regonflent à la nouvelle échelle. Le sous-onglet ouvert est conservé (voir
179+
// bindCategoryRail), sinon chaque essai renverrait sur « Langues ».
180+
val textSizeBtns = listOf(
181+
TextSize.STANDARD to view.findViewById<MaterialButton>(R.id.btn_text_size_standard),
182+
TextSize.LARGE to view.findViewById(R.id.btn_text_size_large),
183+
TextSize.XLARGE to view.findViewById(R.id.btn_text_size_xlarge)
184+
)
185+
val currentTextSize = TextSize.get(requireContext())
186+
textSizeBtns.forEach { (size, btn) ->
187+
val active = size == currentTextSize
188+
btn.backgroundTintList = ColorStateList.valueOf(if (active) accentDim else inactiveColor)
189+
btn.setTextColor(if (active) textActive else textInactive)
190+
btn.strokeColor = ColorStateList.valueOf(
191+
if (active) accentColor else requireContext().getColor(R.color.dash_border)
192+
)
193+
btn.setOnClickListener {
194+
if (size == TextSize.get(requireContext())) return@setOnClickListener
195+
TextSize.set(requireContext(), size)
196+
AppLogger.i("MG4_SETTINGS", "Taille du texte → ${size.key} (×${size.scale})")
197+
requireActivity().recreate()
198+
}
199+
}
200+
168201
// ── Canal de mise a jour beta ────────────────────────────────────────
169202
// Aucun avertissement bloquant : une beta ne donne pas le controle du vehicule a un
170203
// tiers, contrairement a l'API externe. Le texte sous l'interrupteur suffit, et il
@@ -401,17 +434,26 @@ class SettingsFragment : Fragment() {
401434
// firmware sans extinction véhicule…), sinon le décompte serait faux.
402435
setupFirmwareChips(view)
403436
setupDataUsage(view)
404-
bindCategoryRail(view, accentDim, inactiveColor, accentColor, textActive, textInactive)
437+
bindCategoryRail(view, savedInstanceState, accentDim, inactiveColor, accentColor, textActive, textInactive)
438+
}
439+
440+
override fun onSaveInstanceState(outState: Bundle) {
441+
super.onSaveInstanceState(outState)
442+
outState.putInt(STATE_CATEGORY, selectedCategory)
405443
}
406444

407445
/**
408446
* Rail de gauche : une catégorie visible à la fois — même motif que l'éditeur de profil.
409447
*
410448
* Le bouton Diagnostic reste dans l'arbre même sur une page masquée : [MainActivity] peut donc
411449
* continuer à le révéler en direct après les 5 clics sur le logo, quel que soit l'onglet ouvert.
450+
*
451+
* L'onglet ouvert survit à un `recreate()` : langue, thème et taille du texte recréent
452+
* l'activité, et retomber à chaque fois sur le premier onglet obligeait à y retourner.
412453
*/
413454
private fun bindCategoryRail(
414-
view: View, accentDim: Int, inactive: Int, accent: Int, textOn: Int, textOff: Int
455+
view: View, savedInstanceState: Bundle?,
456+
accentDim: Int, inactive: Int, accent: Int, textOn: Int, textOff: Int
415457
) {
416458
val tabs = listOf(
417459
view.findViewById<MaterialButton>(R.id.btn_set_cat_lang) to view.findViewById<ViewGroup>(R.id.page_set_lang),
@@ -431,6 +473,7 @@ class SettingsFragment : Fragment() {
431473
if (usable.isEmpty()) return
432474

433475
fun select(target: ViewGroup) {
476+
selectedCategory = tabs.indexOfFirst { it.second === target }
434477
tabs.forEach { (btn, page) ->
435478
val on = page === target
436479
page.visibility = if (on) View.VISIBLE else View.GONE
@@ -442,7 +485,9 @@ class SettingsFragment : Fragment() {
442485
scroll?.scrollTo(0, 0) // changer d'onglet en gardant le scroll précédent désoriente
443486
}
444487
usable.forEach { (btn, page) -> btn.setOnClickListener { select(page) } }
445-
select(usable.first().second)
488+
// Un onglet mémorisé peut ne plus être disponible (page vidée entre-temps) : repli sur le premier.
489+
val restored = savedInstanceState?.getInt(STATE_CATEGORY, -1)?.let { tabs.getOrNull(it) }
490+
select((restored?.takeIf { it in usable } ?: usable.first()).second)
446491
}
447492

448493

‎app/src/main/java/com/mg4/control/util/LocaleHelper.kt‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.mg4.control.util
22

33
import android.content.Context
44
import android.content.res.Configuration
5+
import android.content.res.Resources
56
import java.util.Locale
67

78
object LocaleHelper {
@@ -28,13 +29,22 @@ object LocaleHelper {
2829
!context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
2930
.getBoolean(KEY_LANG_SET, false)
3031

31-
/** Applique la locale sauvegardée au contexte fourni et retourne le contexte modifié. */
32+
/**
33+
* Applique la locale ET la taille du texte sauvegardées au contexte fourni, et retourne le
34+
* contexte modifié.
35+
*
36+
* La taille du texte est posée ici parce que tous les contextes de l'app y passent déjà :
37+
* activité, application, et popups du service (dont le contexte ne reçoit rien d'autre).
38+
*/
3239
fun applyLocale(context: Context): Context {
3340
val lang = getLanguage(context)
3441
val locale = Locale(lang)
3542
Locale.setDefault(locale)
3643
val config = Configuration(context.resources.configuration)
3744
config.setLocale(locale)
45+
// Calculée depuis l'échelle SYSTÈME, pas depuis celle du contexte reçu : un contexte déjà
46+
// enveloppé l'aurait sinon appliquée deux fois (×1,25 × 1,25).
47+
config.fontScale = Resources.getSystem().configuration.fontScale * TextSize.get(context).scale
3848
return context.createConfigurationContext(config)
3949
}
4050
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.mg4.control.util
2+
3+
import android.content.Context
4+
5+
/**
6+
* Taille du texte de toute l'application — Réglages → Interface.
7+
*
8+
* Appliquée par l'échelle de police d'Android (`Configuration.fontScale`, posée dans
9+
* [LocaleHelper.applyLocale]) et non taille par taille : les ~700 tailles de l'app sont écrites en
10+
* dur dans les layouts, sans style commun. L'échelle couvre d'un coup les écrans, les boîtes de
11+
* dialogue et les popups du service, sans risque d'oubli ni de double application.
12+
*
13+
* Contrepartie : l'agrandissement est PROPORTIONNEL. Les coefficients sont calés sur 16 sp, la
14+
* taille la plus répandue, qui gagne exactement +2 puis +4 ; une étiquette de 10 sp gagne moins,
15+
* un titre de 22 sp davantage — ce qui garde la hiérarchie des textes.
16+
*/
17+
enum class TextSize(val key: String, val scale: Float) {
18+
STANDARD("standard", 1f),
19+
LARGE("large", 1.125f),
20+
XLARGE("xlarge", 1.25f);
21+
22+
companion object {
23+
private const val PREFS = "mg4_settings"
24+
private const val KEY = "text_size"
25+
26+
/** Taille correspondant à une clé enregistrée ; STANDARD si absente ou inconnue. */
27+
fun fromKey(key: String?): TextSize = entries.firstOrNull { it.key == key } ?: STANDARD
28+
29+
fun get(context: Context): TextSize = fromKey(
30+
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE).getString(KEY, null)
31+
)
32+
33+
fun set(context: Context, size: TextSize) {
34+
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE).edit()
35+
.putString(KEY, size.key)
36+
.apply()
37+
}
38+
}
39+
}

‎app/src/main/res/layout/fragment_settings.xml‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,91 @@
429429

430430
</LinearLayout>
431431

432+
</LinearLayout>
433+
434+
<!-- ── Section TAILLE DU TEXTE ──────────────────────────────────── -->
435+
<LinearLayout
436+
android:layout_width="match_parent"
437+
android:layout_height="wrap_content"
438+
android:orientation="vertical"
439+
android:background="@drawable/bg_card_rounded"
440+
android:layout_marginBottom="12dp">
441+
442+
<TextView
443+
android:layout_width="match_parent"
444+
android:layout_height="wrap_content"
445+
android:text="@string/settings_text_size"
446+
android:textColor="@color/dash_text_lo"
447+
android:textSize="13sp"
448+
android:textStyle="bold"
449+
android:letterSpacing="0.12"
450+
android:textAllCaps="true"
451+
android:paddingStart="16dp"
452+
android:paddingEnd="16dp"
453+
android:paddingTop="8dp"
454+
android:paddingBottom="7dp" />
455+
456+
<View
457+
android:layout_width="match_parent"
458+
android:layout_height="1dp"
459+
android:background="@color/dash_border" />
460+
461+
<LinearLayout
462+
android:layout_width="match_parent"
463+
android:layout_height="wrap_content"
464+
android:orientation="horizontal"
465+
android:padding="12dp">
466+
467+
<!-- Hauteur minimale plutôt que fixe : ces boutons portent justement le texte
468+
agrandi, ils ne doivent pas être les premiers à le couper. -->
469+
<com.google.android.material.button.MaterialButton
470+
android:id="@+id/btn_text_size_standard"
471+
android:layout_width="0dp"
472+
android:layout_height="wrap_content"
473+
android:minHeight="52dp"
474+
android:layout_weight="1"
475+
android:layout_marginEnd="4dp"
476+
android:text="@string/settings_text_size_standard"
477+
android:textColor="@color/text_secondary"
478+
android:textSize="16sp"
479+
app:backgroundTint="@color/dash_btn"
480+
app:strokeWidth="1dp"
481+
app:strokeColor="@color/dash_border"
482+
app:cornerRadius="8dp" />
483+
484+
<com.google.android.material.button.MaterialButton
485+
android:id="@+id/btn_text_size_large"
486+
android:layout_width="0dp"
487+
android:layout_height="wrap_content"
488+
android:minHeight="52dp"
489+
android:layout_weight="1"
490+
android:layout_marginStart="4dp"
491+
android:layout_marginEnd="4dp"
492+
android:text="@string/settings_text_size_large"
493+
android:textColor="@color/text_secondary"
494+
android:textSize="16sp"
495+
app:backgroundTint="@color/dash_btn"
496+
app:strokeWidth="1dp"
497+
app:strokeColor="@color/dash_border"
498+
app:cornerRadius="8dp" />
499+
500+
<com.google.android.material.button.MaterialButton
501+
android:id="@+id/btn_text_size_xlarge"
502+
android:layout_width="0dp"
503+
android:layout_height="wrap_content"
504+
android:minHeight="52dp"
505+
android:layout_weight="1"
506+
android:layout_marginStart="4dp"
507+
android:text="@string/settings_text_size_xlarge"
508+
android:textColor="@color/text_secondary"
509+
android:textSize="16sp"
510+
app:backgroundTint="@color/dash_btn"
511+
app:strokeWidth="1dp"
512+
app:strokeColor="@color/dash_border"
513+
app:cornerRadius="8dp" />
514+
515+
</LinearLayout>
516+
432517
</LinearLayout>
433518
</LinearLayout>
434519

‎app/src/main/res/values-de/strings.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@
287287
<string name="settings_theme_dark">Dunkles Design</string>
288288
<string name="settings_theme_light">Helles Design</string>
289289
<string name="settings_theme_desc">Zwischen dunklem und hellem Design wechseln</string>
290+
<string name="settings_text_size">Textgröße</string>
291+
<string name="settings_text_size_standard">Standard</string>
292+
<string name="settings_text_size_large">Groß</string>
293+
<string name="settings_text_size_xlarge">Sehr groß</string>
290294
<string name="settings_language">Sprache</string>
291295
<string name="settings_language_fr">Français</string>
292296
<string name="settings_language_en">English</string>

‎app/src/main/res/values-en/strings.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@
287287
<string name="settings_theme_dark">Dark mode</string>
288288
<string name="settings_theme_light">Light mode</string>
289289
<string name="settings_theme_desc">Switch between dark and light theme</string>
290+
<string name="settings_text_size">Text size</string>
291+
<string name="settings_text_size_standard">Standard</string>
292+
<string name="settings_text_size_large">Large</string>
293+
<string name="settings_text_size_xlarge">Extra large</string>
290294
<string name="settings_language">Language</string>
291295
<string name="settings_language_fr">Français</string>
292296
<string name="settings_language_en">English</string>

‎app/src/main/res/values-es/strings.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@
287287
<string name="settings_theme_dark">Modo oscuro</string>
288288
<string name="settings_theme_light">Modo claro</string>
289289
<string name="settings_theme_desc">Cambiar entre tema oscuro y claro</string>
290+
<string name="settings_text_size">Tamaño del texto</string>
291+
<string name="settings_text_size_standard">Estándar</string>
292+
<string name="settings_text_size_large">Grande</string>
293+
<string name="settings_text_size_xlarge">Muy grande</string>
290294
<string name="settings_language">Idioma</string>
291295
<string name="settings_language_fr">Français</string>
292296
<string name="settings_language_en">English</string>

‎app/src/main/res/values-it/strings.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@
287287
<string name="settings_theme_dark">Modalità scura</string>
288288
<string name="settings_theme_light">Modalità chiara</string>
289289
<string name="settings_theme_desc">Passa dal tema scuro al tema chiaro</string>
290+
<string name="settings_text_size">Dimensione del testo</string>
291+
<string name="settings_text_size_standard">Standard</string>
292+
<string name="settings_text_size_large">Grande</string>
293+
<string name="settings_text_size_xlarge">Molto grande</string>
290294
<string name="settings_language">Lingua</string>
291295
<string name="settings_language_fr">Français</string>
292296
<string name="settings_language_en">English</string>

‎app/src/main/res/values-pt/strings.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@
287287
<string name="settings_theme_dark">Modo escuro</string>
288288
<string name="settings_theme_light">Modo claro</string>
289289
<string name="settings_theme_desc">Alternar entre tema escuro e claro</string>
290+
<string name="settings_text_size">Tamanho do texto</string>
291+
<string name="settings_text_size_standard">Padrão</string>
292+
<string name="settings_text_size_large">Grande</string>
293+
<string name="settings_text_size_xlarge">Muito grande</string>
290294
<string name="settings_language">Idioma</string>
291295
<string name="settings_language_fr">Français</string>
292296
<string name="settings_language_en">English</string>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@
289289
<string name="settings_theme_dark">Mode sombre</string>
290290
<string name="settings_theme_light">Mode clair</string>
291291
<string name="settings_theme_desc">Basculer entre le thème sombre et le thème clair</string>
292+
<string name="settings_text_size">Taille du texte</string>
293+
<string name="settings_text_size_standard">Standard</string>
294+
<string name="settings_text_size_large">Grand</string>
295+
<string name="settings_text_size_xlarge">Très grand</string>
292296
<string name="settings_language">Langue</string>
293297
<string name="settings_language_fr">Français</string>
294298
<string name="settings_language_en">English</string>

0 commit comments

Comments
 (0)