@@ -51,6 +51,7 @@ import com.mg4.control.util.FirmwareInfo
5151import com.mg4.control.service.MG4ControlService
5252import com.mg4.control.util.GarageMode
5353import com.mg4.control.util.LocaleHelper
54+ import com.mg4.control.util.TextSize
5455import kotlinx.coroutines.CoroutineScope
5556import kotlinx.coroutines.Dispatchers
5657import 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
0 commit comments