From f266f4d142aa9ece7a980aa6db458f0b457d218d Mon Sep 17 00:00:00 2001 From: Amirmahdi Nourkazemi Date: Sun, 14 Jun 2026 15:59:48 +0330 Subject: [PATCH] feat: font scaler added --- .../com/approagency/pharmacy/MainActivity.kt | 16 +++++++- .../pharmacy/data/local/SessionManager.kt | 16 ++++++++ .../pharmacy/domain/model/FontScale.kt | 11 ++++++ .../pharmacy/navigation/MainContainer.kt | 3 ++ .../presentation/account/AccountDrawer.kt | 39 ++++++++++++++++++- 5 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/approagency/pharmacy/domain/model/FontScale.kt diff --git a/app/src/main/java/com/approagency/pharmacy/MainActivity.kt b/app/src/main/java/com/approagency/pharmacy/MainActivity.kt index a0fe469..08c801e 100644 --- a/app/src/main/java/com/approagency/pharmacy/MainActivity.kt +++ b/app/src/main/java/com/approagency/pharmacy/MainActivity.kt @@ -12,8 +12,11 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Density import androidx.core.content.ContextCompat import androidx.lifecycle.lifecycleScope import com.approagency.pharmacy.data.local.SessionManager @@ -52,8 +55,19 @@ class MainActivity : ComponentActivity(), OtpAutofillController { enableEdgeToEdge() setContent { val themeMode by session.themeMode.collectAsState() + val fontScale by session.fontScale.collectAsState() DrugTheme(themeMode = themeMode) { - AppNavGraph() + // مقیاسِ متنِ انتخابیِ کاربر روی fontScaleِ سیستم اعمال می‌شود + // تا کلِ متن‌های اپ یک‌جا بزرگ/کوچک شوند. + val density = LocalDensity.current + CompositionLocalProvider( + LocalDensity provides Density( + density = density.density, + fontScale = density.fontScale * fontScale.scale + ) + ) { + AppNavGraph() + } } } } diff --git a/app/src/main/java/com/approagency/pharmacy/data/local/SessionManager.kt b/app/src/main/java/com/approagency/pharmacy/data/local/SessionManager.kt index a3b2b81..947b012 100644 --- a/app/src/main/java/com/approagency/pharmacy/data/local/SessionManager.kt +++ b/app/src/main/java/com/approagency/pharmacy/data/local/SessionManager.kt @@ -2,6 +2,7 @@ package com.approagency.pharmacy.data.local import android.content.Context import android.content.SharedPreferences +import com.approagency.pharmacy.domain.model.FontScale import com.approagency.pharmacy.domain.model.ThemeMode import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -128,6 +129,20 @@ class SessionManager(context: Context) { runCatching { ThemeMode.valueOf(prefs.getString(KEY_THEME_MODE, null) ?: ThemeMode.SYSTEM.name) } .getOrDefault(ThemeMode.SYSTEM) + // ---------- اندازهٔ متن ---------- + + private val _fontScale = MutableStateFlow(readFontScale()) + val fontScale: StateFlow = _fontScale.asStateFlow() + + fun setFontScale(scale: FontScale) { + prefs.edit().putString(KEY_FONT_SCALE, scale.name).apply() + _fontScale.value = scale + } + + private fun readFontScale(): FontScale = + runCatching { FontScale.valueOf(prefs.getString(KEY_FONT_SCALE, null) ?: FontScale.NORMAL.name) } + .getOrDefault(FontScale.NORMAL) + private fun readAccount() = AccountState( isLoggedIn = !token.isNullOrBlank(), mobile = prefs.getString(KEY_MOBILE, null), @@ -147,5 +162,6 @@ class SessionManager(context: Context) { const val KEY_SUB_TITLE = "subscription_title" const val KEY_SUB_EXPIRE = "subscription_expire_at" const val KEY_THEME_MODE = "theme_mode" + const val KEY_FONT_SCALE = "font_scale" } } diff --git a/app/src/main/java/com/approagency/pharmacy/domain/model/FontScale.kt b/app/src/main/java/com/approagency/pharmacy/domain/model/FontScale.kt new file mode 100644 index 0000000..3ecedfa --- /dev/null +++ b/app/src/main/java/com/approagency/pharmacy/domain/model/FontScale.kt @@ -0,0 +1,11 @@ +package com.approagency.pharmacy.domain.model + +/** + * اندازهٔ متنِ انتخابیِ کاربر (به‌ویژه برای کاربرانِ مسن‌تر). + * [scale] ضریبی است که روی fontScaleِ دستگاه اعمال می‌شود. + */ +enum class FontScale(val scale: Float, val label: String) { + NORMAL(1.0f, "معمولی"), + LARGE(1.2f, "بزرگ"), + XLARGE(1.45f, "خیلی بزرگ") +} diff --git a/app/src/main/java/com/approagency/pharmacy/navigation/MainContainer.kt b/app/src/main/java/com/approagency/pharmacy/navigation/MainContainer.kt index f69aa7a..0192f0c 100644 --- a/app/src/main/java/com/approagency/pharmacy/navigation/MainContainer.kt +++ b/app/src/main/java/com/approagency/pharmacy/navigation/MainContainer.kt @@ -39,6 +39,7 @@ fun MainContainer( val account by session.account.collectAsState() val sheetVisible by sheetController.visible.collectAsState() val themeMode by session.themeMode.collectAsState() + val fontScale by session.fontScale.collectAsState() val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() @@ -59,6 +60,8 @@ fun MainContainer( appVersion = appVersion, themeMode = themeMode, onThemeModeChange = { session.setThemeMode(it) }, + fontScale = fontScale, + onFontScaleChange = { session.setFontScale(it) }, onLogout = { showLogoutConfirm = true } ) } diff --git a/app/src/main/java/com/approagency/pharmacy/presentation/account/AccountDrawer.kt b/app/src/main/java/com/approagency/pharmacy/presentation/account/AccountDrawer.kt index ec15097..ec9ddc2 100644 --- a/app/src/main/java/com/approagency/pharmacy/presentation/account/AccountDrawer.kt +++ b/app/src/main/java/com/approagency/pharmacy/presentation/account/AccountDrawer.kt @@ -1,6 +1,8 @@ package com.approagency.pharmacy.presentation.account import androidx.compose.foundation.background +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -43,6 +45,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import com.approagency.pharmacy.data.local.AccountState +import com.approagency.pharmacy.domain.model.FontScale import com.approagency.pharmacy.domain.model.ThemeMode import com.vada.caller.ui.theme.dime @@ -60,6 +63,8 @@ fun AccountDrawer( appVersion: String, themeMode: ThemeMode, onThemeModeChange: (ThemeMode) -> Unit, + fontScale: FontScale, + onFontScaleChange: (FontScale) -> Unit, onLogout: () -> Unit ) { ModalDrawerSheet( @@ -71,6 +76,7 @@ fun AccountDrawer( modifier = Modifier .fillMaxHeight() .fillMaxWidth() + .verticalScroll(rememberScrollState()) .padding(horizontal = MaterialTheme.dime.lg, vertical = MaterialTheme.dime.xl) ) { Header(account) @@ -121,7 +127,18 @@ fun AccountDrawer( Spacer(Modifier.height(MaterialTheme.dime.sm)) ThemeModeSelector(selected = themeMode, onSelect = onThemeModeChange) - Spacer(Modifier.weight(1f)) + Spacer(Modifier.height(MaterialTheme.dime.lg)) + + // اندازهٔ متن (برای کاربرانِ مسن‌تر) + Text( + text = "اندازهٔ متن", + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.Bold + ) + Spacer(Modifier.height(MaterialTheme.dime.sm)) + FontScaleSelector(selected = fontScale, onSelect = onFontScaleChange) + + Spacer(Modifier.height(MaterialTheme.dime.xl)) if (account.isLoggedIn) { OutlinedButton( @@ -267,3 +284,23 @@ private fun ThemeModeSelector( } } } + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun FontScaleSelector( + selected: FontScale, + onSelect: (FontScale) -> Unit +) { + val options = FontScale.entries + SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) { + options.forEachIndexed { index, option -> + SegmentedButton( + selected = selected == option, + onClick = { onSelect(option) }, + shape = SegmentedButtonDefaults.itemShape(index, options.size), + icon = {}, + label = { Text(option.label, style = MaterialTheme.typography.labelSmall) } + ) + } + } +}