Get rid of LiveData
This commit is contained in:
parent
0e40355ae1
commit
d1482ad112
@ -68,7 +68,6 @@ dependencies {
|
||||
implementation(libs.bundles.kotlin)
|
||||
|
||||
implementation(libs.androidx.compose.runtime)
|
||||
implementation(libs.androidx.compose.livedata)
|
||||
implementation(libs.androidx.compose.foundation)
|
||||
implementation(libs.androidx.compose.foundationlayout)
|
||||
implementation(libs.androidx.compose.ui)
|
||||
|
||||
@ -58,19 +58,6 @@
|
||||
android:value="de.mm20.launcher2.ui.launcher.SharedLauncherActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".launcher.widgets.picker.PickAppWidgetActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:parentActivityName=".launcher.SharedLauncherActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:taskAffinity="de.mm20.launcher2.settings"
|
||||
android:theme="@style/SettingsTheme.NoActionBar">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="de.mm20.launcher2.ui.launcher.SharedLauncherActivity" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".launcher.sheets.BindAndConfigureAppWidgetActivity"
|
||||
/>
|
||||
|
||||
@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
@ -178,8 +177,8 @@ fun AssistantScaffold(
|
||||
|
||||
val value by searchVM.searchQuery
|
||||
|
||||
val searchBarColor by viewModel.searchBarColor.observeAsState(Settings.SearchBarSettings.SearchBarColors.Auto)
|
||||
val searchBarStyle by viewModel.searchBarStyle.observeAsState(Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
||||
val searchBarColor by viewModel.searchBarColor.collectAsState()
|
||||
val searchBarStyle by viewModel.searchBarStyle.collectAsState()
|
||||
|
||||
val launchOnEnter by searchVM.launchOnEnter.collectAsState(false)
|
||||
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
package de.mm20.launcher2.ui.base
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
class BaseActivityVM : ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val theme = dataStore.data.map { it.appearance.theme }.asLiveData()
|
||||
|
||||
fun getTheme(): Settings.AppearanceSettings.Theme = runBlocking {
|
||||
dataStore.data.map { it.appearance.theme }.first()
|
||||
}
|
||||
|
||||
val colorScheme = dataStore.data.map { it.appearance.colorScheme }.asLiveData()
|
||||
|
||||
fun getColorScheme(): Settings.AppearanceSettings.ColorScheme = runBlocking {
|
||||
dataStore.data.map { it.appearance.colorScheme }.first()
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,6 @@ import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -38,9 +37,9 @@ fun RestoreBackupSheet(
|
||||
viewModel.setInputUri(uri)
|
||||
}
|
||||
|
||||
val state by viewModel.state.observeAsState(RestoreBackupState.Parsing)
|
||||
val selectedComponents by viewModel.selectedComponents.observeAsState(emptySet())
|
||||
val compatibility by viewModel.compatibility.observeAsState(null)
|
||||
val state by viewModel.state
|
||||
val selectedComponents by viewModel.selectedComponents
|
||||
val compatibility by viewModel.compatibility
|
||||
|
||||
BottomSheetDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
@ -103,7 +102,7 @@ fun RestoreBackupSheet(
|
||||
)
|
||||
}
|
||||
RestoreBackupState.Ready -> {
|
||||
val metadata by viewModel.metadata.observeAsState(null)
|
||||
val metadata by viewModel.metadata
|
||||
|
||||
if (metadata != null) {
|
||||
Column {
|
||||
@ -153,9 +152,7 @@ fun RestoreBackupSheet(
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
modifier = Modifier.padding(top = 8.dp, bottom = 4.dp)
|
||||
)
|
||||
val components by viewModel.availableComponents.observeAsState(
|
||||
emptyList()
|
||||
)
|
||||
val components by viewModel.availableComponents
|
||||
for (component in components) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package de.mm20.launcher2.ui.common
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.backup.BackupCompatibility
|
||||
@ -18,12 +18,12 @@ class RestoreBackupSheetVM : ViewModel(), KoinComponent {
|
||||
|
||||
private var restoreUri: Uri? = null
|
||||
|
||||
val state = MutableLiveData(RestoreBackupState.Parsing)
|
||||
val metadata = MutableLiveData<BackupMetadata?>(null)
|
||||
val compatibility = MutableLiveData<BackupCompatibility?>(null)
|
||||
val selectedComponents = MutableLiveData(setOf<BackupComponent>())
|
||||
val state = mutableStateOf(RestoreBackupState.Parsing)
|
||||
val metadata = mutableStateOf<BackupMetadata?>(null)
|
||||
val compatibility = mutableStateOf<BackupCompatibility?>(null)
|
||||
val selectedComponents = mutableStateOf(setOf<BackupComponent>())
|
||||
|
||||
val availableComponents = MutableLiveData(emptyList<BackupComponent>())
|
||||
val availableComponents = mutableStateOf(emptyList<BackupComponent>())
|
||||
|
||||
fun setInputUri(uri: Uri) {
|
||||
restoreUri = uri
|
||||
|
||||
@ -12,7 +12,6 @@ import androidx.compose.material.icons.rounded.Error
|
||||
import androidx.compose.material.icons.rounded.Search
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@ -29,8 +28,8 @@ fun WeatherLocationSearchDialog(
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val viewModel: WeatherLocationSearchDialogVM = viewModel()
|
||||
val isSearching by viewModel.isSearchingLocation.observeAsState(initial = false)
|
||||
val locations by viewModel.locationResults.observeAsState(emptyList())
|
||||
val isSearching by viewModel.isSearchingLocation
|
||||
val locations by viewModel.locationResults
|
||||
|
||||
BottomSheetDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package de.mm20.launcher2.ui.common
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import de.mm20.launcher2.weather.WeatherLocation
|
||||
import de.mm20.launcher2.weather.WeatherRepository
|
||||
@ -12,8 +12,8 @@ import kotlin.coroutines.coroutineContext
|
||||
class WeatherLocationSearchDialogVM: ViewModel(), KoinComponent {
|
||||
private val repository: WeatherRepository by inject()
|
||||
|
||||
val isSearchingLocation = MutableLiveData(false)
|
||||
val locationResults = MutableLiveData<List<WeatherLocation>>(emptyList())
|
||||
val isSearchingLocation = mutableStateOf(false)
|
||||
val locationResults = mutableStateOf<List<WeatherLocation>>(emptyList())
|
||||
|
||||
private var debounceSearchJob: Job? = null
|
||||
suspend fun searchLocation(query: String) {
|
||||
@ -34,7 +34,7 @@ class WeatherLocationSearchDialogVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
fun setLocation(location: WeatherLocation) {
|
||||
locationResults.postValue(emptyList())
|
||||
locationResults.value = emptyList()
|
||||
repository.setAutoLocation(false)
|
||||
repository.setLocation(location)
|
||||
}
|
||||
|
||||
@ -6,9 +6,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.searchable.SearchableRepository
|
||||
import de.mm20.launcher2.globalactions.GlobalActionsService
|
||||
@ -48,13 +46,17 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||
) { dim, theme, systemDarkMode ->
|
||||
dim && (theme == Settings.AppearanceSettings.Theme.Dark || theme == Settings.AppearanceSettings.Theme.System && systemDarkMode)
|
||||
}
|
||||
val dimBackground = dimBackgroundState.asLiveData()
|
||||
val dimBackground = dimBackgroundState.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
val statusBarColor = dataStore.data.map { it.systemBars.statusBarColor }.asLiveData()
|
||||
val navBarColor = dataStore.data.map { it.systemBars.statusBarColor }.asLiveData()
|
||||
val statusBarColor = dataStore.data.map { it.systemBars.statusBarColor }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val navBarColor = dataStore.data.map { it.systemBars.statusBarColor }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }.asLiveData()
|
||||
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }.asLiveData()
|
||||
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
fun setSystemInDarkMode(darkMode: Boolean) {
|
||||
isSystemInDarkMode.value = darkMode
|
||||
@ -62,15 +64,19 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||
|
||||
val baseLayout = dataStore.data.map { it.layout.baseLayout }
|
||||
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
||||
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }.asLiveData()
|
||||
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }.asLiveData()
|
||||
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }.asLiveData()
|
||||
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }.asLiveData()
|
||||
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
|
||||
val isSearchOpen = MutableLiveData(false)
|
||||
val isWidgetEditMode = MutableLiveData(false)
|
||||
val isSearchOpen = mutableStateOf(false)
|
||||
val isWidgetEditMode = mutableStateOf(false)
|
||||
|
||||
val searchBarFocused = MutableLiveData(false)
|
||||
val searchBarFocused = mutableStateOf(false)
|
||||
|
||||
|
||||
val autoFocusSearch = dataStore.data.map { it.searchBar.autoFocus }
|
||||
@ -103,10 +109,14 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
|
||||
isWidgetEditMode.value = editMode
|
||||
}
|
||||
|
||||
val wallpaperBlur = dataStore.data.map { it.appearance.blurWallpaper }.asLiveData()
|
||||
val fillClockHeight = dataStore.data.map { it.clockWidget.fillHeight }.asLiveData()
|
||||
val searchBarColor = dataStore.data.map { it.searchBar.color }.asLiveData()
|
||||
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }.asLiveData()
|
||||
val wallpaperBlur = dataStore.data.map { it.appearance.blurWallpaper }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
||||
val fillClockHeight = dataStore.data.map { it.clockWidget.fillHeight }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
|
||||
val searchBarColor = dataStore.data.map { it.searchBar.color }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Settings.SearchBarSettings.SearchBarColors.Auto)
|
||||
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
||||
|
||||
val gestureState: StateFlow<GestureState> = dataStore
|
||||
.data.map { it.gestures }
|
||||
|
||||
@ -46,7 +46,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
@ -101,8 +100,8 @@ fun PagerScaffold(
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
val isSearchOpen by viewModel.isSearchOpen.observeAsState(false)
|
||||
val isWidgetEditMode by viewModel.isWidgetEditMode.observeAsState(false)
|
||||
val isSearchOpen by viewModel.isSearchOpen
|
||||
val isWidgetEditMode by viewModel.isWidgetEditMode
|
||||
|
||||
val actions by searchVM.searchActionResults
|
||||
|
||||
@ -147,7 +146,7 @@ fun PagerScaffold(
|
||||
}
|
||||
}
|
||||
|
||||
val fillClockHeight by viewModel.fillClockHeight.observeAsState(true)
|
||||
val fillClockHeight by viewModel.fillClockHeight.collectAsState()
|
||||
|
||||
val showNavBarScrim by remember {
|
||||
derivedStateOf {
|
||||
@ -199,7 +198,7 @@ fun PagerScaffold(
|
||||
}
|
||||
}
|
||||
|
||||
val blurEnabled by viewModel.wallpaperBlur.observeAsState(false)
|
||||
val blurEnabled by viewModel.wallpaperBlur.collectAsState()
|
||||
|
||||
val blurWallpaper by remember {
|
||||
derivedStateOf {
|
||||
@ -369,11 +368,17 @@ fun PagerScaffold(
|
||||
.fillMaxHeight()
|
||||
.pointerInput(gestureManager.shouldDetectDoubleTaps) {
|
||||
detectTapGestures(
|
||||
onDoubleTap = if (gestureManager.shouldDetectDoubleTaps) {{
|
||||
if (!isWidgetEditMode) gestureManager.dispatchDoubleTap(it)
|
||||
}} else null,
|
||||
onDoubleTap = if (gestureManager.shouldDetectDoubleTaps) {
|
||||
{
|
||||
if (!isWidgetEditMode) gestureManager.dispatchDoubleTap(
|
||||
it
|
||||
)
|
||||
}
|
||||
} else null,
|
||||
onLongPress = {
|
||||
if (!isWidgetEditMode) gestureManager.dispatchLongPress(it)
|
||||
if (!isWidgetEditMode) gestureManager.dispatchLongPress(
|
||||
it
|
||||
)
|
||||
},
|
||||
onTap = {
|
||||
if (!isWidgetEditMode) gestureManager.dispatchTap(it)
|
||||
@ -491,7 +496,7 @@ fun PagerScaffold(
|
||||
}
|
||||
}
|
||||
|
||||
val focusSearchBar by viewModel.searchBarFocused.observeAsState(false)
|
||||
val focusSearchBar by viewModel.searchBarFocused
|
||||
|
||||
val widgetEditModeOffset by animateDpAsState(
|
||||
(if (isWidgetEditMode) 128.dp else 0.dp) * (if (bottomSearchBar) 1 else -1)
|
||||
@ -499,8 +504,8 @@ fun PagerScaffold(
|
||||
|
||||
val value by searchVM.searchQuery
|
||||
|
||||
val searchBarColor by viewModel.searchBarColor.observeAsState(SearchBarColors.Auto)
|
||||
val searchBarStyle by viewModel.searchBarStyle.observeAsState(SearchBarStyle.Transparent)
|
||||
val searchBarColor by viewModel.searchBarColor.collectAsState()
|
||||
val searchBarStyle by viewModel.searchBarStyle.collectAsState()
|
||||
|
||||
val launchOnEnter by searchVM.launchOnEnter.collectAsState(false)
|
||||
|
||||
|
||||
@ -43,7 +43,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
@ -100,8 +99,8 @@ fun PullDownScaffold(
|
||||
|
||||
val actions by searchVM.searchActionResults
|
||||
|
||||
val isSearchOpen by viewModel.isSearchOpen.observeAsState(false)
|
||||
val isWidgetEditMode by viewModel.isWidgetEditMode.observeAsState(false)
|
||||
val isSearchOpen by viewModel.isSearchOpen
|
||||
val isWidgetEditMode by viewModel.isWidgetEditMode
|
||||
|
||||
val widgetsScrollState = rememberScrollState()
|
||||
val searchState = rememberLazyListState()
|
||||
@ -148,7 +147,7 @@ fun PullDownScaffold(
|
||||
}
|
||||
}
|
||||
|
||||
val fillClockHeight by viewModel.fillClockHeight.observeAsState(true)
|
||||
val fillClockHeight by viewModel.fillClockHeight.collectAsState()
|
||||
|
||||
val showStatusBarScrim by remember {
|
||||
derivedStateOf {
|
||||
@ -210,7 +209,7 @@ fun PullDownScaffold(
|
||||
|
||||
val maxSearchBarOffset = with(density) { 128.dp.toPx() }
|
||||
|
||||
val blurEnabled by viewModel.wallpaperBlur.observeAsState(false)
|
||||
val blurEnabled by viewModel.wallpaperBlur.collectAsState()
|
||||
|
||||
val blurWallpaper by remember {
|
||||
derivedStateOf {
|
||||
@ -516,15 +515,15 @@ fun PullDownScaffold(
|
||||
}
|
||||
}
|
||||
}
|
||||
val searchBarFocused by viewModel.searchBarFocused.observeAsState(false)
|
||||
val searchBarFocused by viewModel.searchBarFocused
|
||||
val editModeSearchBarOffset by animateDpAsState(
|
||||
(if (isWidgetEditMode) 128.dp else 0.dp) * (if (bottomSearchBar) 1 else -1)
|
||||
)
|
||||
|
||||
val value by searchVM.searchQuery
|
||||
|
||||
val searchBarColor by viewModel.searchBarColor.observeAsState(Settings.SearchBarSettings.SearchBarColors.Auto)
|
||||
val searchBarStyle by viewModel.searchBarStyle.observeAsState(Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
||||
val searchBarColor by viewModel.searchBarColor.collectAsState()
|
||||
val searchBarStyle by viewModel.searchBarStyle.collectAsState()
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
|
||||
@ -19,7 +19,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
@ -90,7 +89,7 @@ abstract class SharedLauncherActivity(
|
||||
setContent {
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val wallpaperColors by wallpaperColorsAsState()
|
||||
val dimBackground by viewModel.dimBackground.observeAsState(false)
|
||||
val dimBackground by viewModel.dimBackground.collectAsState()
|
||||
CompositionLocalProvider(
|
||||
LocalEnterHomeTransitionManager provides enterHomeTransitionManager,
|
||||
LocalWindowSize provides windowSize,
|
||||
@ -103,24 +102,24 @@ abstract class SharedLauncherActivity(
|
||||
LauncherTheme {
|
||||
ProvideCurrentTime {
|
||||
ProvideSettings {
|
||||
val statusBarColor by viewModel.statusBarColor.observeAsState(
|
||||
SystemBarColors.Auto
|
||||
)
|
||||
val navBarColor by viewModel.navBarColor.observeAsState(SystemBarColors.Auto)
|
||||
val statusBarColor by viewModel.statusBarColor.collectAsState()
|
||||
val navBarColor by viewModel.navBarColor.collectAsState()
|
||||
|
||||
val lightStatus =
|
||||
!dimBackground && (statusBarColor == SystemBarColors.Dark || statusBarColor == SystemBarColors.Auto && wallpaperColors.supportsDarkText)
|
||||
val lightNav =
|
||||
!dimBackground && (navBarColor == SystemBarColors.Dark || navBarColor == SystemBarColors.Auto && wallpaperColors.supportsDarkText)
|
||||
|
||||
val hideStatus by viewModel.hideStatusBar.observeAsState(false)
|
||||
val hideNav by viewModel.hideNavBar.observeAsState(false)
|
||||
val hideStatus by viewModel.hideStatusBar.collectAsState()
|
||||
val hideNav by viewModel.hideNavBar.collectAsState()
|
||||
val layout by viewModel.baseLayout.collectAsState(null)
|
||||
val bottomSearchBar by viewModel.bottomSearchBar.observeAsState(false)
|
||||
val reverseSearchResults by viewModel.reverseSearchResults.observeAsState(false)
|
||||
val fixedSearchBar by viewModel.fixedSearchBar.observeAsState(false)
|
||||
val bottomSearchBar by viewModel.bottomSearchBar.collectAsState()
|
||||
val reverseSearchResults by viewModel.reverseSearchResults.collectAsState()
|
||||
val fixedSearchBar by viewModel.fixedSearchBar.collectAsState()
|
||||
|
||||
viewModel.fixedRotation.observe(this) { fixedRotation ->
|
||||
val fixedRotation by viewModel.fixedRotation.collectAsState()
|
||||
|
||||
LaunchedEffect(fixedRotation) {
|
||||
requestedOrientation = if (fixedRotation) {
|
||||
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
} else {
|
||||
|
||||
@ -13,7 +13,6 @@ import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
|
||||
@ -31,7 +31,6 @@ import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
@ -180,11 +179,11 @@ fun CustomizeSearchableSheet(
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val suggestions by remember { viewModel.getIconSuggestions(iconSizePx.toInt()) }
|
||||
.observeAsState(emptyList())
|
||||
.collectAsState(emptyList())
|
||||
|
||||
val defaultIcon by remember {
|
||||
viewModel.getDefaultIcon(iconSizePx.toInt())
|
||||
}.observeAsState()
|
||||
}.collectAsState(null)
|
||||
|
||||
var query by remember { mutableStateOf("") }
|
||||
var filterIconPack by remember { mutableStateOf<IconPack?>(null) }
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package de.mm20.launcher2.ui.launcher.sheets
|
||||
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.liveData
|
||||
import de.mm20.launcher2.data.customattrs.CustomAttributesRepository
|
||||
import de.mm20.launcher2.data.customattrs.CustomIcon
|
||||
import de.mm20.launcher2.icons.CustomIconWithPreview
|
||||
@ -14,6 +13,7 @@ import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.component.KoinComponent
|
||||
@ -32,7 +32,7 @@ class CustomizeSearchableSheetVM(
|
||||
return iconService.getIcon(searchable, size)
|
||||
}
|
||||
|
||||
fun getIconSuggestions(size: Int) = liveData {
|
||||
fun getIconSuggestions(size: Int) = flow {
|
||||
emit(iconService.getCustomIconSuggestions(searchable, size))
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ class CustomizeSearchableSheetVM(
|
||||
closeIconPicker()
|
||||
}
|
||||
|
||||
fun getDefaultIcon(size: Int) = liveData {
|
||||
fun getDefaultIcon(size: Int) = flow {
|
||||
emit(iconService.getUncustomizedDefaultIcon(searchable, size))
|
||||
}
|
||||
|
||||
|
||||
@ -51,7 +51,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
@ -102,8 +101,8 @@ fun EditFavoritesSheet(
|
||||
viewModel.reload()
|
||||
}
|
||||
|
||||
val loading by viewModel.loading.observeAsState(true)
|
||||
val createShortcutTarget by viewModel.createShortcutTarget.observeAsState(null)
|
||||
val loading by viewModel.loading
|
||||
val createShortcutTarget by viewModel.createShortcutTarget
|
||||
|
||||
BottomSheetDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
@ -157,7 +156,7 @@ fun EditFavoritesSheet(
|
||||
|
||||
@Composable
|
||||
fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: PaddingValues) {
|
||||
val items by viewModel.gridItems.observeAsState(emptyList())
|
||||
val items by viewModel.gridItems
|
||||
val columns = LocalGridSettings.current.columnCount
|
||||
|
||||
val availableTags by viewModel.availableTags
|
||||
@ -336,10 +335,8 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: Padding
|
||||
}
|
||||
}
|
||||
}
|
||||
val enableFrequentlyUsed by viewModel.enableFrequentlyUsed.observeAsState(
|
||||
null
|
||||
)
|
||||
val frequentlyUsedRows by viewModel.frequentlyUsedRows.observeAsState(1)
|
||||
val enableFrequentlyUsed by viewModel.enableFrequentlyUsed.collectAsState()
|
||||
val frequentlyUsedRows by viewModel.frequentlyUsedRows.collectAsState()
|
||||
AnimatedVisibility(showSettings) {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
|
||||
@ -6,9 +6,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.lazy.LazyListItemInfo
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridItemInfo
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.appshortcuts.AppShortcutRepository
|
||||
import de.mm20.launcher2.badges.Badge
|
||||
@ -26,9 +24,11 @@ import de.mm20.launcher2.search.Searchable
|
||||
import de.mm20.launcher2.search.data.Tag
|
||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -43,11 +43,11 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val gridItems = MutableLiveData<List<FavoritesSheetGridItem>>(emptyList())
|
||||
val gridItems = mutableStateOf<List<FavoritesSheetGridItem>>(emptyList())
|
||||
|
||||
val loading = MutableLiveData(false)
|
||||
val loading = mutableStateOf(false)
|
||||
|
||||
val createShortcutTarget = MutableLiveData<FavoritesSheetSection?>(null)
|
||||
val createShortcutTarget = mutableStateOf<FavoritesSheetSection?>(null)
|
||||
|
||||
private var manuallySorted: MutableList<SavableSearchable> = mutableListOf()
|
||||
private var automaticallySorted: MutableList<SavableSearchable> = mutableListOf()
|
||||
@ -245,7 +245,8 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val enableFrequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }.asLiveData()
|
||||
val enableFrequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -260,7 +261,8 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }.asLiveData()
|
||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
||||
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -59,7 +59,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import coil.compose.AsyncImage
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.launcher.widgets.picker.PickAppWidgetActivity
|
||||
import de.mm20.launcher2.widgets.CalendarWidget
|
||||
import de.mm20.launcher2.widgets.AppWidget
|
||||
import de.mm20.launcher2.widgets.AppWidgetConfig
|
||||
@ -111,7 +110,7 @@ class BindAndConfigureAppWidgetActivity : Activity() {
|
||||
AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
|
||||
appWidgetProviderInfo.profile
|
||||
)
|
||||
}, PickAppWidgetActivity.RequestCodeBind
|
||||
}, RequestCodeBind
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -122,7 +121,7 @@ class BindAndConfigureAppWidgetActivity : Activity() {
|
||||
this,
|
||||
appWidgetId,
|
||||
0,
|
||||
PickAppWidgetActivity.RequestCodeConfigure,
|
||||
RequestCodeConfigure,
|
||||
null
|
||||
)
|
||||
} else {
|
||||
|
||||
@ -18,9 +18,9 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
@ -77,7 +77,7 @@ fun WidgetColumn(
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
Column {
|
||||
val widgets by viewModel.widgets.observeAsState(emptyList())
|
||||
val widgets by viewModel.widgets.collectAsState()
|
||||
val swapThresholds = remember(widgets) {
|
||||
Array(widgets.size) { floatArrayOf(0f, 0f) }
|
||||
}
|
||||
@ -144,7 +144,7 @@ fun WidgetColumn(
|
||||
}
|
||||
}
|
||||
|
||||
val editButton by viewModel.editButton.observeAsState()
|
||||
val editButton by viewModel.editButton.collectAsState()
|
||||
if (editButton == true) {
|
||||
val icon =
|
||||
AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_edit_add)
|
||||
|
||||
@ -2,11 +2,13 @@ package de.mm20.launcher2.ui.launcher.widgets
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.widgets.Widget
|
||||
import de.mm20.launcher2.widgets.WidgetRepository
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
@ -15,12 +17,14 @@ class WidgetsVM : ViewModel(), KoinComponent {
|
||||
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val editButton = dataStore.data.map { it.widgets.editButton }.asLiveData()
|
||||
val editButton = dataStore.data.map { it.widgets.editButton }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val widgets = widgetRepository.get().asLiveData()
|
||||
val widgets = widgetRepository.get()
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
||||
|
||||
fun addWidget(widget: Widget) {
|
||||
val widgets = widgets.value?.toMutableList() ?: return
|
||||
val widgets = widgets.value.toMutableList()
|
||||
widgets.add(widget)
|
||||
widgetRepository.set(widgets)
|
||||
}
|
||||
@ -34,14 +38,14 @@ class WidgetsVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
fun moveUp(index: Int) {
|
||||
val widgets = widgets.value?.toMutableList() ?: return
|
||||
val widgets = widgets.value.toMutableList()
|
||||
val widget = widgets.removeAt(index)
|
||||
widgets.add(index - 1, widget)
|
||||
widgetRepository.set(widgets)
|
||||
}
|
||||
|
||||
fun moveDown(index: Int) {
|
||||
val widgets = widgets.value?.toMutableList() ?: return
|
||||
val widgets = widgets.value.toMutableList()
|
||||
val widget = widgets.removeAt(index)
|
||||
widgets.add(index + 1, widget)
|
||||
widgetRepository.set(widgets)
|
||||
|
||||
@ -10,9 +10,7 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
@ -61,7 +59,7 @@ fun CalendarWidget(
|
||||
modifier = Modifier.weight(1f),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
val selectedDate by viewModel.selectedDate.observeAsState(LocalDate.now())
|
||||
val selectedDate by viewModel.selectedDate
|
||||
var showDropdown by remember { mutableStateOf(false) }
|
||||
TextButton(onClick = { showDropdown = true }) {
|
||||
Text(
|
||||
@ -99,8 +97,8 @@ fun CalendarWidget(
|
||||
Icon(imageVector = Icons.Rounded.OpenInNew, contentDescription = null)
|
||||
}
|
||||
}
|
||||
val events by viewModel.calendarEvents.observeAsState(emptyList())
|
||||
val hasPermission by viewModel.hasPermission.observeAsState()
|
||||
val events by viewModel.calendarEvents
|
||||
val hasPermission by viewModel.hasPermission.collectAsState()
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.animateContentSize()
|
||||
@ -124,7 +122,7 @@ fun CalendarWidget(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
val runningEvents by viewModel.hiddenPastEvents.observeAsState(0)
|
||||
val runningEvents by viewModel.hiddenPastEvents
|
||||
if (runningEvents > 0) {
|
||||
Info(
|
||||
text = pluralStringResource(
|
||||
@ -137,7 +135,7 @@ fun CalendarWidget(
|
||||
}
|
||||
)
|
||||
}
|
||||
val nextEvents by viewModel.nextEvents.observeAsState(emptyList())
|
||||
val nextEvents by viewModel.nextEvents
|
||||
if (nextEvents.isNotEmpty()) {
|
||||
Text(
|
||||
stringResource(R.string.calendar_widget_next_events),
|
||||
@ -150,7 +148,7 @@ fun CalendarWidget(
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
val pinnedEvents by viewModel.pinnedCalendarEvents.observeAsState(emptyList())
|
||||
val pinnedEvents by viewModel.pinnedCalendarEvents.collectAsState()
|
||||
if (pinnedEvents.isNotEmpty()) {
|
||||
Text(
|
||||
stringResource(R.string.calendar_widget_pinned_events),
|
||||
|
||||
@ -5,23 +5,22 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.CalendarContract
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.calendar.CalendarRepository
|
||||
import de.mm20.launcher2.searchable.SearchableRepository
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.search.data.CalendarEvent
|
||||
import de.mm20.launcher2.services.favorites.FavoritesService
|
||||
import de.mm20.launcher2.widgets.CalendarWidget
|
||||
import de.mm20.launcher2.widgets.CalendarWidgetConfig
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import java.lang.Integer.min
|
||||
@ -39,23 +38,24 @@ class CalendarWidgetVM : ViewModel(), KoinComponent {
|
||||
|
||||
private val widgetConfig = MutableStateFlow(CalendarWidgetConfig())
|
||||
|
||||
val calendarEvents = MutableLiveData<List<CalendarEvent>>(emptyList())
|
||||
val calendarEvents = mutableStateOf<List<CalendarEvent>>(emptyList())
|
||||
val pinnedCalendarEvents =
|
||||
favoritesService.getFavorites(
|
||||
includeTypes = listOf(CalendarEvent.Domain),
|
||||
automaticallySorted = true,
|
||||
manuallySorted = true,
|
||||
).asLiveData(viewModelScope.coroutineContext)
|
||||
val nextEvents = MutableLiveData<List<CalendarEvent>>(emptyList())
|
||||
).stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
||||
val nextEvents = mutableStateOf<List<CalendarEvent>>(emptyList())
|
||||
var availableDates = listOf(LocalDate.now())
|
||||
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Calendar).asLiveData()
|
||||
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
private var showRunningPastDayEvents = false
|
||||
val hiddenPastEvents = MutableLiveData(0)
|
||||
val hiddenPastEvents = mutableStateOf(0)
|
||||
|
||||
val selectedDate = MutableLiveData(LocalDate.now())
|
||||
val selectedDate = mutableStateOf(LocalDate.now())
|
||||
|
||||
fun updateWidget(widget: CalendarWidget) {
|
||||
widgetConfig.value = widget.config
|
||||
@ -147,17 +147,17 @@ class CalendarWidgetVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
val hiddenCount = totalCount - events.size
|
||||
hiddenPastEvents.postValue(hiddenCount)
|
||||
hiddenPastEvents.value = hiddenCount
|
||||
} else {
|
||||
hiddenPastEvents.postValue(0)
|
||||
hiddenPastEvents.value = 0
|
||||
}
|
||||
|
||||
calendarEvents.postValue(events)
|
||||
calendarEvents.value = events
|
||||
val e = this.upcomingEvents
|
||||
if (events.isEmpty() && e.isNotEmpty()) {
|
||||
nextEvents.postValue(listOf(e[0]))
|
||||
nextEvents.value = listOf(e[0])
|
||||
} else {
|
||||
nextEvents.postValue(emptyList())
|
||||
nextEvents.value = emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,8 +16,8 @@ import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -44,9 +44,9 @@ fun ClockWidget(
|
||||
) {
|
||||
val viewModel: ClockWidgetVM = viewModel()
|
||||
val context = LocalContext.current
|
||||
val layout by viewModel.layout.observeAsState()
|
||||
val clockStyle by viewModel.clockStyle.observeAsState()
|
||||
val color by viewModel.color.observeAsState()
|
||||
val layout by viewModel.layout.collectAsState()
|
||||
val clockStyle by viewModel.clockStyle.collectAsState()
|
||||
val color by viewModel.color.collectAsState()
|
||||
val time = LocalTime.current
|
||||
|
||||
LaunchedEffect(time) {
|
||||
|
||||
@ -4,7 +4,6 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.AlarmClock
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
@ -55,10 +54,13 @@ class ClockWidgetVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val layout = dataStore.data.map { it.clockWidget.layout }.asLiveData()
|
||||
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }.asLiveData()
|
||||
val layout = dataStore.data.map { it.clockWidget.layout }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val color = dataStore.data.map { it.clockWidget.color }.asLiveData()
|
||||
val color = dataStore.data.map { it.clockWidget.color }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun updateTime(time: Long) {
|
||||
partProviders.value.forEach { it.setTime(time) }
|
||||
|
||||
@ -15,12 +15,11 @@ import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
@ -29,7 +28,7 @@ import kotlinx.coroutines.flow.*
|
||||
|
||||
class AlarmPartProvider : PartProvider {
|
||||
|
||||
private val nextAlarmTime = MutableLiveData<Long?>(null)
|
||||
private val nextAlarmTime = mutableStateOf<Long?>(null)
|
||||
|
||||
private val time = MutableStateFlow(System.currentTimeMillis())
|
||||
|
||||
@ -75,7 +74,7 @@ class AlarmPartProvider : PartProvider {
|
||||
override fun Component(layout: ClockWidgetLayout) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val alarmTime by nextAlarmTime.observeAsState(null)
|
||||
val alarmTime by nextAlarmTime
|
||||
val time by this.time.collectAsState(System.currentTimeMillis())
|
||||
|
||||
alarmTime?.let {
|
||||
|
||||
@ -5,10 +5,7 @@ import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.media.session.PlaybackState.CustomAction
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import de.mm20.launcher2.music.MusicService
|
||||
import de.mm20.launcher2.music.PlaybackState
|
||||
@ -16,7 +13,6 @@ import de.mm20.launcher2.music.SupportedActions
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
|
||||
@ -1,118 +0,0 @@
|
||||
package de.mm20.launcher2.ui.launcher.widgets.picker
|
||||
|
||||
import android.appwidget.AppWidgetProviderInfo
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||
import androidx.compose.ui.graphics.nativeCanvas
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.ui.component.LauncherCard
|
||||
import de.mm20.launcher2.ui.ktx.toDp
|
||||
|
||||
@Composable
|
||||
fun AppWidgetList(
|
||||
modifier: Modifier = Modifier,
|
||||
widgets: List<AppWidgetGroup>,
|
||||
onWidgetSelected: (AppWidgetProviderInfo) -> Unit = {}
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val density = (LocalDensity.current.density * 160).toInt()
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
) {
|
||||
for (group in widgets) {
|
||||
item {
|
||||
Text(
|
||||
modifier = Modifier.padding(
|
||||
top = 16.dp,
|
||||
start = 8.dp,
|
||||
end = 8.dp,
|
||||
bottom = 8.dp
|
||||
),
|
||||
text = group.appName,
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
}
|
||||
items(group.widgets) {
|
||||
LauncherCard(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
onWidgetSelected(it)
|
||||
}
|
||||
.padding(16.dp),
|
||||
) {
|
||||
val label = remember { it.loadLabel(context.packageManager) }
|
||||
Text(text = label, style = MaterialTheme.typography.titleMedium)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 16.dp)
|
||||
) {
|
||||
|
||||
val image: Drawable? = remember {
|
||||
it.loadPreviewImage(context, density) ?: it.loadIcon(
|
||||
context,
|
||||
density
|
||||
)
|
||||
}
|
||||
|
||||
if (image != null) {
|
||||
|
||||
val mod =
|
||||
if (image.intrinsicWidth > 0 && image.intrinsicHeight > 0) {
|
||||
Modifier
|
||||
.heightIn(max = image.intrinsicHeight.toDp())
|
||||
.widthIn(max = image.intrinsicWidth.toDp())
|
||||
.aspectRatio(
|
||||
image.intrinsicWidth.toFloat() / image.intrinsicHeight.toFloat(),
|
||||
matchHeightConstraintsFirst = true
|
||||
)
|
||||
} else {
|
||||
Modifier.size(64.dp)
|
||||
}
|
||||
|
||||
Canvas(
|
||||
modifier = mod
|
||||
) {
|
||||
drawIntoCanvas {
|
||||
image.setBounds(
|
||||
0,
|
||||
0,
|
||||
size.width.toInt(),
|
||||
size.height.toInt(),
|
||||
)
|
||||
image.draw(it.nativeCanvas)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isAtLeastApiLevel(31)) {
|
||||
val description = remember { it.loadDescription(context)?.toString() }
|
||||
if (description != null) {
|
||||
Text(text = description, style = MaterialTheme.typography.bodySmall)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,168 +0,0 @@
|
||||
package de.mm20.launcher2.ui.launcher.widgets.picker
|
||||
|
||||
import android.appwidget.AppWidgetHost
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProviderInfo
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.base.BaseActivity
|
||||
import de.mm20.launcher2.ui.base.ProvideSettings
|
||||
import de.mm20.launcher2.ui.theme.LauncherTheme
|
||||
|
||||
class PickAppWidgetActivity : BaseActivity() {
|
||||
|
||||
private val viewModel by viewModels<PickAppWidgetVM>()
|
||||
|
||||
private lateinit var widgetHost: AppWidgetHost
|
||||
private lateinit var appWidgetManager: AppWidgetManager
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
widgetHost = AppWidgetHost(this, 44203)
|
||||
appWidgetManager = AppWidgetManager.getInstance(this)
|
||||
|
||||
val availableWidgets = viewModel.getAvailableWidgets(this)
|
||||
setContent {
|
||||
LauncherTheme {
|
||||
ProvideSettings {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
CenterAlignedTopAppBar(
|
||||
title = {
|
||||
Text(stringResource(R.string.widget_add_widget))
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = { finish() }) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(
|
||||
id = R.string.menu_back
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) {
|
||||
val available by availableWidgets.observeAsState()
|
||||
val widgets = available
|
||||
if (widgets != null) {
|
||||
AppWidgetList(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it),
|
||||
widgets = widgets,
|
||||
onWidgetSelected = {
|
||||
selectAppWidget(it)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectAppWidget(widget: AppWidgetProviderInfo) {
|
||||
val appWidgetId = widgetHost.allocateAppWidgetId()
|
||||
bindAppWidget(widget, appWidgetId)
|
||||
}
|
||||
|
||||
private fun bindAppWidget(widget: AppWidgetProviderInfo, appWidgetId: Int) {
|
||||
val canBind = appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, widget.provider)
|
||||
Log.d("MM20", "Can bind: $canBind")
|
||||
if (canBind) {
|
||||
configureAppWidget(widget, appWidgetId)
|
||||
} else {
|
||||
startActivityForResult(
|
||||
Intent(AppWidgetManager.ACTION_APPWIDGET_BIND).apply {
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, widget.provider)
|
||||
}, RequestCodeBind
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureAppWidget(widget: AppWidgetProviderInfo, appWidgetId: Int) {
|
||||
if (widget.configure != null) {
|
||||
widgetHost.startAppWidgetConfigureActivityForResult(
|
||||
this,
|
||||
appWidgetId,
|
||||
0,
|
||||
RequestCodeConfigure,
|
||||
null
|
||||
)
|
||||
} else {
|
||||
finishWithResult(appWidgetId)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in super class")
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
when (requestCode) {
|
||||
RequestCodeBind -> {
|
||||
val appWidgetId =
|
||||
data?.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: return
|
||||
if (resultCode == RESULT_OK) {
|
||||
val widget = appWidgetManager.getAppWidgetInfo(appWidgetId)
|
||||
configureAppWidget(widget, appWidgetId)
|
||||
} else {
|
||||
widgetHost.deleteAppWidgetId(appWidgetId)
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
RequestCodeConfigure -> {
|
||||
val appWidgetId =
|
||||
data?.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: return cancel()
|
||||
if (resultCode == RESULT_OK) {
|
||||
finishWithResult(appWidgetId)
|
||||
} else {
|
||||
widgetHost.deleteAppWidgetId(appWidgetId)
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishWithResult(widgetId: Int) {
|
||||
val data = Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId)
|
||||
setResult(RESULT_OK, data)
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun cancel() {
|
||||
setResult(RESULT_CANCELED)
|
||||
finish()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val RequestCodeConfigure = 1
|
||||
const val RequestCodeBind = 2
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
package de.mm20.launcher2.ui.launcher.widgets.picker
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProviderInfo
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.compose.ui.text.toLowerCase
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.liveData
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
typealias AppWidgetGroup = Pair<String, List<AppWidgetProviderInfo>>
|
||||
|
||||
inline val AppWidgetGroup.appName: String
|
||||
get() = this.first
|
||||
inline val AppWidgetGroup.widgets: List<AppWidgetProviderInfo>
|
||||
get() = this.second
|
||||
|
||||
class PickAppWidgetVM : ViewModel() {
|
||||
fun getAvailableWidgets(context: Context): LiveData<List<AppWidgetGroup>?> = liveData {
|
||||
emit(null)
|
||||
val appWidgetManager = AppWidgetManager.getInstance(context)
|
||||
val widgets = withContext(Dispatchers.IO) {
|
||||
appWidgetManager.installedProviders
|
||||
.sortedBy { it.loadLabel(context.packageManager).lowercase() }
|
||||
.groupBy {
|
||||
val pkg = it.provider.packageName
|
||||
val appInfo = try {
|
||||
context.packageManager.getApplicationInfo(pkg, 0)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
CrashReporter.logException(e)
|
||||
return@groupBy ""
|
||||
}
|
||||
appInfo.loadLabel(context.packageManager).toString()
|
||||
}
|
||||
.toList()
|
||||
.sortedBy { it.first.lowercase() }
|
||||
}
|
||||
emit(widgets)
|
||||
}
|
||||
}
|
||||
@ -34,7 +34,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
@ -81,7 +80,7 @@ fun WeatherWidget(widget: WeatherWidget) {
|
||||
}
|
||||
}
|
||||
|
||||
val selectedForecast by viewModel.currentForecast.observeAsState()
|
||||
val selectedForecast by viewModel.currentForecast
|
||||
|
||||
val imperialUnits by viewModel.imperialUnits.collectAsState(false)
|
||||
val compactMode = !widget.config.showForecast
|
||||
@ -93,8 +92,8 @@ fun WeatherWidget(widget: WeatherWidget) {
|
||||
}
|
||||
|
||||
val forecast = selectedForecast ?: run {
|
||||
val hasPermission by viewModel.hasLocationPermission.observeAsState()
|
||||
val autoLocation by viewModel.autoLocation.observeAsState()
|
||||
val hasPermission by viewModel.hasLocationPermission.collectAsState()
|
||||
val autoLocation by viewModel.autoLocation.collectAsState()
|
||||
Column {
|
||||
AnimatedVisibility(hasPermission == false && autoLocation == true) {
|
||||
MissingPermissionBanner(
|
||||
@ -126,9 +125,9 @@ fun WeatherWidget(widget: WeatherWidget) {
|
||||
|
||||
if (!compactMode) {
|
||||
|
||||
val dailyForecasts by viewModel.dailyForecasts.observeAsState(emptyList())
|
||||
val selectedDayForecast by viewModel.currentDailyForecast.observeAsState()
|
||||
val currentDayForecasts by viewModel.currentDayForecasts.observeAsState(emptyList())
|
||||
val dailyForecasts by viewModel.dailyForecasts
|
||||
val selectedDayForecast by viewModel.currentDailyForecast
|
||||
val currentDayForecasts by viewModel.currentDayForecasts
|
||||
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = LocalCardStyle.current.opacity),
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package de.mm20.launcher2.ui.launcher.widgets.weather
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.*
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
@ -8,8 +9,10 @@ import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.weather.DailyForecast
|
||||
import de.mm20.launcher2.weather.Forecast
|
||||
import de.mm20.launcher2.weather.WeatherRepository
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -30,16 +33,16 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
||||
set(value) {
|
||||
field = min(value, forecasts.lastIndex)
|
||||
if (field < 0) {
|
||||
currentForecast.postValue(null)
|
||||
currentForecast.value = null
|
||||
return
|
||||
}
|
||||
selectedForecastIndex = min(
|
||||
selectedForecastIndex,
|
||||
forecasts[value].hourlyForecasts.lastIndex
|
||||
)
|
||||
currentDayForecasts.postValue(forecasts[value].hourlyForecasts)
|
||||
currentDailyForecast.postValue(forecasts[value])
|
||||
currentForecast.postValue(getCurrentlySelectedForecast())
|
||||
currentDayForecasts.value = forecasts[value].hourlyForecasts
|
||||
currentDailyForecast.value = forecasts[value]
|
||||
currentForecast.value = getCurrentlySelectedForecast()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,11 +51,11 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
||||
private var selectedForecastIndex = 0
|
||||
set(value) {
|
||||
if (selectedDayIndex < 0) {
|
||||
currentForecast.postValue(null)
|
||||
currentForecast.value = null
|
||||
return
|
||||
}
|
||||
field = min(value, forecasts[selectedDayIndex].hourlyForecasts.lastIndex)
|
||||
currentForecast.postValue(getCurrentlySelectedForecast())
|
||||
currentForecast.value = getCurrentlySelectedForecast()
|
||||
}
|
||||
|
||||
private val forecastsFlow = weatherRepository.forecasts
|
||||
@ -65,29 +68,29 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
||||
field = value
|
||||
selectedDayIndex = 0
|
||||
selectedForecastIndex = 0
|
||||
dailyForecasts.postValue(value)
|
||||
dailyForecasts.value = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently selected forecast, one of [currentDayForecasts]
|
||||
*/
|
||||
val currentForecast = MutableLiveData<Forecast?>(getCurrentlySelectedForecast())
|
||||
val currentForecast = mutableStateOf<Forecast?>(getCurrentlySelectedForecast())
|
||||
|
||||
/**
|
||||
* List of forecast summaries for each day
|
||||
*/
|
||||
val dailyForecasts = MutableLiveData<List<DailyForecast>>(emptyList())
|
||||
val dailyForecasts = mutableStateOf<List<DailyForecast>>(emptyList())
|
||||
|
||||
/**
|
||||
* Forecasts of the currently selected day (hourly in most cases).
|
||||
* This is [DailyForecast.hourlyForecasts] of [currentDailyForecast]
|
||||
*/
|
||||
val currentDayForecasts = MutableLiveData<List<Forecast>>(emptyList())
|
||||
val currentDayForecasts = mutableStateOf<List<Forecast>>(emptyList())
|
||||
|
||||
/**
|
||||
* Daily forecast summary for the currently selected day, one of [dailyForecasts] or null
|
||||
*/
|
||||
val currentDailyForecast = MutableLiveData<DailyForecast>(null)
|
||||
val currentDailyForecast = mutableStateOf<DailyForecast?>(null)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
@ -98,11 +101,13 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val hasLocationPermission = permissionsManager.hasPermission(PermissionGroup.Location).asLiveData()
|
||||
val hasLocationPermission = permissionsManager.hasPermission(PermissionGroup.Location)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun requestLocationPermission(context: AppCompatActivity) {
|
||||
permissionsManager.requestPermission(context, PermissionGroup.Location)
|
||||
}
|
||||
val autoLocation = weatherRepository.autoLocation.asLiveData()
|
||||
val autoLocation = weatherRepository.autoLocation
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val imperialUnits = dataStore.data.map { it.weather.imperialUnits }
|
||||
|
||||
|
||||
@ -1,82 +1,24 @@
|
||||
package de.mm20.launcher2.ui.settings.appearance
|
||||
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.FormatPaint
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.FilledIconToggleButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.PlainTooltipBox
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.google.accompanist.pager.HorizontalPager
|
||||
import com.google.accompanist.pager.HorizontalPagerIndicator
|
||||
import com.google.accompanist.pager.rememberPagerState
|
||||
import de.mm20.launcher2.icons.StaticIconLayer
|
||||
import de.mm20.launcher2.icons.StaticLauncherIcon
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
||||
import de.mm20.launcher2.preferences.Settings.IconSettings
|
||||
import de.mm20.launcher2.preferences.Settings.SearchBarSettings
|
||||
import de.mm20.launcher2.preferences.Settings.SearchBarSettings.SearchBarColors
|
||||
import de.mm20.launcher2.preferences.Settings.SearchBarSettings.SearchBarStyle
|
||||
import de.mm20.launcher2.preferences.Settings.SystemBarsSettings.SystemBarColors
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.SearchBar
|
||||
import de.mm20.launcher2.ui.component.SearchBarLevel
|
||||
import de.mm20.launcher2.ui.component.ShapedLauncherIcon
|
||||
import de.mm20.launcher2.ui.component.getShape
|
||||
import de.mm20.launcher2.ui.component.preferences.ListPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.Preference
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.component.preferences.SliderPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
import de.mm20.launcher2.ui.component.preferences.label
|
||||
import de.mm20.launcher2.ui.component.preferences.value
|
||||
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||
import de.mm20.launcher2.ui.theme.getTypography
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
|
||||
@Composable
|
||||
fun AppearanceSettingsScreen() {
|
||||
@ -86,7 +28,7 @@ fun AppearanceSettingsScreen() {
|
||||
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val theme by viewModel.theme.observeAsState()
|
||||
val theme by viewModel.theme.collectAsState()
|
||||
ListPreference(
|
||||
title = stringResource(id = R.string.preference_theme),
|
||||
items = listOf(
|
||||
@ -100,7 +42,7 @@ fun AppearanceSettingsScreen() {
|
||||
viewModel.setTheme(newValue)
|
||||
}
|
||||
)
|
||||
val colorScheme by viewModel.colorScheme.observeAsState()
|
||||
val colorScheme by viewModel.colorScheme.collectAsState()
|
||||
Preference(
|
||||
title = stringResource(id = R.string.preference_screen_colors),
|
||||
summary = when (colorScheme) {
|
||||
@ -113,7 +55,7 @@ fun AppearanceSettingsScreen() {
|
||||
navController?.navigate("settings/appearance/colorscheme")
|
||||
}
|
||||
)
|
||||
val font by viewModel.font.observeAsState()
|
||||
val font by viewModel.font.collectAsState()
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_font),
|
||||
items = listOf(
|
||||
|
||||
@ -1,26 +1,16 @@
|
||||
package de.mm20.launcher2.ui.settings.appearance
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.icons.IconPack
|
||||
import de.mm20.launcher2.icons.IconService
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Font
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
|
||||
import de.mm20.launcher2.preferences.Settings.SearchBarSettings
|
||||
import de.mm20.launcher2.preferences.Settings.SearchBarSettings.SearchBarColors
|
||||
import de.mm20.launcher2.preferences.Settings.SystemBarsSettings
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -30,7 +20,8 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
private val iconService: IconService by inject()
|
||||
|
||||
val theme = dataStore.data.map { it.appearance.theme }.asLiveData()
|
||||
val theme = dataStore.data.map { it.appearance.theme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setTheme(theme: Theme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -41,7 +32,8 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val colorScheme = dataStore.data.map { it.appearance.colorScheme }.asLiveData()
|
||||
val colorScheme = dataStore.data.map { it.appearance.colorScheme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setColorScheme(colorScheme: ColorScheme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -52,7 +44,8 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val font = dataStore.data.map { it.appearance.font }.asLiveData()
|
||||
val font = dataStore.data.map { it.appearance.font }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setFont(font: Font) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -3,7 +3,6 @@ package de.mm20.launcher2.ui.settings.backup
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
@ -19,11 +18,9 @@ import java.time.format.DateTimeFormatter
|
||||
fun BackupSettingsScreen() {
|
||||
val viewModel: BackupSettingsScreenVM = viewModel()
|
||||
|
||||
val restoreUri by viewModel.restoreUri.observeAsState()
|
||||
val restoreUri by viewModel.restoreUri
|
||||
|
||||
val showBackupSheet by viewModel.showBackupSheet.observeAsState(false)
|
||||
|
||||
val context = LocalContext.current
|
||||
val showBackupSheet by viewModel.showBackupSheet
|
||||
|
||||
val restoreLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.OpenDocument(),
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
package de.mm20.launcher2.ui.settings.backup
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.koin.core.component.KoinComponent
|
||||
|
||||
class BackupSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
val showBackupSheet = MutableLiveData(false)
|
||||
val showBackupSheet = mutableStateOf(false)
|
||||
|
||||
val restoreUri = MutableLiveData<Uri?>(null)
|
||||
val restoreUri = mutableStateOf<Uri?>(null)
|
||||
|
||||
fun setShowBackupSheet(show: Boolean) {
|
||||
showBackupSheet.value = show
|
||||
|
||||
@ -12,7 +12,6 @@ import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
@ -38,8 +37,8 @@ fun CreateBackupSheet(
|
||||
viewModel.reset()
|
||||
}
|
||||
|
||||
val components by viewModel.selectedComponents.observeAsState(emptySet())
|
||||
val state by viewModel.state.observeAsState(CreateBackupState.Ready)
|
||||
val components by viewModel.selectedComponents
|
||||
val state by viewModel.state
|
||||
|
||||
|
||||
val backupLauncher = rememberLauncherForActivityResult(
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package de.mm20.launcher2.ui.settings.backup
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.backup.BackupComponent
|
||||
@ -14,9 +14,9 @@ class CreateBackupSheetVM : ViewModel(), KoinComponent {
|
||||
|
||||
private val backupManager: BackupManager by inject()
|
||||
|
||||
val state = MutableLiveData(CreateBackupState.Ready)
|
||||
val state = mutableStateOf(CreateBackupState.Ready)
|
||||
|
||||
val selectedComponents = MutableLiveData(BackupComponent.values().toSet())
|
||||
val selectedComponents = mutableStateOf(BackupComponent.values().toSet())
|
||||
|
||||
fun reset() {
|
||||
state.value = CreateBackupState.Ready
|
||||
|
||||
@ -9,8 +9,8 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.*
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
@ -43,7 +43,7 @@ fun CardsSettingsScreen() {
|
||||
}
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val shape by viewModel.shape.observeAsState()
|
||||
val shape by viewModel.shape.collectAsState()
|
||||
ListPreference(
|
||||
icon = Icons.Rounded.Rectangle,
|
||||
title = stringResource(R.string.preference_cards_shape),
|
||||
@ -55,7 +55,7 @@ fun CardsSettingsScreen() {
|
||||
onValueChanged = {
|
||||
if (it != null) viewModel.setShape(it)
|
||||
})
|
||||
val radius by viewModel.radius.observeAsState(0)
|
||||
val radius by viewModel.radius.collectAsState()
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_cards_corner_radius),
|
||||
icon = Icons.Rounded.RoundedCorner,
|
||||
@ -67,7 +67,7 @@ fun CardsSettingsScreen() {
|
||||
viewModel.setRadius(it)
|
||||
}
|
||||
)
|
||||
val opacity by viewModel.opacity.observeAsState(0f)
|
||||
val opacity by viewModel.opacity.collectAsState()
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_cards_opacity),
|
||||
icon = Icons.Rounded.Opacity,
|
||||
@ -78,7 +78,7 @@ fun CardsSettingsScreen() {
|
||||
viewModel.setOpacity(it)
|
||||
}
|
||||
)
|
||||
val borderWidth by viewModel.borderWidth.observeAsState(0)
|
||||
val borderWidth by viewModel.borderWidth.collectAsState()
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.preference_cards_stroke_width),
|
||||
icon = Icons.Rounded.LineWeight,
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
package de.mm20.launcher2.ui.settings.cards
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -13,7 +14,8 @@ import org.koin.core.component.inject
|
||||
class CardsSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val opacity = dataStore.data.map { it.cards.opacity }.asLiveData()
|
||||
val opacity = dataStore.data.map { it.cards.opacity }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0f)
|
||||
fun setOpacity(opacity: Float) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -25,7 +27,9 @@ class CardsSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val radius = dataStore.data.map { it.cards.radius }.asLiveData()
|
||||
val radius = dataStore.data.map { it.cards.radius }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
||||
|
||||
fun setRadius(radius: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -37,7 +41,8 @@ class CardsSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val borderWidth = dataStore.data.map { it.cards.borderWidth }.asLiveData()
|
||||
val borderWidth = dataStore.data.map { it.cards.borderWidth }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
|
||||
fun setBorderWidth(borderWidth: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -49,7 +54,9 @@ class CardsSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val shape = dataStore.data.map { it.cards.shape }.asLiveData()
|
||||
val shape = dataStore.data.map { it.cards.shape }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setShape(shape: Settings.CardSettings.Shape) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -8,17 +8,14 @@ import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.google.accompanist.pager.ExperimentalPagerApi
|
||||
import com.google.accompanist.pager.HorizontalPager
|
||||
import com.google.accompanist.pager.HorizontalPagerIndicator
|
||||
import com.google.accompanist.pager.rememberPagerState
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockStyle
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
@ -35,7 +32,7 @@ fun ClockWidgetSettingsScreen() {
|
||||
) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val layout by viewModel.layout.observeAsState()
|
||||
val layout by viewModel.layout.collectAsState()
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_clockwidget_layout),
|
||||
value = layout,
|
||||
@ -47,7 +44,7 @@ fun ClockWidgetSettingsScreen() {
|
||||
if (it != null) viewModel.setLayout(it)
|
||||
}
|
||||
)
|
||||
val clockStyle by viewModel.clockStyle.observeAsState()
|
||||
val clockStyle by viewModel.clockStyle.collectAsState()
|
||||
ClockStylePreference(
|
||||
layout = layout ?: ClockWidgetLayout.Vertical,
|
||||
value = clockStyle,
|
||||
@ -55,7 +52,7 @@ fun ClockWidgetSettingsScreen() {
|
||||
viewModel.setClockStyle(it)
|
||||
}
|
||||
)
|
||||
val color by viewModel.color.observeAsState()
|
||||
val color by viewModel.color.collectAsState()
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_clock_widget_color),
|
||||
value = color,
|
||||
@ -68,7 +65,7 @@ fun ClockWidgetSettingsScreen() {
|
||||
if (it != null) viewModel.setColor(it)
|
||||
}
|
||||
)
|
||||
val fillHeight by viewModel.fillHeight.observeAsState()
|
||||
val fillHeight by viewModel.fillHeight.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_clock_widget_fill_height),
|
||||
summary = stringResource(R.string.preference_clock_widget_fill_height_summary),
|
||||
@ -79,7 +76,7 @@ fun ClockWidgetSettingsScreen() {
|
||||
}
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val datePart by viewModel.datePart.observeAsState()
|
||||
val datePart by viewModel.datePart.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_clockwidget_date_part),
|
||||
summary = stringResource(R.string.preference_clockwidget_date_part_summary),
|
||||
@ -89,7 +86,7 @@ fun ClockWidgetSettingsScreen() {
|
||||
viewModel.setDatePart(it)
|
||||
},
|
||||
)
|
||||
val favoritesPart by viewModel.favoritesPart.observeAsState()
|
||||
val favoritesPart by viewModel.favoritesPart.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_clockwidget_favorites_part),
|
||||
summary = stringResource(R.string.preference_clockwidget_favorites_part_summary),
|
||||
@ -103,7 +100,7 @@ fun ClockWidgetSettingsScreen() {
|
||||
}
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val musicPart by viewModel.musicPart.observeAsState()
|
||||
val musicPart by viewModel.musicPart.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_clockwidget_music_part),
|
||||
summary = stringResource(R.string.preference_clockwidget_music_part_summary),
|
||||
@ -113,7 +110,7 @@ fun ClockWidgetSettingsScreen() {
|
||||
viewModel.setMusicPart(it)
|
||||
}
|
||||
)
|
||||
val alarmPart by viewModel.alarmPart.observeAsState()
|
||||
val alarmPart by viewModel.alarmPart.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_clockwidget_alarm_part),
|
||||
summary = stringResource(R.string.preference_clockwidget_alarm_part_summary),
|
||||
@ -123,7 +120,7 @@ fun ClockWidgetSettingsScreen() {
|
||||
viewModel.setAlarmPart(it)
|
||||
}
|
||||
)
|
||||
val batteryPart by viewModel.batteryPart.observeAsState()
|
||||
val batteryPart by viewModel.batteryPart.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_clockwidget_battery_part),
|
||||
summary = stringResource(R.string.preference_clockwidget_battery_part_summary),
|
||||
|
||||
@ -1,20 +1,21 @@
|
||||
package de.mm20.launcher2.ui.settings.clockwidget
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
|
||||
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
val layout = dataStore.data.map { it.clockWidget.layout }.asLiveData()
|
||||
val layout = dataStore.data.map { it.clockWidget.layout }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setLayout(layout: ClockWidgetSettings.ClockWidgetLayout) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -27,7 +28,9 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }.asLiveData()
|
||||
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setClockStyle(clockStyle: ClockWidgetSettings.ClockStyle) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -40,7 +43,8 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val color = dataStore.data.map { it.clockWidget.color }.asLiveData()
|
||||
val color = dataStore.data.map { it.clockWidget.color }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setColor(color: ClockWidgetColors) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -53,7 +57,8 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val fillHeight = dataStore.data.map { it.clockWidget.fillHeight }.asLiveData()
|
||||
val fillHeight = dataStore.data.map { it.clockWidget.fillHeight }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setFillHeight(fillHeight: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -66,7 +71,8 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val datePart = dataStore.data.map { it.clockWidget.datePart }.asLiveData()
|
||||
val datePart = dataStore.data.map { it.clockWidget.datePart }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setDatePart(datePart: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -79,7 +85,8 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val favoritesPart = dataStore.data.map { it.clockWidget.favoritesPart }.asLiveData()
|
||||
val favoritesPart = dataStore.data.map { it.clockWidget.favoritesPart }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setFavoritesPart(favoritesPart: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -92,7 +99,8 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val batteryPart = dataStore.data.map { it.clockWidget.batteryPart }.asLiveData()
|
||||
val batteryPart = dataStore.data.map { it.clockWidget.batteryPart }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setBatteryPart(batteryPart: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -105,7 +113,8 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val musicPart = dataStore.data.map { it.clockWidget.musicPart }.asLiveData()
|
||||
val musicPart = dataStore.data.map { it.clockWidget.musicPart }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setMusicPart(musicPart: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -118,7 +127,8 @@ class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val alarmPart = dataStore.data.map { it.clockWidget.alarmPart }.asLiveData()
|
||||
val alarmPart = dataStore.data.map { it.clockWidget.alarmPart }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setAlarmPart(alarmPart: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -8,8 +8,8 @@ import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@ -34,7 +34,7 @@ fun ColorSchemeSettingsScreen() {
|
||||
PreferenceScreen(title = stringResource(R.string.preference_screen_colors)) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val colorScheme by viewModel.colorScheme.observeAsState()
|
||||
val colorScheme by viewModel.colorScheme.collectAsState()
|
||||
|
||||
val items = mutableListOf(
|
||||
AppearanceSettings.ColorScheme.Default to stringResource(R.string.preference_colors_default),
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
package de.mm20.launcher2.ui.settings.colorscheme
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -13,9 +14,11 @@ import org.koin.core.component.inject
|
||||
class ColorSchemeSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val theme = dataStore.data.map { it.appearance.theme }.asLiveData()
|
||||
val theme = dataStore.data.map { it.appearance.theme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val colorScheme = dataStore.data.map { it.appearance.colorScheme }.asLiveData()
|
||||
val colorScheme = dataStore.data.map { it.appearance.colorScheme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setColorScheme(colorScheme: AppearanceSettings.ColorScheme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -4,7 +4,6 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.MoreVert
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@ -18,7 +17,7 @@ import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
fun CustomColorSchemeSettingsScreen() {
|
||||
val viewModel: CustomColorSchemeSettingsScreenVM = viewModel()
|
||||
|
||||
val advancedMode by viewModel.advancedMode.observeAsState()
|
||||
val advancedMode by viewModel.advancedMode.collectAsState()
|
||||
|
||||
PreferenceScreen(
|
||||
title = stringResource(R.string.preference_screen_colors),
|
||||
@ -64,7 +63,7 @@ fun CustomColorSchemeSettingsScreen() {
|
||||
if (advancedMode == false) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val baseColors by viewModel.baseColors.observeAsState()
|
||||
val baseColors by viewModel.baseColors.collectAsState()
|
||||
ColorPreference(
|
||||
title = stringResource(R.string.preference_custom_colors_a1),
|
||||
value = baseColors?.let { Color(it.accent1) },
|
||||
@ -149,7 +148,7 @@ fun CustomColorSchemeSettingsScreen() {
|
||||
if (advancedMode == true) {
|
||||
item {
|
||||
PreferenceCategory(stringResource(R.string.preference_category_custom_colors_light)) {
|
||||
val lightScheme by viewModel.lightScheme.observeAsState()
|
||||
val lightScheme by viewModel.lightScheme.collectAsState()
|
||||
ColorPreference(
|
||||
title = "Primary",
|
||||
value = lightScheme?.let { Color(it.primary) },
|
||||
@ -513,7 +512,7 @@ fun CustomColorSchemeSettingsScreen() {
|
||||
}
|
||||
|
||||
PreferenceCategory(stringResource(R.string.preference_category_custom_colors_dark)) {
|
||||
val darkScheme by viewModel.darkScheme.observeAsState()
|
||||
val darkScheme by viewModel.darkScheme.collectAsState()
|
||||
ColorPreference(
|
||||
title = "Primary",
|
||||
value = darkScheme?.let { Color(it.primary) },
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
package de.mm20.launcher2.ui.settings.colorscheme
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.CustomColors
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -17,7 +17,8 @@ import scheme.Scheme
|
||||
class CustomColorSchemeSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val advancedMode = dataStore.data.map { it.appearance.customColors.advancedMode }.asLiveData()
|
||||
val advancedMode = dataStore.data.map { it.appearance.customColors.advancedMode }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setAdvancedMode(advancedMode: Boolean) {
|
||||
viewModelScope.launch {
|
||||
val lightScheme = dataStore.updateData {
|
||||
@ -63,7 +64,8 @@ class CustomColorSchemeSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val baseColors = dataStore.data.map { it.appearance.customColors.baseColors }.asLiveData()
|
||||
val baseColors = dataStore.data.map { it.appearance.customColors.baseColors }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setBaseColors(baseColors: CustomColors.BaseColors) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -82,7 +84,8 @@ class CustomColorSchemeSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val darkScheme = dataStore.data.map { it.appearance.customColors.darkScheme }.asLiveData()
|
||||
val darkScheme = dataStore.data.map { it.appearance.customColors.darkScheme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setDarkScheme(darkScheme: CustomColors.Scheme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -99,7 +102,8 @@ class CustomColorSchemeSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val lightScheme = dataStore.data.map { it.appearance.customColors.lightScheme }.asLiveData()
|
||||
val lightScheme = dataStore.data.map { it.appearance.customColors.lightScheme }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setLightScheme(lightScheme: CustomColors.Scheme) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -6,14 +6,13 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.BugReport
|
||||
import androidx.compose.material.icons.rounded.Share
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@ -26,7 +25,7 @@ import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
fun CrashReportScreen(fileName: String) {
|
||||
val viewModel: CrashReportScreenVM = viewModel()
|
||||
val context = LocalContext.current
|
||||
val crashReport by remember(fileName) { viewModel.getCrashReport(fileName) }.observeAsState()
|
||||
val crashReport by remember(fileName) { viewModel.getCrashReport(fileName) }.collectAsState(null)
|
||||
PreferenceScreen(
|
||||
title = when (crashReport?.type) {
|
||||
CrashReportType.Exception -> "Exception"
|
||||
|
||||
@ -5,14 +5,14 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.liveData
|
||||
import de.mm20.launcher2.crashreporter.CrashReport
|
||||
import de.mm20.launcher2.crashreporter.CrashReporter
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import java.io.File
|
||||
import java.net.URLEncoder
|
||||
|
||||
class CrashReportScreenVM : ViewModel() {
|
||||
fun getCrashReport(fileName: String) = liveData<CrashReport?> {
|
||||
fun getCrashReport(fileName: String) = flow<CrashReport?> {
|
||||
emit(CrashReporter.getCrashReport(fileName))
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@ import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
@ -32,9 +31,9 @@ import java.net.URLEncoder
|
||||
fun CrashReporterScreen() {
|
||||
val viewModel: CrashReporterScreenVM = viewModel()
|
||||
val navController = LocalNavController.current
|
||||
val reports by viewModel.reports.observeAsState()
|
||||
val showExceptions by viewModel.showExceptions.observeAsState(true)
|
||||
val showCrashes by viewModel.showCrashes.observeAsState(true)
|
||||
val reports by viewModel.reports
|
||||
val showExceptions by viewModel.showExceptions
|
||||
val showCrashes by viewModel.showCrashes
|
||||
PreferenceScreen(
|
||||
title = stringResource(R.string.preference_crash_reporter),
|
||||
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/troubleshooting/crashreporter"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package de.mm20.launcher2.ui.settings.crashreporter
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.crashreporter.BuildConfig
|
||||
@ -29,10 +29,10 @@ class CrashReporterScreenVM: ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
val showExceptions = MutableLiveData(false)
|
||||
val showCrashes = MutableLiveData(true)
|
||||
val showExceptions = mutableStateOf(false)
|
||||
val showCrashes = mutableStateOf(true)
|
||||
|
||||
val reports = MutableLiveData<List<CrashReport>?>(null)
|
||||
val reports = mutableStateOf<List<CrashReport>?>(null)
|
||||
private var _reports: List<CrashReport>? = null
|
||||
|
||||
init {
|
||||
|
||||
@ -12,8 +12,8 @@ import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -30,7 +30,7 @@ fun EasterEggSettingsScreen() {
|
||||
val viewModel: EasterEggSettingsScreenVM = viewModel()
|
||||
PreferenceScreen(title = stringResource(R.string.preference_screen_about)) {
|
||||
item {
|
||||
val easterEgg by viewModel.easterEgg.observeAsState(false)
|
||||
val easterEgg by viewModel.easterEgg.collectAsState()
|
||||
val bgAlpha by animateFloatAsState(if (easterEgg) 1f else 0f)
|
||||
val textColor by animateColorAsState(if (easterEgg) MaterialTheme.colorScheme.onSecondaryContainer else MaterialTheme.colorScheme.onBackground)
|
||||
Column(
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
package de.mm20.launcher2.ui.settings.easteregg
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -12,7 +13,8 @@ import org.koin.core.component.inject
|
||||
class EasterEggSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val easterEgg = dataStore.data.map { it.easterEgg }.asLiveData()
|
||||
val easterEgg = dataStore.data.map { it.easterEgg }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
fun setEasterEgg(easterEgg: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -7,8 +7,8 @@ import androidx.compose.material.icons.rounded.Sort
|
||||
import androidx.compose.material.icons.rounded.SwapVert
|
||||
import androidx.compose.material.icons.rounded.TableRows
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
@ -45,7 +45,7 @@ fun FavoritesSettingsScreen() {
|
||||
}
|
||||
item {
|
||||
PreferenceCategory(stringResource(R.string.preference_category_favorites_frequently_used)) {
|
||||
val frequentlyUsed by viewModel.frequentlyUsed.observeAsState()
|
||||
val frequentlyUsed by viewModel.frequentlyUsed.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.frequently_used_show_in_favorites),
|
||||
summary = stringResource(R.string.preference_favorites_frequently_used_summary),
|
||||
@ -55,7 +55,7 @@ fun FavoritesSettingsScreen() {
|
||||
},
|
||||
icon = Icons.Rounded.Insights
|
||||
)
|
||||
val frequentlyUsedRows by viewModel.frequentlyUsedRows.observeAsState(1)
|
||||
val frequentlyUsedRows by viewModel.frequentlyUsedRows.collectAsState()
|
||||
SliderPreference(
|
||||
title = stringResource(R.string.frequently_used_rows),
|
||||
value = frequentlyUsedRows,
|
||||
@ -67,7 +67,7 @@ fun FavoritesSettingsScreen() {
|
||||
},
|
||||
icon = Icons.Rounded.TableRows
|
||||
)
|
||||
val searchResultWeightFactor by viewModel.searchResultWeightFactor.observeAsState(WeightFactor.Default)
|
||||
val searchResultWeightFactor by viewModel.searchResultWeightFactor.collectAsState()
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_search_result_ordering_weight_factor),
|
||||
icon = Icons.Rounded.SwapVert,
|
||||
@ -82,7 +82,7 @@ fun FavoritesSettingsScreen() {
|
||||
}
|
||||
}
|
||||
item {
|
||||
val editButton by viewModel.editButton.observeAsState()
|
||||
val editButton by viewModel.editButton.collectAsState()
|
||||
PreferenceCategory {
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_edit_button),
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
package de.mm20.launcher2.ui.settings.favorites
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.WeightFactor
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -13,7 +14,8 @@ import org.koin.core.component.inject
|
||||
class FavoritesSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val frequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }.asLiveData()
|
||||
val frequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setFrequentlyUsed(frequentlyUsed: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -27,7 +29,8 @@ class FavoritesSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }.asLiveData()
|
||||
val frequentlyUsedRows = dataStore.data.map { it.favorites.frequentlyUsedRows }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 1)
|
||||
fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -41,7 +44,8 @@ class FavoritesSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val editButton = dataStore.data.map { it.favorites.editButton }.asLiveData()
|
||||
val editButton = dataStore.data.map { it.favorites.editButton }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setEditButton(editButton: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -55,7 +59,8 @@ class FavoritesSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val searchResultWeightFactor = dataStore.data.map { it.resultOrdering.weightFactor }.asLiveData()
|
||||
val searchResultWeightFactor = dataStore.data.map { it.resultOrdering.weightFactor }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), WeightFactor.Default)
|
||||
fun setSearchResultWeightFactor(searchResultWeightFactor: WeightFactor) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -11,8 +11,8 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
@ -40,7 +40,7 @@ fun FileSearchSettingsScreen() {
|
||||
viewModel.onResume()
|
||||
}
|
||||
}
|
||||
val loading by viewModel.loading.observeAsState()
|
||||
val loading by viewModel.loading
|
||||
PreferenceScreen(title = stringResource(R.string.preference_search_files)) {
|
||||
if (loading == true) {
|
||||
item {
|
||||
@ -52,8 +52,8 @@ fun FileSearchSettingsScreen() {
|
||||
}
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val localFiles by viewModel.localFiles.observeAsState()
|
||||
val hasFilePermission by viewModel.hasFilePermission.observeAsState()
|
||||
val localFiles by viewModel.localFiles.collectAsState()
|
||||
val hasFilePermission by viewModel.hasFilePermission.collectAsState()
|
||||
AnimatedVisibility(hasFilePermission == false) {
|
||||
MissingPermissionBanner(
|
||||
text = stringResource(
|
||||
@ -74,8 +74,8 @@ fun FileSearchSettingsScreen() {
|
||||
enabled = hasFilePermission == true
|
||||
)
|
||||
|
||||
val nextcloud by viewModel.nextcloud.observeAsState()
|
||||
val nextcloudAccount by viewModel.nextcloudAccount.observeAsState()
|
||||
val nextcloud by viewModel.nextcloud.collectAsState()
|
||||
val nextcloudAccount by viewModel.nextcloudAccount
|
||||
AnimatedVisibility(nextcloudAccount == null) {
|
||||
Banner(
|
||||
text = stringResource(R.string.no_account_nextcloud),
|
||||
@ -107,8 +107,8 @@ fun FileSearchSettingsScreen() {
|
||||
enabled = nextcloudAccount != null
|
||||
)
|
||||
|
||||
val owncloud by viewModel.owncloud.observeAsState()
|
||||
val owncloudAccount by viewModel.owncloudAccount.observeAsState()
|
||||
val owncloud by viewModel.owncloud.collectAsState()
|
||||
val owncloudAccount by viewModel.owncloudAccount
|
||||
AnimatedVisibility(owncloudAccount == null) {
|
||||
Banner(
|
||||
text = stringResource(R.string.no_account_owncloud),
|
||||
@ -141,8 +141,8 @@ fun FileSearchSettingsScreen() {
|
||||
)
|
||||
|
||||
if (viewModel.microsoftAvailable) {
|
||||
val onedrive by viewModel.onedrive.observeAsState()
|
||||
val microsoftAccount by viewModel.microsoftAccount.observeAsState()
|
||||
val onedrive by viewModel.onedrive.collectAsState()
|
||||
val microsoftAccount by viewModel.microsoftAccount
|
||||
AnimatedVisibility(microsoftAccount == null) {
|
||||
Banner(
|
||||
text = stringResource(R.string.no_account_microsoft),
|
||||
@ -176,8 +176,8 @@ fun FileSearchSettingsScreen() {
|
||||
}
|
||||
|
||||
if (viewModel.googleAvailable) {
|
||||
val gdrive by viewModel.gdrive.observeAsState()
|
||||
val googleAccount by viewModel.googleAccount.observeAsState()
|
||||
val gdrive by viewModel.gdrive.collectAsState()
|
||||
val googleAccount by viewModel.googleAccount
|
||||
AnimatedVisibility(googleAccount == null) {
|
||||
Banner(
|
||||
text = stringResource(R.string.no_account_google),
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package de.mm20.launcher2.ui.settings.filesearch
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.accounts.Account
|
||||
import de.mm20.launcher2.accounts.AccountType
|
||||
@ -11,7 +10,9 @@ import de.mm20.launcher2.accounts.AccountsRepository
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -21,14 +22,14 @@ class FileSearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val accountsRepository: AccountsRepository by inject()
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
|
||||
val hasFilePermission =
|
||||
permissionsManager.hasPermission(PermissionGroup.ExternalStorage).asLiveData()
|
||||
val hasFilePermission = permissionsManager.hasPermission(PermissionGroup.ExternalStorage)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val loading = MutableLiveData(true)
|
||||
val nextcloudAccount = MutableLiveData<Account?>(null)
|
||||
val owncloudAccount = MutableLiveData<Account?>(null)
|
||||
val microsoftAccount = MutableLiveData<Account?>(null)
|
||||
val googleAccount = MutableLiveData<Account?>(null)
|
||||
val loading = mutableStateOf(true)
|
||||
val nextcloudAccount = mutableStateOf<Account?>(null)
|
||||
val owncloudAccount = mutableStateOf<Account?>(null)
|
||||
val microsoftAccount = mutableStateOf<Account?>(null)
|
||||
val googleAccount = mutableStateOf<Account?>(null)
|
||||
|
||||
val microsoftAvailable = accountsRepository.isSupported(AccountType.Microsoft)
|
||||
val googleAvailable = accountsRepository.isSupported(AccountType.Google)
|
||||
@ -46,7 +47,8 @@ class FileSearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val localFiles = dataStore.data.map { it.fileSearch.localFiles }.asLiveData()
|
||||
val localFiles = dataStore.data.map { it.fileSearch.localFiles }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setLocalFiles(localFiles: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -61,7 +63,8 @@ class FileSearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val nextcloud = dataStore.data.map { it.fileSearch.nextcloud }.asLiveData()
|
||||
val nextcloud = dataStore.data.map { it.fileSearch.nextcloud }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setNextcloud(nextcloud: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -76,7 +79,8 @@ class FileSearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val gdrive = dataStore.data.map { it.fileSearch.gdrive }.asLiveData()
|
||||
val gdrive = dataStore.data.map { it.fileSearch.gdrive }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setGdrive(gdrive: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -91,7 +95,8 @@ class FileSearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val onedrive = dataStore.data.map { it.fileSearch.onedrive }.asLiveData()
|
||||
val onedrive = dataStore.data.map { it.fileSearch.onedrive }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setOneDrive(onedrive: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -106,7 +111,8 @@ class FileSearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val owncloud = dataStore.data.map { it.fileSearch.owncloud }.asLiveData()
|
||||
val owncloud = dataStore.data.map { it.fileSearch.owncloud }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setOwncloud(owncloud: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -14,7 +14,6 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
|
||||
@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.settings.gestures
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.searchable.SearchableRepository
|
||||
import de.mm20.launcher2.icons.IconService
|
||||
@ -29,8 +28,10 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val iconService: IconService by inject()
|
||||
|
||||
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
val baseLayout = dataStore.data.map { it.layout.baseLayout }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setBaseLayout(baseLayout: Settings.LayoutSettings.Layout) {
|
||||
viewModelScope.launch {
|
||||
@ -43,10 +44,15 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
val swipeDown = dataStore.data.map { it.gestures.swipeDown }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val swipeLeft = dataStore.data.map { it.gestures.swipeLeft }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val swipeRight = dataStore.data.map { it.gestures.swipeRight }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val doubleTap = dataStore.data.map { it.gestures.doubleTap }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val longPress = dataStore.data.map { it.gestures.longPress }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setSwipeDown(action: GestureAction) {
|
||||
viewModelScope.launch {
|
||||
|
||||
@ -9,7 +9,6 @@ import androidx.compose.material.icons.rounded.Visibility
|
||||
import androidx.compose.material.icons.rounded.VisibilityOff
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
@ -31,8 +30,8 @@ fun HiddenItemsSettingsScreen() {
|
||||
val context = LocalContext.current
|
||||
val density = LocalDensity.current
|
||||
|
||||
val apps by viewModel.allApps.observeAsState(emptyList())
|
||||
val other by viewModel.hiddenItems.observeAsState(emptyList())
|
||||
val apps by viewModel.allApps.collectAsState()
|
||||
val other by viewModel.hiddenItems.collectAsState()
|
||||
PreferenceScreen(title = stringResource(R.string.preference_hidden_items)) {
|
||||
items(apps, key = { it.key }) { searchable ->
|
||||
val icon by remember(searchable.key) {
|
||||
|
||||
@ -5,10 +5,8 @@ import android.content.Context
|
||||
import android.content.pm.LauncherApps
|
||||
import android.os.Bundle
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.liveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.applications.AppRepository
|
||||
import de.mm20.launcher2.searchable.SearchableRepository
|
||||
import de.mm20.launcher2.icons.IconService
|
||||
@ -18,8 +16,12 @@ import de.mm20.launcher2.search.SavableSearchable
|
||||
import de.mm20.launcher2.search.data.LauncherApp
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -31,11 +33,11 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
val allApps = appRepository.getAllInstalledApps().map {
|
||||
withContext(Dispatchers.Default) { it.sorted() }
|
||||
}.asLiveData()
|
||||
val hiddenItems: LiveData<List<SavableSearchable>> = liveData {
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
||||
val hiddenItems: StateFlow<List<SavableSearchable>> = flow {
|
||||
val hidden = searchableRepository.get(hidden = true).first().filter { it !is LauncherApp }.sorted()
|
||||
emit(hidden)
|
||||
}
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
||||
|
||||
fun isHidden(searchable: SavableSearchable): Flow<Boolean> {
|
||||
return searchableRepository.isHidden(searchable)
|
||||
|
||||
@ -55,8 +55,8 @@ fun HomescreenSettingsScreen() {
|
||||
val bottomSearchBar by viewModel.bottomSearchBar.collectAsStateWithLifecycle(null)
|
||||
val fixedSearchBar by viewModel.fixedSearchBar.collectAsStateWithLifecycle(null)
|
||||
val lightStatusBar by viewModel.statusBarIcons.collectAsStateWithLifecycle(null)
|
||||
val dimWallpaper by viewModel.dimWallpaper.collectAsStateWithLifecycle(false)
|
||||
val blurWallpaper by viewModel.blurWallpaper.collectAsStateWithLifecycle(false)
|
||||
val dimWallpaper by viewModel.dimWallpaper.collectAsStateWithLifecycle()
|
||||
val blurWallpaper by viewModel.blurWallpaper.collectAsStateWithLifecycle()
|
||||
val lightNavBar by viewModel.navBarIcons.collectAsStateWithLifecycle(null)
|
||||
val hideStatusBar by viewModel.hideStatusBar.collectAsStateWithLifecycle(null)
|
||||
val hideNavBar by viewModel.hideNavBar.collectAsStateWithLifecycle(null)
|
||||
|
||||
@ -6,14 +6,15 @@ import android.view.WindowManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
@ -24,6 +25,7 @@ class HomescreenSettingsScreenVM(
|
||||
|
||||
|
||||
val dimWallpaper = dataStore.data.map { it.appearance.dimWallpaper }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
fun setDimWallpaper(dimWallpaper: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -37,6 +39,7 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
|
||||
val blurWallpaper = dataStore.data.map { it.appearance.blurWallpaper }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
fun setBlurWallpaper(blurWallpaper: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -59,6 +62,7 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
|
||||
val statusBarIcons = dataStore.data.map { it.systemBars.statusBarColor }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setLightStatusBar(statusBarColor: Settings.SystemBarsSettings.SystemBarColors) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -73,6 +77,7 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
|
||||
val navBarIcons = dataStore.data.map { it.systemBars.navBarColor }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setLightNavBar(navBarColors: Settings.SystemBarsSettings.SystemBarColors) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -87,6 +92,7 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
|
||||
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setHideStatusBar(hideStatusBar: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -101,6 +107,7 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
|
||||
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setHideNavBar(hideNavBar: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -115,6 +122,7 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
|
||||
val searchBarColor = dataStore.data.map { it.searchBar.color }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setSearchBarColor(color: Settings.SearchBarSettings.SearchBarColors) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -128,9 +136,8 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setSearchBarStyle(searchBarStyle: Settings.SearchBarSettings.SearchBarStyle) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -145,6 +152,7 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
|
||||
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setFixedSearchBar(fixedSearchBar: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -156,6 +164,7 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
|
||||
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setBottomSearchBar(bottomSearchBar: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -167,6 +176,7 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
|
||||
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setFixedRotation(fixedRotation: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -178,6 +188,7 @@ class HomescreenSettingsScreenVM(
|
||||
}
|
||||
|
||||
val widgetEditButton = dataStore.data.map { it.widgets.editButton }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setWidgetEditButton(editButton: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.settings.integrations
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.accounts.Account
|
||||
|
||||
@ -11,8 +11,8 @@ import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.rounded.OpenInBrowser
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@ -102,7 +102,7 @@ fun LicenseScreen(library: OpenSourceLibrary) {
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
}
|
||||
val licenseText by viewModel.getLicenseText(library).observeAsState()
|
||||
val licenseText by viewModel.getLicenseText(library).collectAsState(null)
|
||||
licenseText?.let {
|
||||
Text(
|
||||
text = it,
|
||||
|
||||
@ -2,13 +2,13 @@ package de.mm20.launcher2.ui.settings.license
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.liveData
|
||||
import de.mm20.launcher2.licenses.OpenSourceLibrary
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class LicenseScreenVM(private val context: Application) : AndroidViewModel(context) {
|
||||
fun getLicenseText(library: OpenSourceLibrary) = liveData<String?> {
|
||||
fun getLicenseText(library: OpenSourceLibrary) = flow<String?> {
|
||||
val text = withContext(Dispatchers.IO) {
|
||||
context.resources.openRawResource(library.licenseText).reader()
|
||||
.readText()
|
||||
|
||||
@ -9,7 +9,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
|
||||
@ -7,7 +7,6 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
||||
@ -2,14 +2,15 @@ package de.mm20.launcher2.ui.settings.search
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -19,6 +20,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
|
||||
val favorites = dataStore.data.map { it.favorites.enabled }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setFavorites(favorites: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -31,7 +33,10 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
|
||||
val hasContactsPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val contacts = dataStore.data.map { it.contactsSearch.enabled }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setContacts(contacts: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -47,7 +52,9 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
val hasCalendarPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val calendar = dataStore.data.map { it.calendarSearch.enabled }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setCalendar(calendar: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -63,6 +70,8 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
val calculator = dataStore.data.map { it.calculatorSearch.enabled }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setCalculator(calculator: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -74,6 +83,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setUnitConverter(unitConverter: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -85,6 +95,8 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun setWikipedia(wikipedia: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -96,6 +108,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
val websites = dataStore.data.map { it.websiteSearch.enabled }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setWebsites(websites: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -106,18 +119,8 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val webSearch = dataStore.data.map { it.webSearch.enabled }
|
||||
fun setWebSearch(webSearch: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
it.toBuilder().setWebSearch(
|
||||
it.webSearch.toBuilder().setEnabled(webSearch)
|
||||
).build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val autoFocus = dataStore.data.map { it.searchBar.autoFocus }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setAutoFocus(autoFocus: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -129,6 +132,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
val launchOnEnter = dataStore.data.map { it.searchBar.launchOnEnter }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setLaunchOnEnter(launchOnEnter: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -140,7 +144,9 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
val appShortcuts = dataStore.data.map { it.appShortcutSearch.enabled }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setAppShortcuts(appShortcuts: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -152,6 +158,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
|
||||
val searchResultOrdering = dataStore.data.map { it.resultOrdering.ordering }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setSearchResultOrdering(searchResultOrdering: Settings.SearchResultOrderingSettings.Ordering) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -164,6 +171,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
|
||||
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setReverseSearchResults(reverseSearchResults: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -25,8 +25,8 @@ import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
@ -69,8 +69,8 @@ fun SearchActionsSettingsScreen() {
|
||||
onItemMove = { from, to -> viewModel.moveItem(from.index, to.index) }
|
||||
)
|
||||
|
||||
val searchActions by viewModel.searchActions.observeAsState(emptyList())
|
||||
val disabledActions by viewModel.disabledActions.observeAsState(emptyList())
|
||||
val searchActions by viewModel.searchActions.collectAsState()
|
||||
val disabledActions by viewModel.disabledActions.collectAsState()
|
||||
|
||||
Scaffold(
|
||||
floatingActionButton = {
|
||||
@ -187,8 +187,8 @@ fun SearchActionsSettingsScreen() {
|
||||
}
|
||||
}
|
||||
|
||||
val editAction by viewModel.showEditDialogFor.observeAsState(null)
|
||||
val createAction by viewModel.showCreateDialog.observeAsState(false)
|
||||
val editAction by viewModel.showEditDialogFor
|
||||
val createAction by viewModel.showCreateDialog
|
||||
|
||||
if (createAction) {
|
||||
EditSearchActionSheet(
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
package de.mm20.launcher2.ui.settings.searchactions
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.searchactions.SearchActionService
|
||||
import de.mm20.launcher2.searchactions.builders.CustomizableSearchActionBuilder
|
||||
import de.mm20.launcher2.searchactions.builders.SearchActionBuilder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -18,11 +19,11 @@ class SearchActionsSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
val searchActions = searchActionService
|
||||
.getSearchActionBuilders()
|
||||
.asLiveData()
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
||||
|
||||
val disabledActions = searchActionService
|
||||
.getDisabledActionBuilders()
|
||||
.asLiveData()
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
|
||||
|
||||
fun addAction(searchAction: SearchActionBuilder) {
|
||||
val actions =
|
||||
@ -60,8 +61,8 @@ class SearchActionsSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
searchActionService.saveSearchActionBuilders(actions)
|
||||
}
|
||||
|
||||
val showEditDialogFor = MutableLiveData<CustomizableSearchActionBuilder?>(null)
|
||||
val showCreateDialog = MutableLiveData(false)
|
||||
val showEditDialogFor = mutableStateOf<CustomizableSearchActionBuilder?>(null)
|
||||
val showCreateDialog = mutableStateOf(false)
|
||||
|
||||
fun editAction(action: CustomizableSearchActionBuilder) {
|
||||
showEditDialogFor.value = action
|
||||
|
||||
@ -1,19 +1,14 @@
|
||||
package de.mm20.launcher2.ui.settings.unitconverter
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Loop
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
|
||||
import de.mm20.launcher2.ui.component.preferences.PreferenceWithSwitch
|
||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
import de.mm20.launcher2.ui.settings.search.SearchSettingsScreenVM
|
||||
|
||||
@Composable
|
||||
fun UnitConverterSettingsScreen() {
|
||||
@ -21,7 +16,7 @@ fun UnitConverterSettingsScreen() {
|
||||
PreferenceScreen(title = stringResource(R.string.preference_search_unitconverter)) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val unitConverter by viewModel.unitConverter.observeAsState()
|
||||
val unitConverter by viewModel.unitConverter.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_search_unitconverter),
|
||||
summary = stringResource(R.string.preference_search_unitconverter_summary),
|
||||
@ -30,7 +25,7 @@ fun UnitConverterSettingsScreen() {
|
||||
viewModel.setUnitConverter(it)
|
||||
}
|
||||
)
|
||||
val currencyConverter by viewModel.currencyConverter.observeAsState()
|
||||
val currencyConverter by viewModel.currencyConverter.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_search_currencyconverter),
|
||||
summary = stringResource(R.string.preference_search_currencyconverter_summary),
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
package de.mm20.launcher2.ui.settings.unitconverter
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -13,7 +14,8 @@ class UnitConverterSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }.asLiveData()
|
||||
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setUnitConverter(unitConverter: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -27,7 +29,8 @@ class UnitConverterSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val currencyConverter = dataStore.data.map { it.unitConverterSearch.currencies }.asLiveData()
|
||||
val currencyConverter = dataStore.data.map { it.unitConverterSearch.currencies }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setCurrencyConverter(currencyConverter: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -4,7 +4,6 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@ -29,7 +28,7 @@ fun WeatherIntegrationSettingsScreen() {
|
||||
) {
|
||||
item {
|
||||
PreferenceCategory {
|
||||
val weatherProvider by viewModel.weatherProvider.observeAsState()
|
||||
val weatherProvider by viewModel.weatherProvider.collectAsState()
|
||||
ListPreference(
|
||||
title = stringResource(R.string.preference_weather_provider),
|
||||
items = viewModel.availableProviders.map {
|
||||
@ -60,7 +59,7 @@ fun WeatherIntegrationSettingsScreen() {
|
||||
}
|
||||
item {
|
||||
PreferenceCategory(title = stringResource(R.string.preference_category_location)) {
|
||||
val hasPermission by viewModel.hasLocationPermission.observeAsState()
|
||||
val hasPermission by viewModel.hasLocationPermission.collectAsState()
|
||||
AnimatedVisibility(hasPermission == false) {
|
||||
MissingPermissionBanner(
|
||||
text = stringResource(R.string.missing_permission_auto_location),
|
||||
@ -70,7 +69,7 @@ fun WeatherIntegrationSettingsScreen() {
|
||||
modifier = Modifier.padding(16.dp)
|
||||
)
|
||||
}
|
||||
val autoLocation by viewModel.autoLocation.observeAsState(false)
|
||||
val autoLocation by viewModel.autoLocation.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_automatic_location),
|
||||
summary = stringResource(R.string.preference_automatic_location_summary),
|
||||
@ -79,7 +78,7 @@ fun WeatherIntegrationSettingsScreen() {
|
||||
viewModel.setAutoLocation(it)
|
||||
}
|
||||
)
|
||||
val location by viewModel.location.observeAsState()
|
||||
val location by viewModel.location
|
||||
LocationPreference(
|
||||
title = stringResource(R.string.preference_location),
|
||||
value = location,
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package de.mm20.launcher2.ui.settings.weather
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
@ -12,9 +11,11 @@ import de.mm20.launcher2.preferences.Settings.WeatherSettings
|
||||
import de.mm20.launcher2.weather.WeatherLocation
|
||||
import de.mm20.launcher2.weather.WeatherRepository
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
@ -25,7 +26,8 @@ class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
|
||||
val availableProviders = repository.getAvailableProviders()
|
||||
|
||||
val weatherProvider = repository.selectedProvider.asLiveData()
|
||||
val weatherProvider = repository.selectedProvider
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setWeatherProvider(provider: WeatherSettings.WeatherProvider) {
|
||||
repository.selectProvider(provider)
|
||||
}
|
||||
@ -41,14 +43,16 @@ class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val autoLocation = repository.autoLocation.asLiveData()
|
||||
val autoLocation = repository.autoLocation
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
|
||||
fun setAutoLocation(autoLocation: Boolean) {
|
||||
repository.setAutoLocation(autoLocation)
|
||||
}
|
||||
|
||||
val location = MutableLiveData<WeatherLocation?>(null)
|
||||
val location = mutableStateOf<WeatherLocation?>(null)
|
||||
|
||||
val hasLocationPermission = permissionsManager.hasPermission(PermissionGroup.Location).asLiveData()
|
||||
val hasLocationPermission = permissionsManager.hasPermission(PermissionGroup.Location)
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
|
||||
fun requestLocationPermission(activity: AppCompatActivity) {
|
||||
permissionsManager.requestPermission(activity, PermissionGroup.Location)
|
||||
@ -64,7 +68,7 @@ class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
|
||||
if (autoLoc) lastLoc
|
||||
else loc
|
||||
}.collectLatest {
|
||||
this@WeatherIntegrationSettingsScreenVM.location.postValue(it)
|
||||
this@WeatherIntegrationSettingsScreenVM.location.value = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package de.mm20.launcher2.ui.settings.wikipedia
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.ui.R
|
||||
@ -15,7 +15,7 @@ fun WikipediaSettingsScreen() {
|
||||
val viewModel: WikipediaSettingsScreenVM = viewModel()
|
||||
PreferenceScreen(title = stringResource(R.string.preference_search_wikipedia)) {
|
||||
item {
|
||||
val wikipedia by viewModel.wikipedia.observeAsState()
|
||||
val wikipedia by viewModel.wikipedia.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_search_wikipedia),
|
||||
summary = stringResource(R.string.preference_search_wikipedia_summary),
|
||||
@ -24,7 +24,7 @@ fun WikipediaSettingsScreen() {
|
||||
viewModel.setWikipedia(it)
|
||||
}
|
||||
)
|
||||
val images by viewModel.images.observeAsState()
|
||||
val images by viewModel.images.collectAsState()
|
||||
SwitchPreference(
|
||||
title = stringResource(R.string.preference_search_wikipedia_pictures),
|
||||
summary = stringResource(R.string.preference_search_wikipedia_pictures_summary),
|
||||
@ -34,7 +34,7 @@ fun WikipediaSettingsScreen() {
|
||||
viewModel.setImages(it)
|
||||
}
|
||||
)
|
||||
val customUrl by viewModel.customUrl.observeAsState("")
|
||||
val customUrl by viewModel.customUrl.collectAsState()
|
||||
TextPreference(
|
||||
title = stringResource(R.string.preference_wikipedia_customurl),
|
||||
value = customUrl,
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
package de.mm20.launcher2.ui.settings.wikipedia
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
@ -12,7 +13,8 @@ import org.koin.core.component.inject
|
||||
class WikipediaSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
private val dataStore: LauncherDataStore by inject()
|
||||
|
||||
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }.asLiveData()
|
||||
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setWikipedia(wikipedia: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -26,7 +28,8 @@ class WikipediaSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val images = dataStore.data.map { it.wikipediaSearch.images }.asLiveData()
|
||||
val images = dataStore.data.map { it.wikipediaSearch.images }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
|
||||
fun setImages(images: Boolean) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
@ -40,7 +43,8 @@ class WikipediaSettingsScreenVM: ViewModel(), KoinComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val customUrl = dataStore.data.map { it.wikipediaSearch.customUrl }.asLiveData()
|
||||
val customUrl = dataStore.data.map { it.wikipediaSearch.customUrl }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), "")
|
||||
fun setCustomUrl(customUrl: String) {
|
||||
viewModelScope.launch {
|
||||
dataStore.updateData {
|
||||
|
||||
@ -1,13 +1,10 @@
|
||||
package de.mm20.launcher2.database
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import de.mm20.launcher2.database.entities.IconEntity
|
||||
import de.mm20.launcher2.database.entities.IconPackEntity
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
internal val AppTypes = listOf("app", "calendar", "clock")
|
||||
|
||||
@Dao
|
||||
interface IconDao {
|
||||
@Insert
|
||||
|
||||
@ -37,8 +37,6 @@ dependencyResolutionManagement {
|
||||
version("androidx.compose.compiler", "1.4.5")
|
||||
library("androidx.compose.runtime", "androidx.compose.runtime", "runtime")
|
||||
.version("1.5.0-alpha03")
|
||||
library("androidx.compose.livedata", "androidx.compose.runtime", "runtime-livedata")
|
||||
.version("1.5.0-alpha03")
|
||||
library("androidx.compose.foundation", "androidx.compose.foundation", "foundation")
|
||||
.version("1.5.0-alpha03")
|
||||
library("androidx.compose.foundationlayout", "androidx.compose.foundation", "foundation-layout")
|
||||
@ -61,8 +59,6 @@ dependencyResolutionManagement {
|
||||
version("androidx.lifecycle", "2.6.1")
|
||||
library("androidx.lifecycle.viewmodel", "androidx.lifecycle", "lifecycle-viewmodel-ktx")
|
||||
.versionRef("androidx.lifecycle")
|
||||
library("androidx.lifecycle.livedata", "androidx.lifecycle", "lifecycle-livedata-ktx")
|
||||
.versionRef("androidx.lifecycle")
|
||||
library("androidx.lifecycle.common", "androidx.lifecycle", "lifecycle-common-java8")
|
||||
.versionRef("androidx.lifecycle")
|
||||
library("androidx.lifecycle.runtime", "androidx.lifecycle", "lifecycle-runtime-ktx")
|
||||
@ -75,7 +71,6 @@ dependencyResolutionManagement {
|
||||
"androidx.lifecycle",
|
||||
listOf(
|
||||
"androidx.lifecycle.viewmodel",
|
||||
"androidx.lifecycle.livedata",
|
||||
"androidx.lifecycle.common",
|
||||
"androidx.lifecycle.runtime"
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user