clean up settings and some other things
This commit is contained in:
@@ -9,14 +9,15 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||||
import com.google.accompanist.permissions.PermissionStatus
|
import com.google.accompanist.permissions.PermissionStatus
|
||||||
import com.meloda.app.fast.auth.AuthGraph
|
import com.meloda.app.fast.auth.AuthGraph
|
||||||
|
import com.meloda.app.fast.common.LongPollController
|
||||||
import com.meloda.app.fast.common.UserConfig
|
import com.meloda.app.fast.common.UserConfig
|
||||||
import com.meloda.app.fast.common.extensions.ifEmpty
|
import com.meloda.app.fast.common.extensions.ifEmpty
|
||||||
import com.meloda.app.fast.common.extensions.listenValue
|
import com.meloda.app.fast.common.extensions.listenValue
|
||||||
import com.meloda.app.fast.common.extensions.setValue
|
import com.meloda.app.fast.common.extensions.setValue
|
||||||
|
import com.meloda.app.fast.common.model.LongPollState
|
||||||
import com.meloda.app.fast.data.db.GetCurrentAccountUseCase
|
import com.meloda.app.fast.data.db.GetCurrentAccountUseCase
|
||||||
import com.meloda.app.fast.datastore.SettingsController
|
import com.meloda.app.fast.datastore.AppSettings
|
||||||
import com.meloda.app.fast.datastore.UserSettings
|
import com.meloda.app.fast.datastore.UserSettings
|
||||||
import com.meloda.app.fast.datastore.model.LongPollState
|
|
||||||
import com.meloda.app.fast.model.BaseError
|
import com.meloda.app.fast.model.BaseError
|
||||||
import com.meloda.app.fast.navigation.Main
|
import com.meloda.app.fast.navigation.Main
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -54,7 +55,8 @@ interface MainViewModel {
|
|||||||
|
|
||||||
class MainViewModelImpl(
|
class MainViewModelImpl(
|
||||||
private val getCurrentAccountUseCase: GetCurrentAccountUseCase,
|
private val getCurrentAccountUseCase: GetCurrentAccountUseCase,
|
||||||
private val userSettings: UserSettings
|
private val userSettings: UserSettings,
|
||||||
|
private val longPollController: LongPollController
|
||||||
) : MainViewModel, ViewModel() {
|
) : MainViewModel, ViewModel() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -83,11 +85,11 @@ class MainViewModelImpl(
|
|||||||
|
|
||||||
override fun onAppResumed() {
|
override fun onAppResumed() {
|
||||||
if (isNeedToShowNotificationsRationaleDialog.value) {
|
if (isNeedToShowNotificationsRationaleDialog.value) {
|
||||||
|
isNeedToShowNotificationsRationaleDialog.update { false }
|
||||||
isNeedToCheckNotificationsPermission.update { true }
|
isNeedToCheckNotificationsPermission.update { true }
|
||||||
}
|
}
|
||||||
|
|
||||||
userSettings.onLanguageChanged(
|
val newLanguage = AppCompatDelegate.getApplicationLocales()
|
||||||
AppCompatDelegate.getApplicationLocales()
|
|
||||||
.toLanguageTags()
|
.toLanguageTags()
|
||||||
.ifEmpty { null }
|
.ifEmpty { null }
|
||||||
?: LocaleListCompat.getDefault()
|
?: LocaleListCompat.getDefault()
|
||||||
@@ -96,9 +98,8 @@ class MainViewModelImpl(
|
|||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
.take(5)
|
.take(5)
|
||||||
)
|
|
||||||
|
|
||||||
userSettings.updateUsingDarkTheme()
|
userSettings.onAppLanguageChanged(newLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExperimentalPermissionsApi
|
@ExperimentalPermissionsApi
|
||||||
@@ -151,7 +152,7 @@ class MainViewModelImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun listenLongPollState() {
|
private fun listenLongPollState() {
|
||||||
userSettings.longPollStateToApply.listenValue { newState ->
|
longPollController.stateToApply.listenValue { newState ->
|
||||||
if (newState == LongPollState.Background) {
|
if (newState == LongPollState.Background) {
|
||||||
isNeedToCheckNotificationsPermission.update { true }
|
isNeedToCheckNotificationsPermission.update { true }
|
||||||
}
|
}
|
||||||
@@ -174,8 +175,8 @@ class MainViewModelImpl(
|
|||||||
this.trustedHash = currentAccount.trustedHash
|
this.trustedHash = currentAccount.trustedHash
|
||||||
}
|
}
|
||||||
|
|
||||||
userSettings.setLongPollStateToApply(
|
longPollController.setStateToApply(
|
||||||
if (SettingsController.isLongPollInBackgroundEnabled) {
|
if (AppSettings.Debug.longPollInBackground) {
|
||||||
LongPollState.Background
|
LongPollState.Background
|
||||||
} else {
|
} else {
|
||||||
LongPollState.InApp
|
LongPollState.InApp
|
||||||
@@ -191,7 +192,7 @@ class MainViewModelImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun disableBackgroundLongPoll() {
|
private fun disableBackgroundLongPoll() {
|
||||||
SettingsController.isLongPollInBackgroundEnabled = false
|
AppSettings.Debug.longPollInBackground = false
|
||||||
userSettings.setLongPollStateToApply(LongPollState.InApp)
|
longPollController.setStateToApply(LongPollState.InApp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import androidx.preference.PreferenceManager
|
|||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.ImageLoaderFactory
|
import coil.ImageLoaderFactory
|
||||||
import com.meloda.app.fast.common.di.applicationModule
|
import com.meloda.app.fast.common.di.applicationModule
|
||||||
import com.meloda.app.fast.datastore.SettingsController
|
import com.meloda.app.fast.datastore.AppSettings
|
||||||
import org.koin.android.ext.android.get
|
import org.koin.android.ext.android.get
|
||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.android.ext.koin.androidLogger
|
import org.koin.android.ext.koin.androidLogger
|
||||||
@@ -17,7 +17,7 @@ class AppGlobal : Application(), ImageLoaderFactory {
|
|||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
|
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
SettingsController.init(preferences)
|
AppSettings.init(preferences)
|
||||||
UserConfig.init(preferences)
|
UserConfig.init(preferences)
|
||||||
|
|
||||||
initKoin()
|
initKoin()
|
||||||
|
|||||||
@@ -33,15 +33,17 @@ import com.google.accompanist.permissions.rememberPermissionState
|
|||||||
import com.meloda.app.fast.MainViewModel
|
import com.meloda.app.fast.MainViewModel
|
||||||
import com.meloda.app.fast.MainViewModelImpl
|
import com.meloda.app.fast.MainViewModelImpl
|
||||||
import com.meloda.app.fast.common.AppConstants
|
import com.meloda.app.fast.common.AppConstants
|
||||||
|
import com.meloda.app.fast.common.LongPollController
|
||||||
import com.meloda.app.fast.common.extensions.isSdkAtLeast
|
import com.meloda.app.fast.common.extensions.isSdkAtLeast
|
||||||
import com.meloda.app.fast.datastore.SettingsController
|
import com.meloda.app.fast.common.model.LongPollState
|
||||||
|
import com.meloda.app.fast.datastore.AppSettings
|
||||||
import com.meloda.app.fast.datastore.UserSettings
|
import com.meloda.app.fast.datastore.UserSettings
|
||||||
import com.meloda.app.fast.datastore.model.LongPollState
|
|
||||||
import com.meloda.app.fast.service.OnlineService
|
import com.meloda.app.fast.service.OnlineService
|
||||||
import com.meloda.app.fast.service.longpolling.LongPollingService
|
import com.meloda.app.fast.service.longpolling.LongPollingService
|
||||||
import com.meloda.app.fast.ui.model.ThemeConfig
|
import com.meloda.app.fast.ui.model.ThemeConfig
|
||||||
import com.meloda.app.fast.ui.theme.AppTheme
|
import com.meloda.app.fast.ui.theme.AppTheme
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
|
import com.meloda.app.fast.ui.util.isNeedToEnableDarkMode
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
import org.koin.compose.KoinContext
|
import org.koin.compose.KoinContext
|
||||||
import org.koin.compose.koinInject
|
import org.koin.compose.koinInject
|
||||||
@@ -53,7 +55,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
SettingsController.deviceId = Settings.Secure.getString(
|
AppSettings.deviceId = Settings.Secure.getString(
|
||||||
contentResolver,
|
contentResolver,
|
||||||
Settings.Secure.ANDROID_ID
|
Settings.Secure.ANDROID_ID
|
||||||
)
|
)
|
||||||
@@ -78,10 +80,12 @@ class MainActivity : AppCompatActivity() {
|
|||||||
setContent {
|
setContent {
|
||||||
KoinContext {
|
KoinContext {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val userSettings: UserSettings = koinInject()
|
|
||||||
|
|
||||||
val longPollCurrentState by userSettings.longPollCurrentState.collectAsStateWithLifecycle()
|
val userSettings: UserSettings = koinInject()
|
||||||
val longPollStateToApply by userSettings.longPollStateToApply.collectAsStateWithLifecycle()
|
val longPollController: LongPollController = koinInject()
|
||||||
|
|
||||||
|
val longPollCurrentState by longPollController.currentState.collectAsStateWithLifecycle()
|
||||||
|
val longPollStateToApply by longPollController.stateToApply.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
val viewModel: MainViewModel = koinViewModel<MainViewModelImpl>()
|
val viewModel: MainViewModel = koinViewModel<MainViewModelImpl>()
|
||||||
|
|
||||||
@@ -136,9 +140,9 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val isOnline by userSettings.online.collectAsStateWithLifecycle()
|
val sendOnline by userSettings.sendOnlineStatus.collectAsStateWithLifecycle()
|
||||||
LifecycleResumeEffect(isOnline) {
|
LifecycleResumeEffect(sendOnline) {
|
||||||
toggleOnlineService(isOnline)
|
toggleOnlineService(sendOnline)
|
||||||
|
|
||||||
onPauseOrDispose {
|
onPauseOrDispose {
|
||||||
toggleOnlineService(false)
|
toggleOnlineService(false)
|
||||||
@@ -151,25 +155,22 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val theme by userSettings.theme.collectAsStateWithLifecycle()
|
val themeConfig = ThemeConfig(
|
||||||
CompositionLocalProvider(
|
darkMode = isNeedToEnableDarkMode(userSettings.darkMode.value),
|
||||||
LocalTheme provides ThemeConfig(
|
dynamicColors = userSettings.enableDynamicColors.value,
|
||||||
usingDarkStyle = theme.usingDarkStyle,
|
selectedColorScheme = 0,
|
||||||
usingDynamicColors = theme.usingDynamicColors,
|
amoledDark = userSettings.enableAmoledDark.value,
|
||||||
selectedColorScheme = theme.selectedColorScheme,
|
enableBlur = userSettings.useBlur.value,
|
||||||
usingAmoledBackground = theme.usingAmoledBackground,
|
enableMultiline = userSettings.enableMultiline.value,
|
||||||
usingBlur = theme.usingBlur,
|
|
||||||
isMultiline = theme.isMultiline,
|
|
||||||
isDeviceCompact = isDeviceCompact
|
isDeviceCompact = isDeviceCompact
|
||||||
)
|
)
|
||||||
) {
|
|
||||||
val currentTheme = LocalTheme.current
|
|
||||||
|
|
||||||
|
CompositionLocalProvider(LocalThemeConfig provides themeConfig) {
|
||||||
AppTheme(
|
AppTheme(
|
||||||
useDarkTheme = currentTheme.usingDarkStyle,
|
useDarkTheme = themeConfig.darkMode,
|
||||||
useDynamicColors = currentTheme.usingDynamicColors,
|
useDynamicColors = themeConfig.dynamicColors,
|
||||||
selectedColorScheme = currentTheme.selectedColorScheme,
|
selectedColorScheme = themeConfig.selectedColorScheme,
|
||||||
useAmoledBackground = currentTheme.usingAmoledBackground,
|
useAmoledBackground = themeConfig.amoledDark,
|
||||||
) {
|
) {
|
||||||
RootScreen(viewModel = viewModel)
|
RootScreen(viewModel = viewModel)
|
||||||
}
|
}
|
||||||
@@ -220,7 +221,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun toggleLongPollService(
|
private fun toggleLongPollService(
|
||||||
enable: Boolean,
|
enable: Boolean,
|
||||||
inBackground: Boolean = SettingsController.isLongPollInBackgroundEnabled
|
inBackground: Boolean = AppSettings.Debug.longPollInBackground
|
||||||
) {
|
) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
val longPollIntent = Intent(this, LongPollingService::class.java)
|
val longPollIntent = Intent(this, LongPollingService::class.java)
|
||||||
@@ -246,7 +247,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private fun stopServices() {
|
private fun stopServices() {
|
||||||
toggleOnlineService(enable = false)
|
toggleOnlineService(enable = false)
|
||||||
|
|
||||||
val asForeground = SettingsController.isLongPollInBackgroundEnabled
|
val asForeground = AppSettings.Debug.longPollInBackground
|
||||||
|
|
||||||
if (!asForeground) {
|
if (!asForeground) {
|
||||||
toggleLongPollService(enable = false)
|
toggleLongPollService(enable = false)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import androidx.navigation.compose.rememberNavController
|
|||||||
import com.meloda.app.fast.conversations.navigation.conversationsScreen
|
import com.meloda.app.fast.conversations.navigation.conversationsScreen
|
||||||
import com.meloda.app.fast.ui.theme.LocalBottomPadding
|
import com.meloda.app.fast.ui.theme.LocalBottomPadding
|
||||||
import com.meloda.app.fast.ui.theme.LocalHazeState
|
import com.meloda.app.fast.ui.theme.LocalHazeState
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import com.meloda.app.fast.friends.navigation.friendsScreen
|
import com.meloda.app.fast.friends.navigation.friendsScreen
|
||||||
import com.meloda.app.fast.model.BaseError
|
import com.meloda.app.fast.model.BaseError
|
||||||
import com.meloda.app.fast.model.BottomNavigationItem
|
import com.meloda.app.fast.model.BottomNavigationItem
|
||||||
@@ -47,7 +47,7 @@ fun MainScreen(
|
|||||||
onSettingsButtonClicked: () -> Unit = {},
|
onSettingsButtonClicked: () -> Unit = {},
|
||||||
onConversationItemClicked: (conversationId: Int) -> Unit = {}
|
onConversationItemClicked: (conversationId: Int) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
val hazeState = remember { HazeState() }
|
val hazeState = remember { HazeState() }
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ fun MainScreen(
|
|||||||
NavigationBar(
|
NavigationBar(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.then(
|
.then(
|
||||||
if (currentTheme.usingBlur) {
|
if (currentTheme.enableBlur) {
|
||||||
Modifier.hazeChild(
|
Modifier.hazeChild(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = HazeMaterials.thick()
|
style = HazeMaterials.thick()
|
||||||
@@ -69,7 +69,7 @@ fun MainScreen(
|
|||||||
)
|
)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
containerColor = NavigationBarDefaults.containerColor.copy(
|
containerColor = NavigationBarDefaults.containerColor.copy(
|
||||||
alpha = if (currentTheme.usingBlur) 0f else 1f
|
alpha = if (currentTheme.enableBlur) 0f else 1f
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
navigationItems.forEachIndexed { index, item ->
|
navigationItems.forEachIndexed { index, item ->
|
||||||
@@ -105,11 +105,11 @@ fun MainScreen(
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(bottom = if (currentTheme.usingBlur) 0.dp else padding.calculateBottomPadding())
|
.padding(bottom = if (currentTheme.enableBlur) 0.dp else padding.calculateBottomPadding())
|
||||||
) {
|
) {
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalHazeState provides hazeState,
|
LocalHazeState provides hazeState,
|
||||||
LocalBottomPadding provides if (currentTheme.usingBlur) padding.calculateBottomPadding() else 0.dp
|
LocalBottomPadding provides if (currentTheme.enableBlur) padding.calculateBottomPadding() else 0.dp
|
||||||
) {
|
) {
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package com.meloda.app.fast.provider
|
package com.meloda.app.fast.provider
|
||||||
|
|
||||||
import com.meloda.app.fast.common.ApiLanguage
|
import com.meloda.app.fast.common.model.ApiLanguage
|
||||||
import com.meloda.app.fast.common.provider.Provider
|
import com.meloda.app.fast.common.provider.Provider
|
||||||
import com.meloda.app.fast.datastore.UserSettings
|
import com.meloda.app.fast.datastore.UserSettings
|
||||||
|
|
||||||
class ApiLanguageProvider(private val userSettings: UserSettings) : Provider<ApiLanguage> {
|
class ApiLanguageProvider(private val userSettings: UserSettings) : Provider<ApiLanguage> {
|
||||||
|
|
||||||
override fun provide(): ApiLanguage? {
|
override fun provide(): ApiLanguage? {
|
||||||
val language = userSettings.language.value
|
val language = userSettings.appLanguage.value
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
language == "ru-RU" -> "ru"
|
language == "ru-RU" -> "ru"
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.meloda.app.fast.service.longpolling
|
|||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
@@ -13,19 +12,18 @@ import androidx.core.app.NotificationCompat
|
|||||||
import androidx.core.app.ServiceCompat
|
import androidx.core.app.ServiceCompat
|
||||||
import com.conena.nanokt.android.app.stopForegroundCompat
|
import com.conena.nanokt.android.app.stopForegroundCompat
|
||||||
import com.meloda.app.fast.common.AppConstants
|
import com.meloda.app.fast.common.AppConstants
|
||||||
|
import com.meloda.app.fast.common.LongPollController
|
||||||
import com.meloda.app.fast.common.UserConfig
|
import com.meloda.app.fast.common.UserConfig
|
||||||
import com.meloda.app.fast.common.VkConstants
|
import com.meloda.app.fast.common.VkConstants
|
||||||
import com.meloda.app.fast.common.extensions.listenValue
|
import com.meloda.app.fast.common.extensions.listenValue
|
||||||
|
import com.meloda.app.fast.common.model.LongPollState
|
||||||
import com.meloda.app.fast.data.LongPollUpdatesParser
|
import com.meloda.app.fast.data.LongPollUpdatesParser
|
||||||
import com.meloda.app.fast.data.LongPollUseCase
|
import com.meloda.app.fast.data.LongPollUseCase
|
||||||
import com.meloda.app.fast.data.processState
|
import com.meloda.app.fast.data.processState
|
||||||
import com.meloda.app.fast.datastore.SettingsController
|
import com.meloda.app.fast.datastore.AppSettings
|
||||||
import com.meloda.app.fast.datastore.SettingsKeys
|
|
||||||
import com.meloda.app.fast.datastore.UserSettings
|
|
||||||
import com.meloda.app.fast.datastore.model.LongPollState
|
|
||||||
import com.meloda.app.fast.ui.R
|
|
||||||
import com.meloda.app.fast.model.api.data.LongPollUpdates
|
import com.meloda.app.fast.model.api.data.LongPollUpdates
|
||||||
import com.meloda.app.fast.model.api.data.VkLongPollData
|
import com.meloda.app.fast.model.api.data.VkLongPollData
|
||||||
|
import com.meloda.app.fast.ui.R
|
||||||
import com.meloda.app.fast.util.NotificationsUtils
|
import com.meloda.app.fast.util.NotificationsUtils
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -40,7 +38,7 @@ import kotlin.coroutines.suspendCoroutine
|
|||||||
|
|
||||||
class LongPollingService : Service() {
|
class LongPollingService : Service() {
|
||||||
|
|
||||||
private val userSettings: UserSettings by inject()
|
private val longPollController: LongPollController by inject()
|
||||||
|
|
||||||
private val job = SupervisorJob()
|
private val job = SupervisorJob()
|
||||||
|
|
||||||
@@ -51,8 +49,8 @@ class LongPollingService : Service() {
|
|||||||
throwable.printStackTrace()
|
throwable.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
userSettings.updateLongPollCurrentState(LongPollState.Exception)
|
longPollController.updateCurrentState(LongPollState.Exception)
|
||||||
userSettings.setLongPollStateToApply(LongPollState.Exception)
|
longPollController.setStateToApply(LongPollState.Exception)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val coroutineContext: CoroutineContext
|
private val coroutineContext: CoroutineContext
|
||||||
@@ -62,7 +60,6 @@ class LongPollingService : Service() {
|
|||||||
|
|
||||||
private val longPollUseCase: LongPollUseCase by inject()
|
private val longPollUseCase: LongPollUseCase by inject()
|
||||||
private val updatesParser: LongPollUpdatesParser by inject()
|
private val updatesParser: LongPollUpdatesParser by inject()
|
||||||
private val preferences: SharedPreferences by inject()
|
|
||||||
|
|
||||||
private var currentJob: Job? = null
|
private var currentJob: Job? = null
|
||||||
|
|
||||||
@@ -79,10 +76,7 @@ class LongPollingService : Service() {
|
|||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
if (startId > 1) return START_STICKY
|
if (startId > 1) return START_STICKY
|
||||||
|
|
||||||
val inBackground = preferences.getBoolean(
|
val inBackground = AppSettings.Debug.longPollInBackground
|
||||||
SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND,
|
|
||||||
SettingsKeys.DEFAULT_VALUE_FEATURES_LONG_POLL_IN_BACKGROUND
|
|
||||||
)
|
|
||||||
|
|
||||||
Log.d(
|
Log.d(
|
||||||
STATE_TAG,
|
STATE_TAG,
|
||||||
@@ -114,7 +108,7 @@ class LongPollingService : Service() {
|
|||||||
PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
|
||||||
userSettings.updateLongPollCurrentState(
|
longPollController.updateCurrentState(
|
||||||
if (inBackground) LongPollState.Background
|
if (inBackground) LongPollState.Background
|
||||||
else LongPollState.InApp
|
else LongPollState.InApp
|
||||||
)
|
)
|
||||||
@@ -254,11 +248,9 @@ class LongPollingService : Service() {
|
|||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
Log.d(STATE_TAG, "onDestroy")
|
Log.d(STATE_TAG, "onDestroy")
|
||||||
userSettings.updateLongPollCurrentState(LongPollState.Stopped)
|
longPollController.updateCurrentState(LongPollState.Stopped)
|
||||||
try {
|
try {
|
||||||
SettingsController.edit {
|
AppSettings.edit { putBoolean(KEY_LONG_POLL_WAS_DESTROYED, true) }
|
||||||
putBoolean(KEY_LONG_POLL_WAS_DESTROYED, true)
|
|
||||||
}
|
|
||||||
job.cancel()
|
job.cancel()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
@@ -268,6 +260,7 @@ class LongPollingService : Service() {
|
|||||||
|
|
||||||
override fun onLowMemory() {
|
override fun onLowMemory() {
|
||||||
Log.d(STATE_TAG, "onLowMemory")
|
Log.d(STATE_TAG, "onLowMemory")
|
||||||
|
longPollController.updateCurrentState(LongPollState.Stopped)
|
||||||
super.onLowMemory()
|
super.onLowMemory()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.meloda.app.fast.common
|
||||||
|
|
||||||
|
import com.meloda.app.fast.common.model.LongPollState
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
|
interface LongPollController {
|
||||||
|
val currentState: StateFlow<LongPollState>
|
||||||
|
val stateToApply: StateFlow<LongPollState>
|
||||||
|
|
||||||
|
fun updateCurrentState(newState: LongPollState)
|
||||||
|
fun setStateToApply(newState: LongPollState)
|
||||||
|
}
|
||||||
|
|
||||||
|
class LongPollControllerImpl : LongPollController {
|
||||||
|
|
||||||
|
override val currentState = MutableStateFlow<LongPollState>(LongPollState.Stopped)
|
||||||
|
override val stateToApply = MutableStateFlow<LongPollState>(LongPollState.Stopped)
|
||||||
|
|
||||||
|
override fun updateCurrentState(newState: LongPollState) {
|
||||||
|
currentState.value = newState
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setStateToApply(newState: LongPollState) {
|
||||||
|
currentState.value = newState
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
package com.meloda.app.fast.common.di
|
package com.meloda.app.fast.common.di
|
||||||
|
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
|
import com.meloda.app.fast.common.LongPollController
|
||||||
|
import com.meloda.app.fast.common.LongPollControllerImpl
|
||||||
|
import com.meloda.app.fast.common.provider.ResourceProvider
|
||||||
|
import com.meloda.app.fast.common.provider.ResourceProviderImpl
|
||||||
|
import org.koin.core.module.dsl.singleOf
|
||||||
|
import org.koin.dsl.bind
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val commonModule = module {
|
val commonModule = module {
|
||||||
@@ -9,4 +15,7 @@ val commonModule = module {
|
|||||||
.crossfade(true)
|
.crossfade(true)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
singleOf(::LongPollControllerImpl) bind LongPollController::class
|
||||||
|
singleOf(::ResourceProviderImpl) bind ResourceProvider::class
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.meloda.app.fast.common
|
package com.meloda.app.fast.common.extensions
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
package com.meloda.app.fast.common
|
package com.meloda.app.fast.common.model
|
||||||
|
|
||||||
data class ApiLanguage(val value: String)
|
data class ApiLanguage(val value: String)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.meloda.app.fast.common.model
|
||||||
|
|
||||||
|
private const val MODE_NIGHT_NO = 1
|
||||||
|
private const val MODE_NIGHT_YES = 2
|
||||||
|
private const val MODE_NIGHT_FOLLOW_SYSTEM = -1
|
||||||
|
private const val MODE_NIGHT_AUTO_BATTERY = 3
|
||||||
|
|
||||||
|
enum class DarkMode(val value: Int) {
|
||||||
|
DISABLED(MODE_NIGHT_NO),
|
||||||
|
FOLLOW_SYSTEM(MODE_NIGHT_FOLLOW_SYSTEM),
|
||||||
|
AUTO_BATTERY(MODE_NIGHT_AUTO_BATTERY),
|
||||||
|
ENABLED(MODE_NIGHT_YES);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun parse(value: Int): DarkMode = entries.firstOrNull { it.value == value }
|
||||||
|
?: throw IllegalArgumentException("Unknown dark mode with value: $value")
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
package com.meloda.app.fast.datastore.model
|
package com.meloda.app.fast.common.model
|
||||||
|
|
||||||
sealed class LongPollState {
|
sealed class LongPollState {
|
||||||
data object Stopped : LongPollState()
|
data object Stopped : LongPollState()
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.meloda.app.fast.common
|
package com.meloda.app.fast.common.model
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
+3
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.meloda.app.fast.common
|
package com.meloda.app.fast.common.model
|
||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import androidx.annotation.PluralsRes
|
import androidx.annotation.PluralsRes
|
||||||
@@ -18,6 +18,8 @@ sealed class UiText {
|
|||||||
data class Simple(val text: String) : UiText()
|
data class Simple(val text: String) : UiText()
|
||||||
|
|
||||||
data class QuantityResource(@PluralsRes val resId: Int, val quantity: Int) : UiText()
|
data class QuantityResource(@PluralsRes val resId: Int, val quantity: Int) : UiText()
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun UiText?.parseString(resources: Resources): String? {
|
fun UiText?.parseString(resources: Resources): String? {
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.meloda.app.fast.common.provider
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
|
||||||
|
interface ResourceProvider {
|
||||||
|
|
||||||
|
fun getString(resId: Int): String
|
||||||
|
}
|
||||||
|
|
||||||
|
class ResourceProviderImpl(private val resources: Resources) : ResourceProvider {
|
||||||
|
|
||||||
|
override fun getString(resId: Int): String {
|
||||||
|
return resources.getString(resId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
package com.meloda.app.fast.datastore
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import com.meloda.app.fast.common.model.DarkMode
|
||||||
|
import kotlin.properties.Delegates
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
object AppSettings {
|
||||||
|
|
||||||
|
private var preferences: SharedPreferences by Delegates.notNull()
|
||||||
|
|
||||||
|
fun init(preferences: SharedPreferences) {
|
||||||
|
this.preferences = preferences
|
||||||
|
}
|
||||||
|
|
||||||
|
fun edit(
|
||||||
|
commit: Boolean = false,
|
||||||
|
action: SharedPreferences.Editor.() -> Unit
|
||||||
|
) {
|
||||||
|
preferences.edit(commit, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getString(key: String, defaultValue: String?): String? {
|
||||||
|
return preferences.getString(key, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBoolean(key: String, defaultValue: Boolean): Boolean {
|
||||||
|
return preferences.getBoolean(key, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getInt(key: String, defaultValue: Int): Int {
|
||||||
|
return preferences.getInt(key, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLong(key: String, defaultValue: Long): Long {
|
||||||
|
return preferences.getLong(key, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFloat(key: String, defaultValue: Float): Float {
|
||||||
|
return preferences.getFloat(key, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T : Any> get(clazz: KClass<T>, key: String, defaultValue: T): T {
|
||||||
|
return when (clazz) {
|
||||||
|
String::class -> getString(key, defaultValue as String)
|
||||||
|
Boolean::class -> getBoolean(key, defaultValue as Boolean)
|
||||||
|
Int::class -> getInt(key, defaultValue as Int)
|
||||||
|
Long::class -> getLong(key, defaultValue as Long)
|
||||||
|
Float::class -> getFloat(key, defaultValue as Float)
|
||||||
|
else -> throw IllegalStateException("Unsupported class: $clazz")
|
||||||
|
} as T
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> get(key: String, defaultValue: T): T {
|
||||||
|
return when (T::class) {
|
||||||
|
String::class -> getString(key, defaultValue as String)
|
||||||
|
Boolean::class -> getBoolean(key, defaultValue as Boolean)
|
||||||
|
Int::class -> getInt(key, defaultValue as Int)
|
||||||
|
Long::class -> getLong(key, defaultValue as Long)
|
||||||
|
Float::class -> getFloat(key, defaultValue as Float)
|
||||||
|
else -> throw IllegalStateException("Unsupported class: ${T::class}")
|
||||||
|
} as T
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> put(key: String, newValue: T?) {
|
||||||
|
preferences.edit {
|
||||||
|
when (newValue) {
|
||||||
|
is String -> putString(key, newValue)
|
||||||
|
is Boolean -> putBoolean(key, newValue)
|
||||||
|
is Int -> putInt(key, newValue)
|
||||||
|
is Long -> putLong(key, newValue)
|
||||||
|
is Float -> putFloat(key, newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var deviceId: String
|
||||||
|
get() = get("device_id", "")
|
||||||
|
set(value) = put("device_id", value)
|
||||||
|
|
||||||
|
object General {
|
||||||
|
var useContactNames: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_USE_CONTACT_NAMES,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_USE_CONTACT_NAMES
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_USE_CONTACT_NAMES, value)
|
||||||
|
|
||||||
|
var enablePullToRefresh: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_ENABLE_PULL_TO_REFRESH,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_ENABLE_PULL_TO_REFRESH
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_ENABLE_PULL_TO_REFRESH, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Appearance {
|
||||||
|
var enableMultiline: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_APPEARANCE_MULTILINE,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_MULTILINE
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_APPEARANCE_MULTILINE, value)
|
||||||
|
|
||||||
|
var darkMode: DarkMode
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_APPEARANCE_DARK_MODE,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_APPEARANCE_DARK_MODE
|
||||||
|
).let(DarkMode.Companion::parse)
|
||||||
|
set(mode) = put(SettingsKeys.KEY_APPEARANCE_DARK_MODE, mode.value)
|
||||||
|
|
||||||
|
var enableAmoledDark: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_APPEARANCE_AMOLED_THEME,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_APPEARANCE_AMOLED_THEME
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_APPEARANCE_AMOLED_THEME, value)
|
||||||
|
|
||||||
|
var enableDynamicColors: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_USE_DYNAMIC_COLORS,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_USE_DYNAMIC_COLORS
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_USE_DYNAMIC_COLORS, value)
|
||||||
|
|
||||||
|
var appLanguage: String
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_APPEARANCE_LANGUAGE,
|
||||||
|
SettingsKeys.DEFAULT_APPEARANCE_LANGUAGE
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_APPEARANCE_LANGUAGE, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Features {
|
||||||
|
var fastText: String
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_FEATURES_FAST_TEXT,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_FEATURES_FAST_TEXT
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_FEATURES_FAST_TEXT, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Activity {
|
||||||
|
var sendOnlineStatus: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_ACTIVITY_SEND_ONLINE_STATUS,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_KEY_ACTIVITY_SEND_ONLINE_STATUS
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_ACTIVITY_SEND_ONLINE_STATUS, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Debug {
|
||||||
|
var showAlertAfterCrash: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_DEBUG_SHOW_CRASH_ALERT,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_DEBUG_SHOW_CRASH_ALERT, value)
|
||||||
|
|
||||||
|
var longPollInBackground: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_FEATURES_LONG_POLL_IN_BACKGROUND
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND, value)
|
||||||
|
|
||||||
|
var useBlur: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_APPEARANCE_USE_BLUR,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_KEY_APPEARANCE_USE_BLUR
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_APPEARANCE_USE_BLUR, value)
|
||||||
|
|
||||||
|
var showEmojiButton: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_SHOW_EMOJI_BUTTON,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_KEY_SHOW_EMOJI_BUTTON
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_SHOW_EMOJI_BUTTON, value)
|
||||||
|
|
||||||
|
var showDebugCategory: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_SHOW_DEBUG_CATEGORY, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package com.meloda.app.fast.datastore
|
|
||||||
|
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.content.res.Resources
|
|
||||||
import android.os.PowerManager
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
|
|
||||||
fun isUsingDarkMode(
|
|
||||||
resources: Resources,
|
|
||||||
powerManager: PowerManager,
|
|
||||||
): Boolean {
|
|
||||||
val nightThemeMode: Int = SettingsController.getInt(
|
|
||||||
SettingsKeys.KEY_APPEARANCE_DARK_THEME,
|
|
||||||
SettingsKeys.DEFAULT_VALUE_APPEARANCE_DARK_THEME
|
|
||||||
)
|
|
||||||
|
|
||||||
val appForceDarkMode = nightThemeMode == AppCompatDelegate.MODE_NIGHT_YES
|
|
||||||
val appBatterySaver = nightThemeMode == AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY
|
|
||||||
|
|
||||||
val systemUiNightMode = resources.configuration.uiMode
|
|
||||||
|
|
||||||
val isSystemBatterySaver = powerManager.isPowerSaveMode
|
|
||||||
val isSystemUsingDarkTheme =
|
|
||||||
systemUiNightMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
|
||||||
|
|
||||||
return appForceDarkMode || (appBatterySaver && isSystemBatterySaver) || (!appBatterySaver && isSystemUsingDarkTheme && nightThemeMode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isUsingDynamicColors(): Boolean = SettingsController.getBoolean(
|
|
||||||
SettingsKeys.KEY_USE_DYNAMIC_COLORS,
|
|
||||||
SettingsKeys.DEFAULT_VALUE_USE_DYNAMIC_COLORS
|
|
||||||
)
|
|
||||||
|
|
||||||
fun isUsingAmoledBackground(): Boolean = SettingsController.getBoolean(
|
|
||||||
SettingsKeys.KEY_APPEARANCE_AMOLED_THEME,
|
|
||||||
SettingsKeys.DEFAULT_VALUE_APPEARANCE_AMOLED_THEME
|
|
||||||
)
|
|
||||||
|
|
||||||
fun selectedColorScheme(): Int = SettingsController.getInt(
|
|
||||||
SettingsKeys.KEY_APPEARANCE_COLOR_SCHEME,
|
|
||||||
SettingsKeys.DEFAULT_VALUE_APPEARANCE_COLOR_SCHEME
|
|
||||||
)
|
|
||||||
|
|
||||||
fun isUsingBlur(): Boolean = SettingsController.getBoolean(
|
|
||||||
SettingsKeys.KEY_APPEARANCE_BLUR,
|
|
||||||
SettingsKeys.DEFAULT_VALUE_KEY_APPEARANCE_BLUR
|
|
||||||
)
|
|
||||||
|
|
||||||
fun isDebugSettingsShown(): Boolean = SettingsController.getBoolean(
|
|
||||||
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
fun isMultiline(): Boolean = SettingsController.getBoolean(
|
|
||||||
SettingsKeys.KEY_APPEARANCE_MULTILINE,
|
|
||||||
SettingsKeys.DEFAULT_VALUE_MULTILINE
|
|
||||||
)
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
package com.meloda.app.fast.datastore
|
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.core.content.edit
|
|
||||||
import kotlin.properties.Delegates
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
object SettingsController {
|
|
||||||
|
|
||||||
private var preferences: SharedPreferences by Delegates.notNull()
|
|
||||||
|
|
||||||
fun init(preferences: SharedPreferences) {
|
|
||||||
this.preferences = preferences
|
|
||||||
}
|
|
||||||
|
|
||||||
fun edit(
|
|
||||||
commit: Boolean = false,
|
|
||||||
action: SharedPreferences.Editor.() -> Unit
|
|
||||||
) {
|
|
||||||
preferences.edit(commit, action)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getString(key: String, defaultValue: String?): String? {
|
|
||||||
return preferences.getString(key, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getBoolean(key: String, defaultValue: Boolean): Boolean {
|
|
||||||
return preferences.getBoolean(key, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getInt(key: String, defaultValue: Int): Int {
|
|
||||||
return preferences.getInt(key, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getLong(key: String, defaultValue: Long): Long {
|
|
||||||
return preferences.getLong(key, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getFloat(key: String, defaultValue: Float): Float {
|
|
||||||
return preferences.getFloat(key, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun <T : Any> get(clazz: KClass<T>, key: String, defaultValue: T): T {
|
|
||||||
return when (clazz) {
|
|
||||||
String::class -> getString(key, defaultValue as String)
|
|
||||||
Boolean::class -> getBoolean(key, defaultValue as Boolean)
|
|
||||||
Int::class -> getInt(key, defaultValue as Int)
|
|
||||||
Long::class -> getLong(key, defaultValue as Long)
|
|
||||||
Float::class -> getFloat(key, defaultValue as Float)
|
|
||||||
else -> throw IllegalStateException("Unsupported class: $clazz")
|
|
||||||
} as T
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T> get(key: String, defaultValue: T): T {
|
|
||||||
return when (T::class) {
|
|
||||||
String::class -> getString(key, defaultValue as String)
|
|
||||||
Boolean::class -> getBoolean(key, defaultValue as Boolean)
|
|
||||||
Int::class -> getInt(key, defaultValue as Int)
|
|
||||||
Long::class -> getLong(key, defaultValue as Long)
|
|
||||||
Float::class -> getFloat(key, defaultValue as Float)
|
|
||||||
else -> throw IllegalStateException("Unsupported class: ${T::class}")
|
|
||||||
} as T
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> put(key: String, newValue: T?) {
|
|
||||||
preferences.edit {
|
|
||||||
when (newValue) {
|
|
||||||
is String -> putString(key, newValue)
|
|
||||||
is Boolean -> putBoolean(key, newValue)
|
|
||||||
is Int -> putInt(key, newValue)
|
|
||||||
is Long -> putLong(key, newValue)
|
|
||||||
is Float -> putFloat(key, newValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var isLongPollInBackgroundEnabled: Boolean
|
|
||||||
get() = get(
|
|
||||||
SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND,
|
|
||||||
SettingsKeys.DEFAULT_VALUE_FEATURES_LONG_POLL_IN_BACKGROUND
|
|
||||||
)
|
|
||||||
set(value) = put(SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND, value)
|
|
||||||
|
|
||||||
var deviceId: String
|
|
||||||
get() = get("device_id", "")
|
|
||||||
set(value) = put("device_id", value)
|
|
||||||
|
|
||||||
var enablePullToRefresh: Boolean
|
|
||||||
get() = get(
|
|
||||||
SettingsKeys.KEY_ENABLE_PULL_TO_REFRESH,
|
|
||||||
SettingsKeys.DEFAULT_VALUE_ENABLE_PULL_TO_REFRESH
|
|
||||||
)
|
|
||||||
set(value) = put(SettingsKeys.KEY_ENABLE_PULL_TO_REFRESH, value)
|
|
||||||
}
|
|
||||||
@@ -17,8 +17,8 @@ object SettingsKeys {
|
|||||||
const val KEY_APPEARANCE = "appearance"
|
const val KEY_APPEARANCE = "appearance"
|
||||||
const val KEY_APPEARANCE_MULTILINE = "appearance_multiline"
|
const val KEY_APPEARANCE_MULTILINE = "appearance_multiline"
|
||||||
const val DEFAULT_VALUE_MULTILINE = true
|
const val DEFAULT_VALUE_MULTILINE = true
|
||||||
const val KEY_APPEARANCE_DARK_THEME = "appearance_appearance_dark_theme"
|
const val KEY_APPEARANCE_DARK_MODE = "appearance_appearance_dark_mode"
|
||||||
const val DEFAULT_VALUE_APPEARANCE_DARK_THEME = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
const val DEFAULT_VALUE_APPEARANCE_DARK_MODE = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
const val KEY_APPEARANCE_AMOLED_THEME = "appearance_amoled_theme"
|
const val KEY_APPEARANCE_AMOLED_THEME = "appearance_amoled_theme"
|
||||||
const val DEFAULT_VALUE_APPEARANCE_AMOLED_THEME = false
|
const val DEFAULT_VALUE_APPEARANCE_AMOLED_THEME = false
|
||||||
const val KEY_USE_DYNAMIC_COLORS = "appearance_use_dynamic_colors"
|
const val KEY_USE_DYNAMIC_COLORS = "appearance_use_dynamic_colors"
|
||||||
@@ -26,8 +26,9 @@ object SettingsKeys {
|
|||||||
const val KEY_APPEARANCE_COLOR_SCHEME = "appearance_color_scheme"
|
const val KEY_APPEARANCE_COLOR_SCHEME = "appearance_color_scheme"
|
||||||
const val DEFAULT_VALUE_APPEARANCE_COLOR_SCHEME = 0
|
const val DEFAULT_VALUE_APPEARANCE_COLOR_SCHEME = 0
|
||||||
const val KEY_APPEARANCE_LANGUAGE = "appearance_language"
|
const val KEY_APPEARANCE_LANGUAGE = "appearance_language"
|
||||||
const val KEY_APPEARANCE_BLUR = "appearance_blur"
|
const val DEFAULT_APPEARANCE_LANGUAGE = ""
|
||||||
const val DEFAULT_VALUE_KEY_APPEARANCE_BLUR = false
|
const val KEY_APPEARANCE_USE_BLUR = "appearance_use_blur"
|
||||||
|
const val DEFAULT_VALUE_KEY_APPEARANCE_USE_BLUR = false
|
||||||
|
|
||||||
const val KEY_FEATURES_FAST_TEXT = "features_fast_text"
|
const val KEY_FEATURES_FAST_TEXT = "features_fast_text"
|
||||||
const val DEFAULT_VALUE_FEATURES_FAST_TEXT = "¯\\_(ツ)_/¯"
|
const val DEFAULT_VALUE_FEATURES_FAST_TEXT = "¯\\_(ツ)_/¯"
|
||||||
|
|||||||
@@ -1,144 +1,124 @@
|
|||||||
package com.meloda.app.fast.datastore
|
package com.meloda.app.fast.datastore
|
||||||
|
|
||||||
import android.content.res.Resources
|
import com.meloda.app.fast.common.model.DarkMode
|
||||||
import android.os.PowerManager
|
|
||||||
import android.util.Log
|
|
||||||
import com.meloda.app.fast.datastore.model.LongPollState
|
|
||||||
import com.meloda.app.fast.ui.model.ThemeConfig
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
|
||||||
|
|
||||||
interface UserSettings {
|
interface UserSettings {
|
||||||
val theme: StateFlow<ThemeConfig>
|
|
||||||
val longPollStateToApply: StateFlow<LongPollState>
|
|
||||||
val longPollCurrentState: StateFlow<LongPollState>
|
|
||||||
val online: StateFlow<Boolean>
|
|
||||||
val debugSettingsEnabled: StateFlow<Boolean>
|
|
||||||
val useContactNames: StateFlow<Boolean>
|
val useContactNames: StateFlow<Boolean>
|
||||||
val language: StateFlow<String>
|
|
||||||
val enablePullToRefresh: StateFlow<Boolean>
|
val enablePullToRefresh: StateFlow<Boolean>
|
||||||
|
|
||||||
fun updateUsingDarkTheme()
|
val enableMultiline: StateFlow<Boolean>
|
||||||
fun useDarkThemeChanged(use: Boolean)
|
val darkMode: StateFlow<DarkMode>
|
||||||
fun useAmoledThemeChanged(use: Boolean)
|
val enableAmoledDark: StateFlow<Boolean>
|
||||||
fun useDynamicColorsChanged(use: Boolean)
|
val enableDynamicColors: StateFlow<Boolean>
|
||||||
fun useBlurChanged(use: Boolean)
|
val appLanguage: StateFlow<String>
|
||||||
fun useMultiline(use: Boolean)
|
|
||||||
fun setLongPollStateToApply(newState: LongPollState)
|
val fastText: StateFlow<String>
|
||||||
fun updateLongPollCurrentState(currentState: LongPollState)
|
|
||||||
fun setOnline(use: Boolean)
|
val sendOnlineStatus: StateFlow<Boolean>
|
||||||
fun enableDebugSettings(enable: Boolean)
|
|
||||||
|
val showAlertAfterCrash: StateFlow<Boolean>
|
||||||
|
val longPollInBackground: StateFlow<Boolean>
|
||||||
|
val useBlur: StateFlow<Boolean>
|
||||||
|
val showEmojiButton: StateFlow<Boolean>
|
||||||
|
val showDebugCategory: StateFlow<Boolean>
|
||||||
|
|
||||||
fun onUseContactNamesChanged(use: Boolean)
|
fun onUseContactNamesChanged(use: Boolean)
|
||||||
fun onLanguageChanged(newLanguage: String)
|
|
||||||
fun onEnablePullToRefreshChanged(enable: Boolean)
|
fun onEnablePullToRefreshChanged(enable: Boolean)
|
||||||
|
|
||||||
|
fun onEnableMultilineChanged(enable: Boolean)
|
||||||
|
fun onDarkModeChanged(mode: DarkMode)
|
||||||
|
fun onEnableAmoledDarkChanged(enable: Boolean)
|
||||||
|
fun onEnableDynamicColorsChanged(enable: Boolean)
|
||||||
|
fun onAppLanguageChanged(language: String)
|
||||||
|
|
||||||
|
fun onFastTextChanged(text: String)
|
||||||
|
|
||||||
|
fun onSendOnlineStatusChanged(send: Boolean)
|
||||||
|
|
||||||
|
fun onShowAlertAfterCrashChanged(show: Boolean)
|
||||||
|
fun onLongPollInBackgroundChanged(inBackground: Boolean)
|
||||||
|
fun onUseBlurChanged(use: Boolean)
|
||||||
|
fun onShowEmojiButtonChanged(show: Boolean)
|
||||||
|
fun onShowDebugCategoryChanged(show: Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserSettingsImpl(
|
class UserSettingsImpl : UserSettings {
|
||||||
private val resources: Resources,
|
|
||||||
private val powerManager: PowerManager
|
|
||||||
) : UserSettings {
|
|
||||||
|
|
||||||
override val theme = MutableStateFlow(
|
override val useContactNames = MutableStateFlow(AppSettings.General.useContactNames)
|
||||||
ThemeConfig(
|
override val enablePullToRefresh = MutableStateFlow(AppSettings.General.enablePullToRefresh)
|
||||||
usingDarkStyle = isUsingDarkMode(resources, powerManager),
|
|
||||||
usingDynamicColors = isUsingDynamicColors(),
|
|
||||||
selectedColorScheme = selectedColorScheme(),
|
|
||||||
usingAmoledBackground = isUsingAmoledBackground(),
|
|
||||||
usingBlur = isUsingBlur(),
|
|
||||||
isMultiline = isMultiline(),
|
|
||||||
isDeviceCompact = false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
override val longPollStateToApply = MutableStateFlow<LongPollState>(LongPollState.Stopped)
|
override val enableMultiline = MutableStateFlow(AppSettings.Appearance.enableMultiline)
|
||||||
override val longPollCurrentState = MutableStateFlow<LongPollState>(LongPollState.Stopped)
|
override val darkMode = MutableStateFlow(AppSettings.Appearance.darkMode)
|
||||||
|
override val enableAmoledDark = MutableStateFlow(AppSettings.Appearance.enableAmoledDark)
|
||||||
|
override val enableDynamicColors = MutableStateFlow(AppSettings.Appearance.enableDynamicColors)
|
||||||
|
override val appLanguage = MutableStateFlow(AppSettings.Appearance.appLanguage)
|
||||||
|
|
||||||
override val online = MutableStateFlow(
|
override val fastText = MutableStateFlow(AppSettings.Features.fastText)
|
||||||
SettingsController.getBoolean(
|
|
||||||
SettingsKeys.KEY_ACTIVITY_SEND_ONLINE_STATUS,
|
|
||||||
SettingsKeys.DEFAULT_VALUE_KEY_ACTIVITY_SEND_ONLINE_STATUS
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
override val debugSettingsEnabled = MutableStateFlow(
|
override val sendOnlineStatus = MutableStateFlow(AppSettings.Activity.sendOnlineStatus)
|
||||||
SettingsController.getBoolean(
|
|
||||||
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
override val useContactNames = MutableStateFlow(
|
override val showAlertAfterCrash = MutableStateFlow(AppSettings.Debug.showAlertAfterCrash)
|
||||||
SettingsController.getBoolean(
|
override val longPollInBackground = MutableStateFlow(AppSettings.Debug.longPollInBackground)
|
||||||
SettingsKeys.KEY_USE_CONTACT_NAMES,
|
override val useBlur = MutableStateFlow(AppSettings.Debug.useBlur)
|
||||||
SettingsKeys.DEFAULT_VALUE_USE_CONTACT_NAMES
|
override val showEmojiButton = MutableStateFlow(AppSettings.Debug.showEmojiButton)
|
||||||
)
|
override val showDebugCategory = MutableStateFlow(AppSettings.Debug.showDebugCategory)
|
||||||
)
|
|
||||||
|
|
||||||
override val language = MutableStateFlow("")
|
|
||||||
|
|
||||||
override val enablePullToRefresh = MutableStateFlow(SettingsController.enablePullToRefresh)
|
|
||||||
|
|
||||||
override fun updateUsingDarkTheme() {
|
|
||||||
useDarkThemeChanged(
|
|
||||||
isUsingDarkMode(
|
|
||||||
resources = resources,
|
|
||||||
powerManager = powerManager,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun useDarkThemeChanged(use: Boolean) {
|
|
||||||
theme.value = theme.value.copy(
|
|
||||||
usingDarkStyle = use
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun useAmoledThemeChanged(use: Boolean) {
|
|
||||||
theme.value = theme.value.copy(
|
|
||||||
usingAmoledBackground = use
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun useDynamicColorsChanged(use: Boolean) {
|
|
||||||
theme.value = theme.value.copy(usingDynamicColors = use)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun useBlurChanged(use: Boolean) {
|
|
||||||
theme.value = theme.value.copy(usingBlur = use)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun useMultiline(use: Boolean) {
|
|
||||||
theme.value = theme.value.copy(isMultiline = use)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setLongPollStateToApply(newState: LongPollState) {
|
|
||||||
longPollStateToApply.update { newState }
|
|
||||||
Log.d("UserSettings", "setLongPollState: $newState")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateLongPollCurrentState(currentState: LongPollState) {
|
|
||||||
longPollCurrentState.update { currentState }
|
|
||||||
Log.d("UserSettings", "updateLongPollCurrentState: $currentState")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setOnline(use: Boolean) {
|
|
||||||
online.value = use
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun enableDebugSettings(enable: Boolean) {
|
|
||||||
debugSettingsEnabled.update { enable }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onUseContactNamesChanged(use: Boolean) {
|
override fun onUseContactNamesChanged(use: Boolean) {
|
||||||
useContactNames.update { use }
|
useContactNames.value = use
|
||||||
}
|
|
||||||
|
|
||||||
override fun onLanguageChanged(newLanguage: String) {
|
|
||||||
language.update { newLanguage }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onEnablePullToRefreshChanged(enable: Boolean) {
|
override fun onEnablePullToRefreshChanged(enable: Boolean) {
|
||||||
enablePullToRefresh.update { enable }
|
enablePullToRefresh.value = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnableMultilineChanged(enable: Boolean) {
|
||||||
|
enableMultiline.value = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDarkModeChanged(mode: DarkMode) {
|
||||||
|
darkMode.value = mode
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnableAmoledDarkChanged(enable: Boolean) {
|
||||||
|
enableAmoledDark.value = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnableDynamicColorsChanged(enable: Boolean) {
|
||||||
|
enableDynamicColors.value = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAppLanguageChanged(language: String) {
|
||||||
|
appLanguage.value = language
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFastTextChanged(text: String) {
|
||||||
|
fastText.value = text
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSendOnlineStatusChanged(send: Boolean) {
|
||||||
|
sendOnlineStatus.value = send
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onShowAlertAfterCrashChanged(show: Boolean) {
|
||||||
|
showAlertAfterCrash.value = show
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLongPollInBackgroundChanged(inBackground: Boolean) {
|
||||||
|
longPollInBackground.value = inBackground
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUseBlurChanged(use: Boolean) {
|
||||||
|
useBlur.value = use
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onShowEmojiButtonChanged(show: Boolean) {
|
||||||
|
showEmojiButton.value = show
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onShowDebugCategoryChanged(show: Boolean) {
|
||||||
|
showDebugCategory.value = show
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package com.meloda.app.fast.network.interceptor
|
package com.meloda.app.fast.network.interceptor
|
||||||
|
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.meloda.app.fast.common.ApiLanguage
|
import com.meloda.app.fast.common.model.ApiLanguage
|
||||||
import com.meloda.app.fast.common.provider.Provider
|
import com.meloda.app.fast.common.provider.Provider
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.ui.graphics.luminance
|
import androidx.compose.ui.graphics.luminance
|
||||||
import com.meloda.app.fast.ui.theme.LocalIsDarkTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default alpha levels used by Material components.
|
* Default alpha levels used by Material components.
|
||||||
@@ -79,7 +79,7 @@ object ContentAlpha {
|
|||||||
lowContrastAlpha: Float
|
lowContrastAlpha: Float
|
||||||
): Float {
|
): Float {
|
||||||
val contentColor = LocalContentColor.current
|
val contentColor = LocalContentColor.current
|
||||||
return if (!LocalIsDarkTheme.current) {
|
return if (!LocalThemeConfig.current.darkMode) {
|
||||||
if (contentColor.luminance() > 0.5) highContrastAlpha else lowContrastAlpha
|
if (contentColor.luminance() > 0.5) highContrastAlpha else lowContrastAlpha
|
||||||
} else {
|
} else {
|
||||||
if (contentColor.luminance() < 0.5) highContrastAlpha else lowContrastAlpha
|
if (contentColor.luminance() < 0.5) highContrastAlpha else lowContrastAlpha
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.model.UiText
|
||||||
import com.meloda.app.fast.common.parseString
|
import com.meloda.app.fast.common.model.parseString
|
||||||
import com.meloda.app.fast.ui.util.ImmutableList
|
import com.meloda.app.fast.ui.util.ImmutableList
|
||||||
import com.meloda.app.fast.ui.util.ImmutableList.Companion.toImmutableList
|
import com.meloda.app.fast.ui.util.ImmutableList.Companion.toImmutableList
|
||||||
import com.meloda.app.fast.ui.util.getString
|
import com.meloda.app.fast.ui.util.getString
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.meloda.app.fast.ui.model
|
package com.meloda.app.fast.ui.model
|
||||||
|
|
||||||
data class ThemeConfig(
|
data class ThemeConfig(
|
||||||
val usingDarkStyle: Boolean,
|
val darkMode: Boolean,
|
||||||
val usingDynamicColors: Boolean,
|
val dynamicColors: Boolean,
|
||||||
val selectedColorScheme: Int,
|
val selectedColorScheme: Int,
|
||||||
val usingAmoledBackground: Boolean,
|
val amoledDark: Boolean,
|
||||||
val usingBlur: Boolean,
|
val enableBlur: Boolean,
|
||||||
val isMultiline: Boolean,
|
val enableMultiline: Boolean,
|
||||||
val isDeviceCompact: Boolean
|
val isDeviceCompact: Boolean
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import androidx.compose.material3.dynamicDarkColorScheme
|
|||||||
import androidx.compose.material3.dynamicLightColorScheme
|
import androidx.compose.material3.dynamicLightColorScheme
|
||||||
import androidx.compose.material3.lightColorScheme
|
import androidx.compose.material3.lightColorScheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
|
||||||
import androidx.compose.runtime.SideEffect
|
import androidx.compose.runtime.SideEffect
|
||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -104,20 +103,18 @@ private val robotoFonts = FontFamily(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val LocalTheme = compositionLocalOf {
|
val LocalThemeConfig = compositionLocalOf {
|
||||||
ThemeConfig(
|
ThemeConfig(
|
||||||
usingDarkStyle = false,
|
darkMode = false,
|
||||||
usingDynamicColors = false,
|
dynamicColors = false,
|
||||||
selectedColorScheme = 0,
|
selectedColorScheme = 0,
|
||||||
usingAmoledBackground = false,
|
amoledDark = false,
|
||||||
usingBlur = false,
|
enableBlur = false,
|
||||||
isMultiline = false,
|
enableMultiline = false,
|
||||||
isDeviceCompact = false
|
isDeviceCompact = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val LocalIsDarkTheme = compositionLocalOf { false }
|
|
||||||
|
|
||||||
val LocalHazeState = compositionLocalOf {
|
val LocalHazeState = compositionLocalOf {
|
||||||
HazeState()
|
HazeState()
|
||||||
}
|
}
|
||||||
@@ -181,11 +178,9 @@ fun AppTheme(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositionLocalProvider(LocalIsDarkTheme provides useDarkTheme) {
|
|
||||||
MaterialTheme(
|
MaterialTheme(
|
||||||
colorScheme = predefinedColorScheme ?: colorScheme,
|
colorScheme = predefinedColorScheme ?: colorScheme,
|
||||||
typography = typography,
|
typography = typography,
|
||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.meloda.app.fast.ui.util
|
package com.meloda.app.fast.ui.util
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.os.PowerManager
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -10,9 +12,12 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.key.onKeyEvent
|
import androidx.compose.ui.input.key.onKeyEvent
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.meloda.app.fast.common.UiText
|
import androidx.core.content.getSystemService
|
||||||
|
import com.meloda.app.fast.common.model.DarkMode
|
||||||
|
import com.meloda.app.fast.common.model.UiText
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UiText?.getString(): String? {
|
fun UiText?.getString(): String? {
|
||||||
@@ -75,3 +80,19 @@ fun LazyListState.isScrollingUp(): Boolean {
|
|||||||
}
|
}
|
||||||
}.value
|
}.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun isNeedToEnableDarkMode(darkMode: DarkMode): Boolean {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
val appForceDarkMode = darkMode == DarkMode.ENABLED
|
||||||
|
val appBatterySaver = darkMode == DarkMode.AUTO_BATTERY
|
||||||
|
|
||||||
|
val systemUiNightMode = context.resources.configuration.uiMode
|
||||||
|
|
||||||
|
val isSystemBatterySaver = context.getSystemService<PowerManager>()?.isPowerSaveMode == true
|
||||||
|
val isSystemUsingDarkTheme =
|
||||||
|
systemUiNightMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
||||||
|
|
||||||
|
return appForceDarkMode || (appBatterySaver && isSystemBatterySaver) || (!appBatterySaver && isSystemUsingDarkTheme && darkMode == DarkMode.FOLLOW_SYSTEM)
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,18 +4,19 @@ import android.util.Log
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.meloda.app.fast.auth.login.BuildConfig
|
import com.meloda.app.fast.auth.login.BuildConfig
|
||||||
|
import com.meloda.app.fast.common.LongPollController
|
||||||
import com.meloda.app.fast.common.UserConfig
|
import com.meloda.app.fast.common.UserConfig
|
||||||
import com.meloda.app.fast.common.VkConstants
|
import com.meloda.app.fast.common.VkConstants
|
||||||
import com.meloda.app.fast.common.extensions.listenValue
|
import com.meloda.app.fast.common.extensions.listenValue
|
||||||
import com.meloda.app.fast.common.extensions.setValue
|
import com.meloda.app.fast.common.extensions.setValue
|
||||||
import com.meloda.app.fast.common.extensions.updateValue
|
import com.meloda.app.fast.common.extensions.updateValue
|
||||||
|
import com.meloda.app.fast.common.model.LongPollState
|
||||||
import com.meloda.app.fast.data.State
|
import com.meloda.app.fast.data.State
|
||||||
import com.meloda.app.fast.data.api.users.UsersUseCase
|
import com.meloda.app.fast.data.api.users.UsersUseCase
|
||||||
import com.meloda.app.fast.data.db.AccountsRepository
|
import com.meloda.app.fast.data.db.AccountsRepository
|
||||||
import com.meloda.app.fast.data.processState
|
import com.meloda.app.fast.data.processState
|
||||||
import com.meloda.app.fast.datastore.SettingsController
|
import com.meloda.app.fast.datastore.AppSettings
|
||||||
import com.meloda.app.fast.datastore.UserSettings
|
import com.meloda.app.fast.datastore.UserSettings
|
||||||
import com.meloda.app.fast.datastore.model.LongPollState
|
|
||||||
import com.meloda.app.fast.model.database.AccountEntity
|
import com.meloda.app.fast.model.database.AccountEntity
|
||||||
import com.meloda.app.fast.network.OAuthErrorDomain
|
import com.meloda.app.fast.network.OAuthErrorDomain
|
||||||
import com.meloda.fast.auth.login.model.CaptchaArguments
|
import com.meloda.fast.auth.login.model.CaptchaArguments
|
||||||
@@ -71,7 +72,8 @@ class LoginViewModelImpl(
|
|||||||
private val usersUseCase: UsersUseCase,
|
private val usersUseCase: UsersUseCase,
|
||||||
private val accountsRepository: AccountsRepository,
|
private val accountsRepository: AccountsRepository,
|
||||||
private val loginValidator: LoginValidator,
|
private val loginValidator: LoginValidator,
|
||||||
private val userSettings: UserSettings
|
private val userSettings: UserSettings,
|
||||||
|
private val longPollController: LongPollController
|
||||||
) : ViewModel(), LoginViewModel {
|
) : ViewModel(), LoginViewModel {
|
||||||
|
|
||||||
override val screenState = MutableStateFlow(LoginScreenState.EMPTY)
|
override val screenState = MutableStateFlow(LoginScreenState.EMPTY)
|
||||||
@@ -347,8 +349,8 @@ class LoginViewModelImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startLongPoll() {
|
private fun startLongPoll() {
|
||||||
userSettings.setLongPollStateToApply(
|
longPollController.setStateToApply(
|
||||||
if (SettingsController.isLongPollInBackgroundEnabled) {
|
if (AppSettings.Debug.longPollInBackground) {
|
||||||
LongPollState.Background
|
LongPollState.Background
|
||||||
} else {
|
} else {
|
||||||
LongPollState.InApp
|
LongPollState.InApp
|
||||||
|
|||||||
+3
-3
@@ -50,13 +50,13 @@ import androidx.compose.ui.text.input.TextFieldValue
|
|||||||
import androidx.compose.ui.text.input.VisualTransformation
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.model.UiText
|
||||||
import com.meloda.app.fast.ui.basic.autoFillRequestHandler
|
import com.meloda.app.fast.ui.basic.autoFillRequestHandler
|
||||||
import com.meloda.app.fast.ui.basic.connectNode
|
import com.meloda.app.fast.ui.basic.connectNode
|
||||||
import com.meloda.app.fast.ui.basic.defaultFocusChangeAutoFill
|
import com.meloda.app.fast.ui.basic.defaultFocusChangeAutoFill
|
||||||
import com.meloda.app.fast.ui.components.MaterialDialog
|
import com.meloda.app.fast.ui.components.MaterialDialog
|
||||||
import com.meloda.app.fast.ui.components.TextFieldErrorText
|
import com.meloda.app.fast.ui.components.TextFieldErrorText
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import com.meloda.app.fast.ui.util.handleEnterKey
|
import com.meloda.app.fast.ui.util.handleEnterKey
|
||||||
import com.meloda.app.fast.ui.util.handleTabKey
|
import com.meloda.app.fast.ui.util.handleTabKey
|
||||||
import com.meloda.fast.auth.login.LoginViewModel
|
import com.meloda.fast.auth.login.LoginViewModel
|
||||||
@@ -157,7 +157,7 @@ fun LoginScreen(
|
|||||||
onPasswordFieldGoAction: () -> Unit = {},
|
onPasswordFieldGoAction: () -> Unit = {},
|
||||||
onSignInButtonClicked: () -> Unit = {}
|
onSignInButtonClicked: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
val (loginFocusable, passwordFocusable) = FocusRequester.createRefs()
|
val (loginFocusable, passwordFocusable) = FocusRequester.createRefs()
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -31,7 +31,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import com.meloda.fast.auth.login.LoginViewModel
|
import com.meloda.fast.auth.login.LoginViewModel
|
||||||
import com.meloda.fast.auth.login.LoginViewModelImpl
|
import com.meloda.fast.auth.login.LoginViewModelImpl
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
@@ -64,7 +64,7 @@ fun LogoScreen(
|
|||||||
onLogoLongClicked: () -> Unit = {},
|
onLogoLongClicked: () -> Unit = {},
|
||||||
onGoNextButtonClicked: () -> Unit = {}
|
onGoNextButtonClicked: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
Scaffold { padding ->
|
Scaffold { padding ->
|
||||||
val topPadding by animateDpAsState(
|
val topPadding by animateDpAsState(
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ import androidx.navigation.compose.composable
|
|||||||
import androidx.navigation.toRoute
|
import androidx.navigation.toRoute
|
||||||
import com.meloda.app.fast.auth.validation.model.ValidationArguments
|
import com.meloda.app.fast.auth.validation.model.ValidationArguments
|
||||||
import com.meloda.app.fast.auth.validation.presentation.ValidationRoute
|
import com.meloda.app.fast.auth.validation.presentation.ValidationRoute
|
||||||
import com.meloda.app.fast.common.customNavType
|
import com.meloda.app.fast.common.extensions.customNavType
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlin.reflect.typeOf
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -66,7 +66,7 @@ import com.meloda.app.fast.chatmaterials.ChatMaterialsViewModelImpl
|
|||||||
import com.meloda.app.fast.chatmaterials.model.ChatMaterialsScreenState
|
import com.meloda.app.fast.chatmaterials.model.ChatMaterialsScreenState
|
||||||
import com.meloda.app.fast.datastore.UserSettings
|
import com.meloda.app.fast.datastore.UserSettings
|
||||||
import com.meloda.app.fast.ui.R
|
import com.meloda.app.fast.ui.R
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import dev.chrisbanes.haze.HazeState
|
import dev.chrisbanes.haze.HazeState
|
||||||
import dev.chrisbanes.haze.haze
|
import dev.chrisbanes.haze.haze
|
||||||
import dev.chrisbanes.haze.hazeChild
|
import dev.chrisbanes.haze.hazeChild
|
||||||
@@ -110,7 +110,7 @@ fun ChatMaterialsScreen(
|
|||||||
onRefreshDropdownItemClicked: () -> Unit = {},
|
onRefreshDropdownItemClicked: () -> Unit = {},
|
||||||
onRefresh: () -> Unit = {}
|
onRefresh: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
val attachments = screenState.materials
|
val attachments = screenState.materials
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ fun ChatMaterialsScreen(
|
|||||||
Log.d("ChatMaterialsScreen", "ChatMaterialsScreen: canScrollBackward: $canScrollBackward")
|
Log.d("ChatMaterialsScreen", "ChatMaterialsScreen: canScrollBackward: $canScrollBackward")
|
||||||
|
|
||||||
val topBarContainerColorAlpha by animateFloatAsState(
|
val topBarContainerColorAlpha by animateFloatAsState(
|
||||||
targetValue = if (!currentTheme.usingBlur || !canScrollBackward) 1f else 0f,
|
targetValue = if (!currentTheme.enableBlur || !canScrollBackward) 1f else 0f,
|
||||||
label = "toolbarColorAlpha",
|
label = "toolbarColorAlpha",
|
||||||
animationSpec = tween(
|
animationSpec = tween(
|
||||||
durationMillis = 200,
|
durationMillis = 200,
|
||||||
@@ -164,7 +164,7 @@ fun ChatMaterialsScreen(
|
|||||||
|
|
||||||
val topBarContainerColor by animateColorAsState(
|
val topBarContainerColor by animateColorAsState(
|
||||||
targetValue =
|
targetValue =
|
||||||
if (currentTheme.usingBlur || !canScrollBackward)
|
if (currentTheme.enableBlur || !canScrollBackward)
|
||||||
MaterialTheme.colorScheme.surface
|
MaterialTheme.colorScheme.surface
|
||||||
else
|
else
|
||||||
MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
|
MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
|
||||||
@@ -182,7 +182,7 @@ fun ChatMaterialsScreen(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.then(
|
.then(
|
||||||
if (currentTheme.usingBlur) {
|
if (currentTheme.enableBlur) {
|
||||||
Modifier.hazeChild(
|
Modifier.hazeChild(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = hazeStyle
|
style = hazeStyle
|
||||||
@@ -244,7 +244,7 @@ fun ChatMaterialsScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (currentTheme.usingBlur) {
|
if (currentTheme.enableBlur) {
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = {
|
text = {
|
||||||
Text(text = if (moreClearBlur) "Default blur" else "Clearer blur")
|
Text(text = if (moreClearBlur) "Default blur" else "Clearer blur")
|
||||||
@@ -300,7 +300,7 @@ fun ChatMaterialsScreen(
|
|||||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.then(
|
.then(
|
||||||
if (currentTheme.usingBlur) {
|
if (currentTheme.enableBlur) {
|
||||||
Modifier.haze(
|
Modifier.haze(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = hazeStyle
|
style = hazeStyle
|
||||||
@@ -331,7 +331,7 @@ fun ChatMaterialsScreen(
|
|||||||
state = listState,
|
state = listState,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.then(
|
.then(
|
||||||
if (currentTheme.usingBlur) {
|
if (currentTheme.enableBlur) {
|
||||||
Modifier.haze(
|
Modifier.haze(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = hazeStyle
|
style = hazeStyle
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
package com.meloda.app.fast.conversations.model
|
package com.meloda.app.fast.conversations.model
|
||||||
|
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.model.UiText
|
||||||
import com.meloda.app.fast.ui.R as UiR
|
import com.meloda.app.fast.ui.R as UiR
|
||||||
|
|
||||||
sealed class ConversationOption(
|
sealed class ConversationOption(
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ package com.meloda.app.fast.conversations.model
|
|||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
import com.meloda.app.fast.model.api.PeerType
|
import com.meloda.app.fast.model.api.PeerType
|
||||||
import com.meloda.app.fast.model.api.domain.VkMessage
|
import com.meloda.app.fast.model.api.domain.VkMessage
|
||||||
import com.meloda.app.fast.ui.util.ImmutableList
|
import com.meloda.app.fast.ui.util.ImmutableList
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
import com.meloda.app.fast.conversations.model.ConversationOption
|
import com.meloda.app.fast.conversations.model.ConversationOption
|
||||||
import com.meloda.app.fast.conversations.model.UiConversation
|
import com.meloda.app.fast.conversations.model.UiConversation
|
||||||
import com.meloda.app.fast.ui.basic.ContentAlpha
|
import com.meloda.app.fast.ui.basic.ContentAlpha
|
||||||
|
|||||||
+7
-7
@@ -78,7 +78,7 @@ import com.meloda.app.fast.ui.components.FullScreenLoader
|
|||||||
import com.meloda.app.fast.ui.components.MaterialDialog
|
import com.meloda.app.fast.ui.components.MaterialDialog
|
||||||
import com.meloda.app.fast.ui.theme.LocalBottomPadding
|
import com.meloda.app.fast.ui.theme.LocalBottomPadding
|
||||||
import com.meloda.app.fast.ui.theme.LocalHazeState
|
import com.meloda.app.fast.ui.theme.LocalHazeState
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import com.meloda.app.fast.ui.util.isScrollingUp
|
import com.meloda.app.fast.ui.util.isScrollingUp
|
||||||
import dev.chrisbanes.haze.haze
|
import dev.chrisbanes.haze.haze
|
||||||
import dev.chrisbanes.haze.hazeChild
|
import dev.chrisbanes.haze.hazeChild
|
||||||
@@ -159,10 +159,10 @@ fun ConversationsScreen(
|
|||||||
onRefresh: () -> Unit = {}
|
onRefresh: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
val maxLines by remember(currentTheme) {
|
val maxLines by remember(currentTheme) {
|
||||||
mutableIntStateOf(if (currentTheme.isMultiline) 2 else 1)
|
mutableIntStateOf(if (currentTheme.enableMultiline) 2 else 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
@@ -195,7 +195,7 @@ fun ConversationsScreen(
|
|||||||
|
|
||||||
val toolbarContainerColor by animateColorAsState(
|
val toolbarContainerColor by animateColorAsState(
|
||||||
targetValue =
|
targetValue =
|
||||||
if (currentTheme.usingBlur || !listState.canScrollBackward)
|
if (currentTheme.enableBlur || !listState.canScrollBackward)
|
||||||
MaterialTheme.colorScheme.surface
|
MaterialTheme.colorScheme.surface
|
||||||
else
|
else
|
||||||
MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
|
MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
|
||||||
@@ -258,12 +258,12 @@ fun ConversationsScreen(
|
|||||||
},
|
},
|
||||||
colors = TopAppBarDefaults.topAppBarColors(
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
containerColor = toolbarContainerColor.copy(
|
containerColor = toolbarContainerColor.copy(
|
||||||
alpha = if (currentTheme.usingBlur) toolbarColorAlpha else 1f
|
alpha = if (currentTheme.enableBlur) toolbarColorAlpha else 1f
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.then(
|
.then(
|
||||||
if (currentTheme.usingBlur) {
|
if (currentTheme.enableBlur) {
|
||||||
Modifier.hazeChild(
|
Modifier.hazeChild(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = HazeMaterials.thick()
|
style = HazeMaterials.thick()
|
||||||
@@ -355,7 +355,7 @@ fun ConversationsScreen(
|
|||||||
screenState = screenState,
|
screenState = screenState,
|
||||||
state = listState,
|
state = listState,
|
||||||
maxLines = maxLines,
|
maxLines = maxLines,
|
||||||
modifier = if (currentTheme.usingBlur) {
|
modifier = if (currentTheme.enableBlur) {
|
||||||
Modifier.haze(
|
Modifier.haze(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = HazeMaterials.thick()
|
style = HazeMaterials.thick()
|
||||||
|
|||||||
+3
-3
@@ -9,11 +9,11 @@ import androidx.compose.ui.text.font.FontWeight
|
|||||||
import androidx.compose.ui.text.withStyle
|
import androidx.compose.ui.text.withStyle
|
||||||
import com.conena.nanokt.jvm.util.dayOfMonth
|
import com.conena.nanokt.jvm.util.dayOfMonth
|
||||||
import com.conena.nanokt.jvm.util.month
|
import com.conena.nanokt.jvm.util.month
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.model.UiText
|
||||||
import com.meloda.app.fast.common.UserConfig
|
import com.meloda.app.fast.common.UserConfig
|
||||||
import com.meloda.app.fast.common.extensions.orDots
|
import com.meloda.app.fast.common.extensions.orDots
|
||||||
import com.meloda.app.fast.common.parseString
|
import com.meloda.app.fast.common.model.parseString
|
||||||
import com.meloda.app.fast.common.util.TimeUtils
|
import com.meloda.app.fast.common.util.TimeUtils
|
||||||
import com.meloda.app.fast.conversations.model.ActionState
|
import com.meloda.app.fast.conversations.model.ActionState
|
||||||
import com.meloda.app.fast.conversations.model.UiConversation
|
import com.meloda.app.fast.conversations.model.UiConversation
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.meloda.app.fast.friends.model
|
package com.meloda.app.fast.friends.model
|
||||||
|
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
import com.meloda.app.fast.model.api.domain.OnlineStatus
|
import com.meloda.app.fast.model.api.domain.OnlineStatus
|
||||||
|
|
||||||
data class UiFriend(
|
data class UiFriend(
|
||||||
|
|||||||
+7
-7
@@ -59,7 +59,7 @@ import com.meloda.app.fast.ui.components.FullScreenLoader
|
|||||||
import com.meloda.app.fast.ui.components.NoItemsView
|
import com.meloda.app.fast.ui.components.NoItemsView
|
||||||
import com.meloda.app.fast.ui.model.TabItem
|
import com.meloda.app.fast.ui.model.TabItem
|
||||||
import com.meloda.app.fast.ui.theme.LocalHazeState
|
import com.meloda.app.fast.ui.theme.LocalHazeState
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import com.meloda.app.fast.ui.util.ImmutableList
|
import com.meloda.app.fast.ui.util.ImmutableList
|
||||||
import dev.chrisbanes.haze.haze
|
import dev.chrisbanes.haze.haze
|
||||||
import dev.chrisbanes.haze.hazeChild
|
import dev.chrisbanes.haze.hazeChild
|
||||||
@@ -122,11 +122,11 @@ fun FriendsScreen(
|
|||||||
onPaginationConditionsMet: () -> Unit = {},
|
onPaginationConditionsMet: () -> Unit = {},
|
||||||
onRefresh: () -> Unit = {}
|
onRefresh: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
val maxLines by remember {
|
val maxLines by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (currentTheme.isMultiline) 2 else 1
|
if (currentTheme.enableMultiline) 2 else 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ fun FriendsScreen(
|
|||||||
val hazeState = LocalHazeState.current
|
val hazeState = LocalHazeState.current
|
||||||
|
|
||||||
val topBarContainerColorAlpha by animateFloatAsState(
|
val topBarContainerColorAlpha by animateFloatAsState(
|
||||||
targetValue = if (!currentTheme.usingBlur || !listState.canScrollBackward) 1f else 0f,
|
targetValue = if (!currentTheme.enableBlur || !listState.canScrollBackward) 1f else 0f,
|
||||||
label = "toolbarColorAlpha",
|
label = "toolbarColorAlpha",
|
||||||
animationSpec = tween(
|
animationSpec = tween(
|
||||||
durationMillis = 200,
|
durationMillis = 200,
|
||||||
@@ -159,7 +159,7 @@ fun FriendsScreen(
|
|||||||
|
|
||||||
val topBarContainerColor by animateColorAsState(
|
val topBarContainerColor by animateColorAsState(
|
||||||
targetValue =
|
targetValue =
|
||||||
if (currentTheme.usingBlur || !listState.canScrollBackward)
|
if (currentTheme.enableBlur || !listState.canScrollBackward)
|
||||||
MaterialTheme.colorScheme.surface
|
MaterialTheme.colorScheme.surface
|
||||||
else
|
else
|
||||||
MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
|
MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
|
||||||
@@ -196,7 +196,7 @@ fun FriendsScreen(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.then(
|
.then(
|
||||||
if (currentTheme.usingBlur) {
|
if (currentTheme.enableBlur) {
|
||||||
Modifier.hazeChild(
|
Modifier.hazeChild(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = HazeMaterials.thick()
|
style = HazeMaterials.thick()
|
||||||
@@ -295,7 +295,7 @@ fun FriendsScreen(
|
|||||||
val friendsToDisplay = screenState.friends
|
val friendsToDisplay = screenState.friends
|
||||||
|
|
||||||
FriendsList(
|
FriendsList(
|
||||||
modifier = if (currentTheme.usingBlur) {
|
modifier = if (currentTheme.enableBlur) {
|
||||||
Modifier.haze(
|
Modifier.haze(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = HazeMaterials.thick()
|
style = HazeMaterials.thick()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.meloda.app.fast.friends.util
|
package com.meloda.app.fast.friends.util
|
||||||
|
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
import com.meloda.app.fast.data.VkMemoryCache
|
import com.meloda.app.fast.data.VkMemoryCache
|
||||||
import com.meloda.app.fast.friends.model.UiFriend
|
import com.meloda.app.fast.friends.model.UiFriend
|
||||||
import com.meloda.app.fast.model.api.domain.VkUser
|
import com.meloda.app.fast.model.api.domain.VkUser
|
||||||
|
|||||||
+2
-2
@@ -4,9 +4,9 @@ import android.content.res.Resources
|
|||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.core.os.LocaleListCompat
|
import androidx.core.os.LocaleListCompat
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.model.UiText
|
||||||
import com.meloda.app.fast.common.extensions.setValue
|
import com.meloda.app.fast.common.extensions.setValue
|
||||||
import com.meloda.app.fast.common.parseString
|
import com.meloda.app.fast.common.model.parseString
|
||||||
import com.meloda.app.fast.languagepicker.model.LanguagePickerScreenState
|
import com.meloda.app.fast.languagepicker.model.LanguagePickerScreenState
|
||||||
import com.meloda.app.fast.languagepicker.model.SelectableLanguage
|
import com.meloda.app.fast.languagepicker.model.SelectableLanguage
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package com.meloda.app.fast.messageshistory.model
|
package com.meloda.app.fast.messageshistory.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
import com.meloda.app.fast.model.api.domain.VkAttachment
|
import com.meloda.app.fast.model.api.domain.VkAttachment
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package com.meloda.app.fast.messageshistory.model
|
package com.meloda.app.fast.messageshistory.model
|
||||||
|
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
|
|
||||||
data class UiMessage(
|
data class UiMessage(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import androidx.navigation.NavController
|
|||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.toRoute
|
import androidx.navigation.toRoute
|
||||||
import com.meloda.app.fast.common.customNavType
|
import com.meloda.app.fast.common.extensions.customNavType
|
||||||
import com.meloda.app.fast.messageshistory.model.MessagesHistoryArguments
|
import com.meloda.app.fast.messageshistory.model.MessagesHistoryArguments
|
||||||
import com.meloda.app.fast.messageshistory.presentation.MessagesHistoryRoute
|
import com.meloda.app.fast.messageshistory.presentation.MessagesHistoryRoute
|
||||||
import com.meloda.app.fast.model.BaseError
|
import com.meloda.app.fast.model.BaseError
|
||||||
|
|||||||
+4
-4
@@ -72,7 +72,7 @@ import com.meloda.app.fast.messageshistory.MessagesHistoryViewModelImpl
|
|||||||
import com.meloda.app.fast.messageshistory.model.ActionMode
|
import com.meloda.app.fast.messageshistory.model.ActionMode
|
||||||
import com.meloda.app.fast.messageshistory.model.MessagesHistoryScreenState
|
import com.meloda.app.fast.messageshistory.model.MessagesHistoryScreenState
|
||||||
import com.meloda.app.fast.model.BaseError
|
import com.meloda.app.fast.model.BaseError
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import com.meloda.app.fast.ui.util.ImmutableList
|
import com.meloda.app.fast.ui.util.ImmutableList
|
||||||
import dev.chrisbanes.haze.HazeState
|
import dev.chrisbanes.haze.HazeState
|
||||||
import dev.chrisbanes.haze.hazeChild
|
import dev.chrisbanes.haze.hazeChild
|
||||||
@@ -131,7 +131,7 @@ fun MessagesHistoryScreen(
|
|||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
|
|
||||||
val preferences: SharedPreferences = koinInject()
|
val preferences: SharedPreferences = koinInject()
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ fun MessagesHistoryScreen(
|
|||||||
TopAppBar(
|
TopAppBar(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.then(
|
.then(
|
||||||
if (currentTheme.usingBlur) {
|
if (currentTheme.enableBlur) {
|
||||||
Modifier.hazeChild(
|
Modifier.hazeChild(
|
||||||
state = hazeSate,
|
state = hazeSate,
|
||||||
style = HazeMaterials.thick()
|
style = HazeMaterials.thick()
|
||||||
@@ -203,7 +203,7 @@ fun MessagesHistoryScreen(
|
|||||||
},
|
},
|
||||||
colors = TopAppBarDefaults.topAppBarColors(
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
containerColor = MaterialTheme.colorScheme.surface.copy(
|
containerColor = MaterialTheme.colorScheme.surface.copy(
|
||||||
alpha = if (currentTheme.usingBlur) toolbarColorAlpha else 1f
|
alpha = if (currentTheme.enableBlur) toolbarColorAlpha else 1f
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
actions = {
|
actions = {
|
||||||
|
|||||||
+3
-3
@@ -17,7 +17,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.meloda.app.fast.messageshistory.model.UiMessage
|
import com.meloda.app.fast.messageshistory.model.UiMessage
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import com.meloda.app.fast.ui.util.ImmutableList
|
import com.meloda.app.fast.ui.util.ImmutableList
|
||||||
import dev.chrisbanes.haze.HazeState
|
import dev.chrisbanes.haze.HazeState
|
||||||
import dev.chrisbanes.haze.haze
|
import dev.chrisbanes.haze.haze
|
||||||
@@ -35,13 +35,13 @@ fun MessagesList(
|
|||||||
enableAnimations: Boolean
|
enableAnimations: Boolean
|
||||||
) {
|
) {
|
||||||
val messages = immutableMessages.toList()
|
val messages = immutableMessages.toList()
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.then(
|
.then(
|
||||||
if (currentTheme.usingBlur) {
|
if (currentTheme.enableBlur) {
|
||||||
Modifier.haze(
|
Modifier.haze(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = HazeMaterials.regular()
|
style = HazeMaterials.regular()
|
||||||
|
|||||||
+3
-3
@@ -1,11 +1,11 @@
|
|||||||
package com.meloda.app.fast.messageshistory.util
|
package com.meloda.app.fast.messageshistory.util
|
||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.model.UiText
|
||||||
import com.meloda.app.fast.common.UserConfig
|
import com.meloda.app.fast.common.UserConfig
|
||||||
import com.meloda.app.fast.common.extensions.orDots
|
import com.meloda.app.fast.common.extensions.orDots
|
||||||
import com.meloda.app.fast.common.parseString
|
import com.meloda.app.fast.common.model.parseString
|
||||||
import com.meloda.app.fast.data.VkMemoryCache
|
import com.meloda.app.fast.data.VkMemoryCache
|
||||||
import com.meloda.app.fast.ui.R
|
import com.meloda.app.fast.ui.R
|
||||||
import com.meloda.app.fast.messageshistory.model.UiMessage
|
import com.meloda.app.fast.messageshistory.model.UiMessage
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package com.meloda.app.fast.photoviewer.model
|
package com.meloda.app.fast.photoviewer.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class PhotoViewArguments(
|
data class PhotoViewArguments(
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package com.meloda.app.fast.photoviewer.model
|
package com.meloda.app.fast.photoviewer.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class PhotoViewState(
|
data class PhotoViewState(
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@ import androidx.compose.ui.unit.DpOffset
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import com.meloda.app.fast.common.UiImage
|
import com.meloda.app.fast.common.model.UiImage
|
||||||
import com.meloda.app.fast.photoviewer.PhotoViewViewModel
|
import com.meloda.app.fast.photoviewer.PhotoViewViewModel
|
||||||
import com.meloda.app.fast.photoviewer.model.PhotoViewState
|
import com.meloda.app.fast.photoviewer.model.PhotoViewState
|
||||||
|
|
||||||
|
|||||||
+109
-94
@@ -6,17 +6,18 @@ import androidx.appcompat.app.AppCompatDelegate
|
|||||||
import androidx.core.view.HapticFeedbackConstantsCompat
|
import androidx.core.view.HapticFeedbackConstantsCompat
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.LongPollController
|
||||||
import com.meloda.app.fast.common.UserConfig
|
import com.meloda.app.fast.common.UserConfig
|
||||||
import com.meloda.app.fast.common.extensions.findWithIndex
|
import com.meloda.app.fast.common.extensions.findWithIndex
|
||||||
import com.meloda.app.fast.common.extensions.isSdkAtLeast
|
import com.meloda.app.fast.common.extensions.isSdkAtLeast
|
||||||
import com.meloda.app.fast.common.extensions.setValue
|
import com.meloda.app.fast.common.extensions.setValue
|
||||||
|
import com.meloda.app.fast.common.model.DarkMode
|
||||||
|
import com.meloda.app.fast.common.model.LongPollState
|
||||||
|
import com.meloda.app.fast.common.model.UiText
|
||||||
import com.meloda.app.fast.data.db.AccountsRepository
|
import com.meloda.app.fast.data.db.AccountsRepository
|
||||||
import com.meloda.app.fast.datastore.SettingsController
|
import com.meloda.app.fast.datastore.AppSettings
|
||||||
import com.meloda.app.fast.datastore.SettingsKeys
|
import com.meloda.app.fast.datastore.SettingsKeys
|
||||||
import com.meloda.app.fast.datastore.UserSettings
|
import com.meloda.app.fast.datastore.UserSettings
|
||||||
import com.meloda.app.fast.datastore.isDebugSettingsShown
|
|
||||||
import com.meloda.app.fast.datastore.model.LongPollState
|
|
||||||
import com.meloda.app.fast.model.database.AccountEntity
|
import com.meloda.app.fast.model.database.AccountEntity
|
||||||
import com.meloda.app.fast.settings.model.SettingsItem
|
import com.meloda.app.fast.settings.model.SettingsItem
|
||||||
import com.meloda.app.fast.settings.model.SettingsScreenState
|
import com.meloda.app.fast.settings.model.SettingsScreenState
|
||||||
@@ -32,8 +33,7 @@ import com.meloda.app.fast.ui.R as UiR
|
|||||||
interface SettingsViewModel {
|
interface SettingsViewModel {
|
||||||
|
|
||||||
val screenState: StateFlow<SettingsScreenState>
|
val screenState: StateFlow<SettingsScreenState>
|
||||||
|
val hapticType: StateFlow<HapticType?>
|
||||||
val isLongPollBackgroundEnabled: StateFlow<Boolean?>
|
|
||||||
|
|
||||||
fun onLogOutAlertDismissed()
|
fun onLogOutAlertDismissed()
|
||||||
fun onLogOutAlertPositiveClick()
|
fun onLogOutAlertPositiveClick()
|
||||||
@@ -46,22 +46,20 @@ interface SettingsViewModel {
|
|||||||
fun onSettingsItemChanged(key: String, newValue: Any?)
|
fun onSettingsItemChanged(key: String, newValue: Any?)
|
||||||
|
|
||||||
fun onHapticPerformed()
|
fun onHapticPerformed()
|
||||||
|
|
||||||
fun onNotificationsPermissionRequested()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SettingsViewModelImpl(
|
class SettingsViewModelImpl(
|
||||||
private val accountsRepository: AccountsRepository,
|
private val accountsRepository: AccountsRepository,
|
||||||
private val userSettings: UserSettings,
|
private val userSettings: UserSettings,
|
||||||
private val resources: Resources
|
private val resources: Resources,
|
||||||
|
private val longPollController: LongPollController
|
||||||
) : SettingsViewModel, ViewModel() {
|
) : SettingsViewModel, ViewModel() {
|
||||||
|
|
||||||
override val screenState = MutableStateFlow(SettingsScreenState.EMPTY)
|
override val screenState = MutableStateFlow(SettingsScreenState.EMPTY)
|
||||||
|
override val hapticType = MutableStateFlow<HapticType?>(null)
|
||||||
|
|
||||||
private val settings = MutableStateFlow<List<SettingsItem<*>>>(emptyList())
|
private val settings = MutableStateFlow<List<SettingsItem<*>>>(emptyList())
|
||||||
|
|
||||||
override val isLongPollBackgroundEnabled = MutableStateFlow<Boolean?>(null)
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
createSettings()
|
createSettings()
|
||||||
}
|
}
|
||||||
@@ -106,22 +104,15 @@ class SettingsViewModelImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingsKeys.KEY_DEBUG_HIDE_DEBUG_LIST -> {
|
SettingsKeys.KEY_DEBUG_HIDE_DEBUG_LIST -> {
|
||||||
val showDebugCategory = isDebugSettingsShown()
|
val showDebugCategory = AppSettings.Debug.showDebugCategory
|
||||||
if (!showDebugCategory) return
|
if (!showDebugCategory) return
|
||||||
|
|
||||||
SettingsController.put(
|
onSettingsItemChanged(key, false)
|
||||||
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
createSettings()
|
createSettings()
|
||||||
|
|
||||||
screenState.setValue { old ->
|
hapticType.update { HapticType.REJECT }
|
||||||
old.copy(
|
screenState.setValue { old -> old.copy(showDebugOptions = false) }
|
||||||
useHaptics = HapticType.REJECT,
|
|
||||||
showDebugOptions = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,18 +120,14 @@ class SettingsViewModelImpl(
|
|||||||
override fun onSettingsItemLongClicked(key: String) {
|
override fun onSettingsItemLongClicked(key: String) {
|
||||||
when (key) {
|
when (key) {
|
||||||
SettingsKeys.KEY_ACTIVITY_SEND_ONLINE_STATUS -> {
|
SettingsKeys.KEY_ACTIVITY_SEND_ONLINE_STATUS -> {
|
||||||
if (isDebugSettingsShown()) return
|
if (AppSettings.Debug.showDebugCategory) return
|
||||||
|
|
||||||
SettingsController.put(SettingsKeys.KEY_SHOW_DEBUG_CATEGORY, true)
|
onSettingsItemChanged(key, true)
|
||||||
|
|
||||||
createSettings()
|
createSettings()
|
||||||
|
|
||||||
screenState.setValue { old ->
|
hapticType.update { HapticType.LONG_PRESS }
|
||||||
old.copy(
|
screenState.setValue { old -> old.copy(showDebugOptions = true) }
|
||||||
useHaptics = HapticType.LONG_PRESS,
|
|
||||||
showDebugOptions = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,70 +147,98 @@ class SettingsViewModelImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
when (key) {
|
when (key) {
|
||||||
SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND -> {
|
|
||||||
val isEnabled = (newValue as? Boolean) == true
|
|
||||||
userSettings.setLongPollStateToApply(
|
|
||||||
userSettings.longPollStateToApply.value.let { state ->
|
|
||||||
if (state.isLaunched()) {
|
|
||||||
if (isEnabled) LongPollState.Background
|
|
||||||
else LongPollState.InApp
|
|
||||||
} else state
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (isEnabled) {
|
|
||||||
// TODO: 26/11/2023, Danil Nikolaev: implement
|
|
||||||
val isNotificationsPermissionGranted = false
|
|
||||||
|
|
||||||
if (!isNotificationsPermissionGranted) {
|
|
||||||
// TODO: 26/11/2023, Danil Nikolaev: implement restart
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsKeys.KEY_APPEARANCE_MULTILINE -> {
|
|
||||||
val isUsing = newValue as? Boolean ?: false
|
|
||||||
userSettings.useMultiline(isUsing)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsKeys.KEY_APPEARANCE_AMOLED_THEME -> {
|
|
||||||
val isUsing = newValue as? Boolean ?: false
|
|
||||||
userSettings.useAmoledThemeChanged(isUsing)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsKeys.KEY_USE_DYNAMIC_COLORS -> {
|
|
||||||
val isUsing = newValue as? Boolean ?: false
|
|
||||||
userSettings.useDynamicColorsChanged(isUsing)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsKeys.KEY_APPEARANCE_BLUR -> {
|
|
||||||
val isUsing = newValue as? Boolean ?: false
|
|
||||||
userSettings.useBlurChanged(isUsing)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsKeys.KEY_ACTIVITY_SEND_ONLINE_STATUS -> {
|
|
||||||
val isUsing = newValue as? Boolean ?: false
|
|
||||||
userSettings.setOnline(isUsing)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsKeys.KEY_USE_CONTACT_NAMES -> {
|
SettingsKeys.KEY_USE_CONTACT_NAMES -> {
|
||||||
val isUsing = newValue as? Boolean ?: false
|
val isUsing = newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_USE_CONTACT_NAMES
|
||||||
userSettings.onUseContactNamesChanged(isUsing)
|
userSettings.onUseContactNamesChanged(isUsing)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsKeys.KEY_ENABLE_PULL_TO_REFRESH -> {
|
SettingsKeys.KEY_ENABLE_PULL_TO_REFRESH -> {
|
||||||
val enable = newValue as? Boolean ?: false
|
val enable =
|
||||||
|
newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_ENABLE_PULL_TO_REFRESH
|
||||||
userSettings.onEnablePullToRefreshChanged(enable)
|
userSettings.onEnablePullToRefreshChanged(enable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingsKeys.KEY_APPEARANCE_MULTILINE -> {
|
||||||
|
val isUsing = newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_MULTILINE
|
||||||
|
userSettings.onEnableMultilineChanged(isUsing)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsKeys.KEY_APPEARANCE_DARK_MODE -> {
|
||||||
|
val newMode = newValue as? Int ?: SettingsKeys.DEFAULT_VALUE_APPEARANCE_DARK_MODE
|
||||||
|
AppCompatDelegate.setDefaultNightMode(newMode)
|
||||||
|
userSettings.onDarkModeChanged(DarkMode.parse(newMode))
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsKeys.KEY_APPEARANCE_AMOLED_THEME -> {
|
||||||
|
val isUsing =
|
||||||
|
newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_APPEARANCE_AMOLED_THEME
|
||||||
|
userSettings.onEnableAmoledDarkChanged(isUsing)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsKeys.KEY_USE_DYNAMIC_COLORS -> {
|
||||||
|
val isUsing = newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_USE_DYNAMIC_COLORS
|
||||||
|
userSettings.onEnableDynamicColorsChanged(isUsing)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsKeys.KEY_APPEARANCE_LANGUAGE -> {
|
||||||
|
val newLanguage = newValue as? String ?: SettingsKeys.DEFAULT_APPEARANCE_LANGUAGE
|
||||||
|
userSettings.onAppLanguageChanged(newLanguage)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingsKeys.DEFAULT_VALUE_FEATURES_FAST_TEXT -> {
|
||||||
|
val newText = newValue as? String ?: SettingsKeys.DEFAULT_VALUE_FEATURES_FAST_TEXT
|
||||||
|
userSettings.onFastTextChanged(newText)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingsKeys.KEY_ACTIVITY_SEND_ONLINE_STATUS -> {
|
||||||
|
val isUsing = newValue as? Boolean
|
||||||
|
?: SettingsKeys.DEFAULT_VALUE_KEY_ACTIVITY_SEND_ONLINE_STATUS
|
||||||
|
userSettings.onSendOnlineStatusChanged(isUsing)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsKeys.KEY_DEBUG_SHOW_CRASH_ALERT -> {
|
||||||
|
val show = newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_KEY_SHOW_EMOJI_BUTTON
|
||||||
|
userSettings.onShowAlertAfterCrashChanged(show)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND -> {
|
||||||
|
val inBackground = newValue as? Boolean
|
||||||
|
?: SettingsKeys.DEFAULT_VALUE_FEATURES_LONG_POLL_IN_BACKGROUND
|
||||||
|
userSettings.onLongPollInBackgroundChanged(inBackground)
|
||||||
|
|
||||||
|
longPollController.setStateToApply(
|
||||||
|
longPollController.stateToApply.value.let { state ->
|
||||||
|
if (state.isLaunched()) {
|
||||||
|
if (inBackground) LongPollState.Background
|
||||||
|
else LongPollState.InApp
|
||||||
|
} else state
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsKeys.KEY_APPEARANCE_USE_BLUR -> {
|
||||||
|
val isUsing =
|
||||||
|
newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_KEY_APPEARANCE_USE_BLUR
|
||||||
|
userSettings.onUseBlurChanged(isUsing)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsKeys.KEY_SHOW_EMOJI_BUTTON -> {
|
||||||
|
val show = newValue as? Boolean ?: SettingsKeys.DEFAULT_VALUE_KEY_SHOW_EMOJI_BUTTON
|
||||||
|
userSettings.onShowEmojiButtonChanged(show)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY -> {
|
||||||
|
val show = newValue as? Boolean ?: false
|
||||||
|
userSettings.onShowDebugCategoryChanged(show)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onHapticPerformed() {
|
override fun onHapticPerformed() {
|
||||||
screenState.setValue { old -> old.copy(useHaptics = null) }
|
hapticType.update { null }
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNotificationsPermissionRequested() {
|
|
||||||
screenState.setValue { old -> old.copy(isNeedToRequestNotificationPermission = false) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun emitShowOptions(function: (SettingsShowOptions) -> SettingsShowOptions) {
|
private fun emitShowOptions(function: (SettingsShowOptions) -> SettingsShowOptions) {
|
||||||
@@ -273,22 +288,22 @@ class SettingsViewModelImpl(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val darkThemeValues = listOf(
|
val darkThemeValues = listOf(
|
||||||
AppCompatDelegate.MODE_NIGHT_YES to UiText.Resource(UiR.string.settings_dark_theme_value_enabled),
|
DarkMode.ENABLED to UiText.Resource(UiR.string.settings_dark_theme_value_enabled),
|
||||||
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM to UiText.Resource(UiR.string.settings_dark_theme_value_follow_system),
|
DarkMode.FOLLOW_SYSTEM to UiText.Resource(UiR.string.settings_dark_theme_value_follow_system),
|
||||||
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY to UiText.Resource(UiR.string.settings_dark_theme_value_battery_saver),
|
DarkMode.AUTO_BATTERY to UiText.Resource(UiR.string.settings_dark_theme_value_battery_saver),
|
||||||
AppCompatDelegate.MODE_NIGHT_NO to UiText.Resource(UiR.string.settings_dark_theme_value_disabled)
|
DarkMode.DISABLED to UiText.Resource(UiR.string.settings_dark_theme_value_disabled)
|
||||||
).toMap()
|
).toMap()
|
||||||
|
|
||||||
val appearanceDarkTheme = SettingsItem.ListItem(
|
val appearanceDarkTheme = SettingsItem.ListItem(
|
||||||
key = SettingsKeys.KEY_APPEARANCE_DARK_THEME,
|
key = SettingsKeys.KEY_APPEARANCE_DARK_MODE,
|
||||||
title = UiText.Resource(UiR.string.settings_dark_theme),
|
title = UiText.Resource(UiR.string.settings_dark_theme),
|
||||||
valueClass = Int::class,
|
valueClass = Int::class,
|
||||||
defaultValue = SettingsKeys.DEFAULT_VALUE_APPEARANCE_DARK_THEME,
|
defaultValue = SettingsKeys.DEFAULT_VALUE_APPEARANCE_DARK_MODE,
|
||||||
titles = darkThemeValues.values.toList(),
|
titles = darkThemeValues.values.toList(),
|
||||||
values = darkThemeValues.keys.toList()
|
values = darkThemeValues.keys.toList().map(DarkMode::value)
|
||||||
).apply {
|
).apply {
|
||||||
textProvider = TextProvider { item ->
|
textProvider = TextProvider { item ->
|
||||||
val darkThemeValue = darkThemeValues[item.value]
|
val darkThemeValue = darkThemeValues[DarkMode.parse(item.value)]
|
||||||
|
|
||||||
UiText.ResourceParams(
|
UiText.ResourceParams(
|
||||||
value = UiR.string.settings_dark_theme_current_value,
|
value = UiR.string.settings_dark_theme_current_value,
|
||||||
@@ -368,8 +383,8 @@ class SettingsViewModelImpl(
|
|||||||
text = UiText.Simple("Shows alert dialog with stacktrace after app crashed\n(it will be not shown if you perform crash manually)")
|
text = UiText.Simple("Shows alert dialog with stacktrace after app crashed\n(it will be not shown if you perform crash manually)")
|
||||||
)
|
)
|
||||||
val debugUseBlur = SettingsItem.Switch(
|
val debugUseBlur = SettingsItem.Switch(
|
||||||
key = SettingsKeys.KEY_APPEARANCE_BLUR,
|
key = SettingsKeys.KEY_APPEARANCE_USE_BLUR,
|
||||||
defaultValue = SettingsKeys.DEFAULT_VALUE_KEY_APPEARANCE_BLUR,
|
defaultValue = SettingsKeys.DEFAULT_VALUE_KEY_APPEARANCE_USE_BLUR,
|
||||||
title = UiText.Simple("[WIP] Use blur"),
|
title = UiText.Simple("[WIP] Use blur"),
|
||||||
text = UiText.Simple("Adds blur wherever possible\nOn android 11 and older will have transparency instead of blurring"),
|
text = UiText.Simple("Adds blur wherever possible\nOn android 11 and older will have transparency instead of blurring"),
|
||||||
)
|
)
|
||||||
@@ -432,7 +447,7 @@ class SettingsViewModelImpl(
|
|||||||
debugList,
|
debugList,
|
||||||
).forEach(settingsList::addAll)
|
).forEach(settingsList::addAll)
|
||||||
|
|
||||||
if (!isDebugSettingsShown()) {
|
if (!AppSettings.Debug.showDebugCategory) {
|
||||||
settingsList.removeAll(debugList)
|
settingsList.removeAll(debugList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package com.meloda.app.fast.settings.model
|
|||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.model.UiText
|
||||||
import com.meloda.app.fast.common.parseString
|
import com.meloda.app.fast.common.model.parseString
|
||||||
import com.meloda.app.fast.datastore.SettingsController
|
import com.meloda.app.fast.datastore.AppSettings
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -37,7 +37,7 @@ sealed class SettingsItem<T>(
|
|||||||
protected set(newValue) {
|
protected set(newValue) {
|
||||||
field = newValue
|
field = newValue
|
||||||
|
|
||||||
SettingsController.put(key, newValue)
|
AppSettings.put(key, newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
var title: UiText? = null
|
var title: UiText? = null
|
||||||
@@ -165,7 +165,7 @@ sealed class SettingsItem<T>(
|
|||||||
val values: List<T>
|
val values: List<T>
|
||||||
) : SettingsItem<T>(
|
) : SettingsItem<T>(
|
||||||
key = key,
|
key = key,
|
||||||
value = selectedValue ?: SettingsController.get(valueClass, key, defaultValue),
|
value = selectedValue ?: AppSettings.get(valueClass, key, defaultValue),
|
||||||
defaultValue = defaultValue
|
defaultValue = defaultValue
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -245,6 +245,6 @@ private inline fun <reified T> getCurrentValue(key: String, defaultValue: T): T
|
|||||||
if (T::class == Nothing::class) {
|
if (T::class == Nothing::class) {
|
||||||
throw IllegalStateException("Items with Nothing does not have a value")
|
throw IllegalStateException("Items with Nothing does not have a value")
|
||||||
} else {
|
} else {
|
||||||
return SettingsController.get(key, defaultValue)
|
return AppSettings.get(key, defaultValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-7
@@ -1,15 +1,12 @@
|
|||||||
package com.meloda.app.fast.settings.model
|
package com.meloda.app.fast.settings.model
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.meloda.app.fast.datastore.isDebugSettingsShown
|
import com.meloda.app.fast.datastore.AppSettings
|
||||||
import com.meloda.app.fast.settings.HapticType
|
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class SettingsScreenState(
|
data class SettingsScreenState(
|
||||||
val showOptions: SettingsShowOptions,
|
val showOptions: SettingsShowOptions,
|
||||||
val settings: List<UiItem>,
|
val settings: List<UiItem>,
|
||||||
val useHaptics: HapticType?,
|
|
||||||
val isNeedToRequestNotificationPermission: Boolean,
|
|
||||||
val showDebugOptions: Boolean
|
val showDebugOptions: Boolean
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -17,9 +14,7 @@ data class SettingsScreenState(
|
|||||||
val EMPTY: SettingsScreenState = SettingsScreenState(
|
val EMPTY: SettingsScreenState = SettingsScreenState(
|
||||||
showOptions = SettingsShowOptions.EMPTY,
|
showOptions = SettingsShowOptions.EMPTY,
|
||||||
settings = emptyList(),
|
settings = emptyList(),
|
||||||
useHaptics = null,
|
showDebugOptions = AppSettings.Debug.showDebugCategory
|
||||||
isNeedToRequestNotificationPermission = false,
|
|
||||||
showDebugOptions = isDebugSettingsShown()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.meloda.app.fast.settings.model
|
package com.meloda.app.fast.settings.model
|
||||||
|
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.model.UiText
|
||||||
|
|
||||||
fun interface TextProvider<T, S : SettingsItem<T>> {
|
fun interface TextProvider<T, S : SettingsItem<T>> {
|
||||||
fun provideText(item: S): UiText?
|
fun provideText(item: S): UiText?
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package com.meloda.app.fast.settings.model
|
package com.meloda.app.fast.settings.model
|
||||||
|
|
||||||
import com.meloda.app.fast.common.UiText
|
import com.meloda.app.fast.common.model.UiText
|
||||||
|
|
||||||
fun interface TitleProvider<T, S : SettingsItem<T>> {
|
fun interface TitleProvider<T, S : SettingsItem<T>> {
|
||||||
fun provideTitle(item: S): UiText?
|
fun provideTitle(item: S): UiText?
|
||||||
|
|||||||
+12
-40
@@ -1,7 +1,5 @@
|
|||||||
package com.meloda.app.fast.settings.presentation
|
package com.meloda.app.fast.settings.presentation
|
||||||
|
|
||||||
import android.os.PowerManager
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.calculateEndPadding
|
import androidx.compose.foundation.layout.calculateEndPadding
|
||||||
@@ -27,17 +25,14 @@ import androidx.compose.runtime.LaunchedEffect
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.core.content.getSystemService
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.meloda.app.fast.common.UserConfig
|
import com.meloda.app.fast.common.UserConfig
|
||||||
import com.meloda.app.fast.datastore.SettingsKeys
|
import com.meloda.app.fast.datastore.SettingsKeys
|
||||||
import com.meloda.app.fast.datastore.UserSettings
|
import com.meloda.app.fast.settings.HapticType
|
||||||
import com.meloda.app.fast.datastore.isUsingDarkMode
|
|
||||||
import com.meloda.app.fast.settings.SettingsViewModel
|
import com.meloda.app.fast.settings.SettingsViewModel
|
||||||
import com.meloda.app.fast.settings.SettingsViewModelImpl
|
import com.meloda.app.fast.settings.SettingsViewModelImpl
|
||||||
import com.meloda.app.fast.settings.model.SettingsScreenState
|
import com.meloda.app.fast.settings.model.SettingsScreenState
|
||||||
@@ -49,14 +44,13 @@ import com.meloda.app.fast.settings.presentation.item.TitleItem
|
|||||||
import com.meloda.app.fast.settings.presentation.item.TitleTextItem
|
import com.meloda.app.fast.settings.presentation.item.TitleTextItem
|
||||||
import com.meloda.app.fast.ui.components.ActionInvokeDismiss
|
import com.meloda.app.fast.ui.components.ActionInvokeDismiss
|
||||||
import com.meloda.app.fast.ui.components.MaterialDialog
|
import com.meloda.app.fast.ui.components.MaterialDialog
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import dev.chrisbanes.haze.HazeState
|
import dev.chrisbanes.haze.HazeState
|
||||||
import dev.chrisbanes.haze.haze
|
import dev.chrisbanes.haze.haze
|
||||||
import dev.chrisbanes.haze.hazeChild
|
import dev.chrisbanes.haze.hazeChild
|
||||||
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
||||||
import dev.chrisbanes.haze.materials.HazeMaterials
|
import dev.chrisbanes.haze.materials.HazeMaterials
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
import org.koin.compose.koinInject
|
|
||||||
import com.meloda.app.fast.ui.R as UiR
|
import com.meloda.app.fast.ui.R as UiR
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -66,16 +60,12 @@ fun SettingsRoute(
|
|||||||
onLanguageItemClicked: () -> Unit,
|
onLanguageItemClicked: () -> Unit,
|
||||||
viewModel: SettingsViewModel = koinViewModel<SettingsViewModelImpl>()
|
viewModel: SettingsViewModel = koinViewModel<SettingsViewModelImpl>()
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
|
||||||
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
|
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
|
||||||
|
val hapticType by viewModel.hapticType.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
val userSettings: UserSettings = koinInject()
|
SettingsScreen(
|
||||||
|
screenState = screenState,
|
||||||
LaunchedEffect(true) {
|
hapticType = hapticType,
|
||||||
userSettings.enableDebugSettings(screenState.showDebugOptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsScreen(screenState = screenState,
|
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onHapticPerformed = viewModel::onHapticPerformed,
|
onHapticPerformed = viewModel::onHapticPerformed,
|
||||||
onSettingsItemClicked = { key ->
|
onSettingsItemClicked = { key ->
|
||||||
@@ -88,25 +78,7 @@ fun SettingsRoute(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSettingsItemLongClicked = viewModel::onSettingsItemLongClicked,
|
onSettingsItemLongClicked = viewModel::onSettingsItemLongClicked,
|
||||||
onSettingsItemValueChanged = { key, newValue ->
|
onSettingsItemValueChanged = viewModel::onSettingsItemChanged
|
||||||
viewModel.onSettingsItemChanged(key, newValue)
|
|
||||||
|
|
||||||
when (key) {
|
|
||||||
SettingsKeys.KEY_APPEARANCE_DARK_THEME -> {
|
|
||||||
val newMode = newValue as? Int ?: 0
|
|
||||||
AppCompatDelegate.setDefaultNightMode(newMode)
|
|
||||||
|
|
||||||
val isUsing = context.getSystemService<PowerManager>()?.let { manager ->
|
|
||||||
isUsingDarkMode(
|
|
||||||
context.resources,
|
|
||||||
manager
|
|
||||||
)
|
|
||||||
} ?: false
|
|
||||||
|
|
||||||
userSettings.useDarkThemeChanged(isUsing)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
HandlePopups(
|
HandlePopups(
|
||||||
@@ -128,6 +100,7 @@ fun SettingsRoute(
|
|||||||
@Composable
|
@Composable
|
||||||
fun SettingsScreen(
|
fun SettingsScreen(
|
||||||
screenState: SettingsScreenState = SettingsScreenState.EMPTY,
|
screenState: SettingsScreenState = SettingsScreenState.EMPTY,
|
||||||
|
hapticType: HapticType? = null,
|
||||||
onBack: () -> Unit = {},
|
onBack: () -> Unit = {},
|
||||||
onHapticPerformed: () -> Unit = {},
|
onHapticPerformed: () -> Unit = {},
|
||||||
onSettingsItemClicked: (key: String) -> Unit = {},
|
onSettingsItemClicked: (key: String) -> Unit = {},
|
||||||
@@ -135,7 +108,6 @@ fun SettingsScreen(
|
|||||||
onSettingsItemValueChanged: (key: String, newValue: Any?) -> Unit = { _, _ -> }
|
onSettingsItemValueChanged: (key: String, newValue: Any?) -> Unit = { _, _ -> }
|
||||||
) {
|
) {
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
val hapticType = screenState.useHaptics
|
|
||||||
|
|
||||||
LaunchedEffect(hapticType) {
|
LaunchedEffect(hapticType) {
|
||||||
if (hapticType != null) {
|
if (hapticType != null) {
|
||||||
@@ -144,7 +116,7 @@ fun SettingsScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentTheme = LocalTheme.current
|
val themeConfig = LocalThemeConfig.current
|
||||||
|
|
||||||
val hazeState = remember { HazeState() }
|
val hazeState = remember { HazeState() }
|
||||||
|
|
||||||
@@ -164,12 +136,12 @@ fun SettingsScreen(
|
|||||||
},
|
},
|
||||||
colors = TopAppBarDefaults.topAppBarColors(
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
containerColor = MaterialTheme.colorScheme.surface.copy(
|
containerColor = MaterialTheme.colorScheme.surface.copy(
|
||||||
alpha = if (currentTheme.usingBlur) 0f else 1f
|
alpha = if (themeConfig.enableBlur) 0f else 1f
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.then(
|
.then(
|
||||||
if (currentTheme.usingBlur) {
|
if (themeConfig.enableBlur) {
|
||||||
Modifier.hazeChild(
|
Modifier.hazeChild(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = HazeMaterials.thick()
|
style = HazeMaterials.thick()
|
||||||
@@ -185,7 +157,7 @@ fun SettingsScreen(
|
|||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.then(
|
.then(
|
||||||
if (currentTheme.usingBlur) {
|
if (themeConfig.enableBlur) {
|
||||||
Modifier.haze(
|
Modifier.haze(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = HazeMaterials.thick()
|
style = HazeMaterials.thick()
|
||||||
|
|||||||
+4
-4
@@ -32,7 +32,7 @@ import com.meloda.app.fast.ui.basic.LocalContentAlpha
|
|||||||
import com.meloda.app.fast.ui.components.ActionInvokeDismiss
|
import com.meloda.app.fast.ui.components.ActionInvokeDismiss
|
||||||
import com.meloda.app.fast.ui.components.MaterialDialog
|
import com.meloda.app.fast.ui.components.MaterialDialog
|
||||||
import com.meloda.app.fast.ui.components.SelectionType
|
import com.meloda.app.fast.ui.components.SelectionType
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import com.meloda.app.fast.ui.util.ImmutableList
|
import com.meloda.app.fast.ui.util.ImmutableList
|
||||||
import com.meloda.app.fast.ui.util.ImmutableList.Companion.toImmutableList
|
import com.meloda.app.fast.ui.util.ImmutableList.Companion.toImmutableList
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ fun ListItem(
|
|||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@@ -81,7 +81,7 @@ fun ListItem(
|
|||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
maxLines = if (currentTheme.isMultiline) Int.MAX_VALUE else 1,
|
maxLines = if (currentTheme.enableMultiline) Int.MAX_VALUE else 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ fun ListItem(
|
|||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
maxLines = if (currentTheme.isMultiline) Int.MAX_VALUE else 1,
|
maxLines = if (currentTheme.enableMultiline) Int.MAX_VALUE else 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -22,7 +22,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import com.meloda.app.fast.settings.model.UiItem
|
import com.meloda.app.fast.settings.model.UiItem
|
||||||
import com.meloda.app.fast.ui.basic.ContentAlpha
|
import com.meloda.app.fast.ui.basic.ContentAlpha
|
||||||
import com.meloda.app.fast.ui.basic.LocalContentAlpha
|
import com.meloda.app.fast.ui.basic.LocalContentAlpha
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -35,7 +35,7 @@ fun SwitchItem(
|
|||||||
) {
|
) {
|
||||||
if (!item.isVisible) return
|
if (!item.isVisible) return
|
||||||
|
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@@ -65,7 +65,7 @@ fun SwitchItem(
|
|||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
maxLines = if (currentTheme.isMultiline) Int.MAX_VALUE else 1,
|
maxLines = if (currentTheme.enableMultiline) Int.MAX_VALUE else 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@ fun SwitchItem(
|
|||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
maxLines = if (currentTheme.isMultiline) Int.MAX_VALUE else 1,
|
maxLines = if (currentTheme.enableMultiline) Int.MAX_VALUE else 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -38,7 +38,7 @@ import com.meloda.app.fast.ui.basic.ContentAlpha
|
|||||||
import com.meloda.app.fast.ui.basic.LocalContentAlpha
|
import com.meloda.app.fast.ui.basic.LocalContentAlpha
|
||||||
import com.meloda.app.fast.ui.components.ActionInvokeDismiss
|
import com.meloda.app.fast.ui.components.ActionInvokeDismiss
|
||||||
import com.meloda.app.fast.ui.components.MaterialDialog
|
import com.meloda.app.fast.ui.components.MaterialDialog
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -51,7 +51,7 @@ fun TextFieldItem(
|
|||||||
) {
|
) {
|
||||||
if (!item.isVisible) return
|
if (!item.isVisible) return
|
||||||
|
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
var showDialog by rememberSaveable {
|
var showDialog by rememberSaveable {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
@@ -93,7 +93,7 @@ fun TextFieldItem(
|
|||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
maxLines = if (currentTheme.isMultiline) Int.MAX_VALUE else 1,
|
maxLines = if (currentTheme.enableMultiline) Int.MAX_VALUE else 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ fun TextFieldItem(
|
|||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
maxLines = if (currentTheme.isMultiline) Int.MAX_VALUE else 1,
|
maxLines = if (currentTheme.enableMultiline) Int.MAX_VALUE else 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -9,7 +9,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.meloda.app.fast.settings.model.UiItem
|
import com.meloda.app.fast.settings.model.UiItem
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TitleItem(
|
fun TitleItem(
|
||||||
@@ -18,7 +18,7 @@ fun TitleItem(
|
|||||||
) {
|
) {
|
||||||
if (!item.isVisible) return
|
if (!item.isVisible) return
|
||||||
|
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = item.title,
|
text = item.title,
|
||||||
@@ -32,7 +32,7 @@ fun TitleItem(
|
|||||||
bottom = 4.dp
|
bottom = 4.dp
|
||||||
)
|
)
|
||||||
.animateContentSize(),
|
.animateContentSize(),
|
||||||
maxLines = if (currentTheme.isMultiline) Int.MAX_VALUE else 1,
|
maxLines = if (currentTheme.enableMultiline) Int.MAX_VALUE else 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -21,7 +21,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import com.meloda.app.fast.settings.model.UiItem
|
import com.meloda.app.fast.settings.model.UiItem
|
||||||
import com.meloda.app.fast.ui.basic.ContentAlpha
|
import com.meloda.app.fast.ui.basic.ContentAlpha
|
||||||
import com.meloda.app.fast.ui.basic.LocalContentAlpha
|
import com.meloda.app.fast.ui.basic.LocalContentAlpha
|
||||||
import com.meloda.app.fast.ui.theme.LocalTheme
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -33,7 +33,7 @@ fun TitleTextItem(
|
|||||||
) {
|
) {
|
||||||
if (!item.isVisible) return
|
if (!item.isVisible) return
|
||||||
|
|
||||||
val currentTheme = LocalTheme.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@@ -62,7 +62,7 @@ fun TitleTextItem(
|
|||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
maxLines = if (currentTheme.isMultiline) Int.MAX_VALUE else 1,
|
maxLines = if (currentTheme.enableMultiline) Int.MAX_VALUE else 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ fun TitleTextItem(
|
|||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
maxLines = if (currentTheme.isMultiline) Int.MAX_VALUE else 1,
|
maxLines = if (currentTheme.enableMultiline) Int.MAX_VALUE else 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user