Skip to content

Commit

Permalink
Merge pull request #62 from Efimj/enhancement/localization-update
Browse files Browse the repository at this point in the history
Enhancement/localization update
  • Loading branch information
Efimj authored Jun 30, 2024
2 parents 0eef876 + 8b5fb2e commit f6f023a
Show file tree
Hide file tree
Showing 13 changed files with 626 additions and 177 deletions.
23 changes: 7 additions & 16 deletions app/src/main/java/com/jobik/shkiper/NotepadApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package com.jobik.shkiper
import android.app.Application
import android.content.Context
import com.jobik.shkiper.services.billing.BillingService
import com.jobik.shkiper.services.localization.LocaleHelper
import com.jobik.shkiper.services.localization.Localization
import com.jobik.shkiper.util.ContextUtils
import com.jobik.shkiper.util.settings.SettingsManager

import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
Expand All @@ -20,18 +18,11 @@ class NotepadApplication : Application() {

override fun attachBaseContext(base: Context) {
SettingsManager.init(base)
val currentLocalization = LocaleHelper.getSavedLocalization(base) ?: LocaleHelper.getDeviceLocalization()
super.attachBaseContext(LocaleHelper.setLocale(base, currentLocalization ?: Localization.EN))
}

companion object {
private var _currentLanguage = Localization.EN
var currentLanguage: Localization
get() {
return _currentLanguage
}
set(value) {
_currentLanguage = value
}
super.attachBaseContext(
ContextUtils.setLocale(
context = base,
language = SettingsManager.settings.localization
)
)
}
}
7 changes: 5 additions & 2 deletions app/src/main/java/com/jobik/shkiper/activity/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ import com.jobik.shkiper.navigation.Screen
import com.jobik.shkiper.screens.layout.AppLayout
import com.jobik.shkiper.services.billing.BillingService
import com.jobik.shkiper.services.inAppUpdates.InAppUpdatesService
import com.jobik.shkiper.services.localization.LocaleHelper
import com.jobik.shkiper.services.review.ReviewService
import com.jobik.shkiper.services.statistics.StatisticsService
import com.jobik.shkiper.ui.components.modals.OfferWriteReview
import com.jobik.shkiper.ui.components.modals.onboarding.OnboardingDialog
import com.jobik.shkiper.ui.helpers.SecureModeManager
import com.jobik.shkiper.ui.theme.ShkiperTheme
import com.jobik.shkiper.util.ContextUtils
import com.jobik.shkiper.util.ContextUtils.adjustFontSize
import com.jobik.shkiper.util.settings.NightMode
import com.jobik.shkiper.util.settings.SettingsManager
Expand All @@ -47,7 +47,10 @@ open class MainActivity : ComponentActivity() {

override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(
LocaleHelper.setLocale(newBase, NotepadApplication.currentLanguage)
ContextUtils.setLocale(
context = newBase,
language = SettingsManager.settings.localization
)
)
}

Expand Down
208 changes: 171 additions & 37 deletions app/src/main/java/com/jobik/shkiper/screens/settings/SettingsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,35 @@ package com.jobik.shkiper.screens.settings
import android.app.Activity
import android.content.Context
import android.os.Build
import android.util.Log
import androidx.activity.compose.BackHandler
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Done
Expand All @@ -38,9 +47,14 @@ import androidx.compose.material.icons.rounded.Download
import androidx.compose.material.icons.rounded.RocketLaunch
import androidx.compose.material.icons.rounded.Tune
import androidx.compose.material.icons.rounded.Upload
import androidx.compose.material3.BottomSheetDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
Expand All @@ -52,8 +66,11 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
Expand All @@ -64,9 +81,6 @@ import com.jobik.shkiper.navigation.NavigationHelpers.Companion.navigateToSecond
import com.jobik.shkiper.navigation.Screen
import com.jobik.shkiper.services.backup.BackupService
import com.jobik.shkiper.ui.components.buttons.CustomSwitch
import com.jobik.shkiper.ui.components.buttons.DropDownButton
import com.jobik.shkiper.ui.components.buttons.DropDownButtonSizeMode
import com.jobik.shkiper.ui.components.buttons.DropDownItem
import com.jobik.shkiper.ui.components.cards.SettingsItem
import com.jobik.shkiper.ui.components.cards.ThemePreview
import com.jobik.shkiper.ui.components.layouts.SettingsGroup
Expand All @@ -77,9 +91,11 @@ import com.jobik.shkiper.ui.theme.AppTheme
import com.jobik.shkiper.ui.theme.CustomThemeColors
import com.jobik.shkiper.ui.theme.CustomThemeStyle
import com.jobik.shkiper.ui.theme.getDynamicColors
import com.jobik.shkiper.util.settings.LocaleData
import com.jobik.shkiper.util.settings.Localization
import com.jobik.shkiper.util.settings.NightMode
import com.jobik.shkiper.util.settings.SettingsManager
import kotlinx.coroutines.CoroutineScope
import com.jobik.shkiper.util.settings.SettingsManager.settings
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.enums.EnumEntries
Expand Down Expand Up @@ -331,7 +347,7 @@ private fun ProgramSettings(navController: NavController, settingsViewModel: Set
}
SettingsColorThemePicker(settingsViewModel)
Spacer(Modifier.height(4.dp))
SettingsItemSelectLanguage(settingsViewModel = settingsViewModel)
SettingsItemSelectLanguage()
SettingsItem(
icon = Icons.Rounded.Tune,
title = stringResource(R.string.advanced),
Expand Down Expand Up @@ -423,52 +439,170 @@ private fun getColors(
}


@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun SettingsItemSelectLanguage(settingsViewModel: SettingsViewModel) {
private fun SettingsItemSelectLanguage() {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val currentLanguage = NotepadApplication.currentLanguage
val dropDownItems =
remember { settingsViewModel.getLocalizationList(context).map { DropDownItem(text = it) } }
val isExpanded = remember { mutableStateOf(false) }
val currentLanguage = settings.localization
var isExpanded by remember { mutableStateOf(false) }

SettingsItem(
icon = Icons.Outlined.Language,
title = stringResource(R.string.ChoseLocalization),
onClick = { isExpanded.value = true }
onClick = { isExpanded = true }
) {
DropDownButton(
items = dropDownItems,
selectedIndex = currentLanguage.ordinal,
expanded = isExpanded,
stretchMode = DropDownButtonSizeMode.STRERCHBYCONTENT,
onChangedSelection = {
settingsViewModel.selectLocalization(it)
recreateActivity(context, coroutineScope)
}) {
Column(
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier.padding(vertical = 6.dp)
) {
Text(
text = currentLanguage.getLocalizedValue(context).name,
style = MaterialTheme.typography.titleMedium,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = AppTheme.colors.primary
)
Text(
text = currentLanguage.getLocalizedValue(context),
text = currentLanguage.getLocalizedValue(context).language,
style = MaterialTheme.typography.bodySmall,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = AppTheme.colors.primary,
style = MaterialTheme.typography.titleMedium
color = AppTheme.colors.textSecondary
)
}
}

val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
val scope = rememberCoroutineScope()

LaunchedEffect(isExpanded) {
if (!isExpanded) {
sheetState.hide()
}
}

if (isExpanded) {
val topInsets = WindowInsets.systemBars.only(WindowInsetsSides.Top)
val bottomInsets = WindowInsets.systemBars.only(WindowInsetsSides.Bottom)

ModalBottomSheet(
sheetState = sheetState,
dragHandle = null,
containerColor = Color.Transparent,
contentColor = AppTheme.colors.text,
windowInsets = WindowInsets.ime,
onDismissRequest = { isExpanded = false }
) {
Spacer(modifier = Modifier.windowInsetsPadding(topInsets))
Column(
modifier = Modifier
.clip(BottomSheetDefaults.ExpandedShape)
.background(AppTheme.colors.background)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 30.dp, vertical = 12.dp)
) {
Text(
text = stringResource(R.string.language),
style = MaterialTheme.typography.headlineSmall,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.SemiBold,
)
}
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.windowInsetsPadding(bottomInsets)
.padding(horizontal = 10.dp)
.padding(vertical = 10.dp)
.padding(bottom = 40.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Localization.entries.map { locale ->
LanguageItem(
isSelected = currentLanguage.name == locale.name,
locale = locale.getLocalizedValue(context),
onClick = {
scope
.launch {
sheetState.hide()
}
.invokeOnCompletion {
isExpanded = false
if (currentLanguage.name == locale.name) return@invokeOnCompletion

try {
SettingsManager.update(
context = context,
settings = settings.copy(localization = locale)
)
} catch (e: Exception) {
Log.d(
"ChangeLocalizationError",
e.message.toString()
)
}
(context as? Activity)?.recreate()
}
}
)
}
}
}
}
}
}

private fun recreateActivity(context: Context, scope: CoroutineScope) {
/*******************
* If you remove the delay, an error will be generated
* ANR in com.example.notepadapp (com.example.notepadapp/.activity.MainActivity)
* PID: 16898
* Reason: Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)
* Load: 0.85 / 0.24 / 0.12
* possible problem drop down layout
*******************/

scope.launch {
delay(150)
(context as? Activity)?.recreate()
@Composable
private fun LanguageItem(
isSelected: Boolean = false,
locale: LocaleData,
onClick: () -> Unit,
) {
val backgroundColorValue =
if (isSelected) AppTheme.colors.secondaryContainer else Color.Transparent
val backgroundColor by animateColorAsState(
targetValue = backgroundColorValue,
label = "backgroundColor"
)

val contentColorValue =
if (isSelected) AppTheme.colors.onSecondaryContainer else AppTheme.colors.text
val contentColor by animateColorAsState(
targetValue = contentColorValue,
label = "backgroundColor"
)

Surface(
color = backgroundColor,
contentColor = contentColor,
modifier = Modifier.fillMaxWidth(),
onClick = onClick,
shape = CircleShape,
) {
Column(
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier.padding(horizontal = 20.dp, vertical = 6.dp)
) {
Text(
text = locale.name,
style = MaterialTheme.typography.titleMedium,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = contentColor
)
Text(
text = locale.language,
style = MaterialTheme.typography.bodySmall,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = AppTheme.colors.textSecondary
)
}
}
}
Loading

0 comments on commit f6f023a

Please sign in to comment.