diff --git a/app/ui/build.gradle.kts b/app/ui/build.gradle.kts index c88c7893..c3d26e1f 100644 --- a/app/ui/build.gradle.kts +++ b/app/ui/build.gradle.kts @@ -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) diff --git a/app/ui/src/main/AndroidManifest.xml b/app/ui/src/main/AndroidManifest.xml index 58823eef..5d532173 100644 --- a/app/ui/src/main/AndroidManifest.xml +++ b/app/ui/src/main/AndroidManifest.xml @@ -58,19 +58,6 @@ android:value="de.mm20.launcher2.ui.launcher.SharedLauncherActivity" /> - - - - diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/assistant/AssistantScaffold.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/assistant/AssistantScaffold.kt index da485779..8770169a 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/assistant/AssistantScaffold.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/assistant/AssistantScaffold.kt @@ -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) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/base/BaseActivityVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/base/BaseActivityVM.kt deleted file mode 100644 index 794e0d2e..00000000 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/base/BaseActivityVM.kt +++ /dev/null @@ -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() - } -} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/common/RestoreBackupSheet.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/common/RestoreBackupSheet.kt index 579aa638..403a7095 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/common/RestoreBackupSheet.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/common/RestoreBackupSheet.kt @@ -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 diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/common/RestoreBackupSheetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/common/RestoreBackupSheetVM.kt index a029904c..f85b04ba 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/common/RestoreBackupSheetVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/common/RestoreBackupSheetVM.kt @@ -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(null) - val compatibility = MutableLiveData(null) - val selectedComponents = MutableLiveData(setOf()) + val state = mutableStateOf(RestoreBackupState.Parsing) + val metadata = mutableStateOf(null) + val compatibility = mutableStateOf(null) + val selectedComponents = mutableStateOf(setOf()) - val availableComponents = MutableLiveData(emptyList()) + val availableComponents = mutableStateOf(emptyList()) fun setInputUri(uri: Uri) { restoreUri = uri diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/common/WeatherLocationSearchDialog.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/common/WeatherLocationSearchDialog.kt index 6c94088f..d28902dc 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/common/WeatherLocationSearchDialog.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/common/WeatherLocationSearchDialog.kt @@ -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, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/common/WeatherLocationSearchDialogVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/common/WeatherLocationSearchDialogVM.kt index 9a3bb5a3..01231557 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/common/WeatherLocationSearchDialogVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/common/WeatherLocationSearchDialogVM.kt @@ -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>(emptyList()) + val isSearchingLocation = mutableStateOf(false) + val locationResults = mutableStateOf>(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) } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldVM.kt index f7264756..cb4d68a7 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldVM.kt @@ -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 = dataStore .data.map { it.gestures } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt index 17731b4e..c631cc75 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt @@ -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) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PullDownScaffold.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PullDownScaffold.kt index c68e7778..57251740 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PullDownScaffold.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/PullDownScaffold.kt @@ -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 diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/SharedLauncherActivity.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/SharedLauncherActivity.kt index 05bbeff3..0163936c 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/SharedLauncherActivity.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/SharedLauncherActivity.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/LauncherSearchBar.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/LauncherSearchBar.kt index ecc3a729..2337a325 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/LauncherSearchBar.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/searchbar/LauncherSearchBar.kt @@ -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 diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/CustomizeSearchableSheet.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/CustomizeSearchableSheet.kt index 150c4873..585ed6ec 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/CustomizeSearchableSheet.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/CustomizeSearchableSheet.kt @@ -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(null) } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/CustomizeSearchableSheetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/CustomizeSearchableSheetVM.kt index 0895cf6f..2e9d0c52 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/CustomizeSearchableSheetVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/CustomizeSearchableSheetVM.kt @@ -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)) } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt index 75ef65c5..871ceb5b 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheet.kt @@ -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 diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheetVM.kt index bffda3fc..0a9f4182 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheetVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/EditFavoritesSheetVM.kt @@ -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>(emptyList()) + val gridItems = mutableStateOf>(emptyList()) - val loading = MutableLiveData(false) + val loading = mutableStateOf(false) - val createShortcutTarget = MutableLiveData(null) + val createShortcutTarget = mutableStateOf(null) private var manuallySorted: MutableList = mutableListOf() private var automaticallySorted: MutableList = 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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/WidgetPickerSheet.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/WidgetPickerSheet.kt index 91eb8068..aaf82423 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/WidgetPickerSheet.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/sheets/WidgetPickerSheet.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetColumn.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetColumn.kt index 29442760..995107a8 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetColumn.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetColumn.kt @@ -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) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetsVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetsVM.kt index 31d21061..06ef81e5 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetsVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/WidgetsVM.kt @@ -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) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidget.kt index 7b62fb06..e0ae7b81 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidget.kt @@ -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), diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidgetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidgetVM.kt index 496255ae..7d786273 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidgetVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/calendar/CalendarWidgetVM.kt @@ -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>(emptyList()) + val calendarEvents = mutableStateOf>(emptyList()) val pinnedCalendarEvents = favoritesService.getFavorites( includeTypes = listOf(CalendarEvent.Domain), automaticallySorted = true, manuallySorted = true, - ).asLiveData(viewModelScope.coroutineContext) - val nextEvents = MutableLiveData>(emptyList()) + ).stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList()) + val nextEvents = mutableStateOf>(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() } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt index 495d966c..f0fde621 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidget.kt @@ -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) { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidgetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidgetVM.kt index 5b2babc7..8aeb394d 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidgetVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/ClockWidgetVM.kt @@ -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) } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/parts/AlarmPartProvider.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/parts/AlarmPartProvider.kt index 6df1addd..e224d55c 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/parts/AlarmPartProvider.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/clock/parts/AlarmPartProvider.kt @@ -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(null) + private val nextAlarmTime = mutableStateOf(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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/music/MusicWidgetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/music/MusicWidgetVM.kt index f13b6c0d..3c5f7572 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/music/MusicWidgetVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/music/MusicWidgetVM.kt @@ -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 diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/picker/AppWidgetList.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/picker/AppWidgetList.kt deleted file mode 100644 index 0b5969a8..00000000 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/picker/AppWidgetList.kt +++ /dev/null @@ -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, - 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) - } - } - } - } - } - } - - } -} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/picker/PickAppWidgetActivity.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/picker/PickAppWidgetActivity.kt deleted file mode 100644 index 2e25e8f1..00000000 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/picker/PickAppWidgetActivity.kt +++ /dev/null @@ -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() - - 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 - } -} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/picker/PickAppWidgetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/picker/PickAppWidgetVM.kt deleted file mode 100644 index 5bb72549..00000000 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/picker/PickAppWidgetVM.kt +++ /dev/null @@ -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> - -inline val AppWidgetGroup.appName: String - get() = this.first -inline val AppWidgetGroup.widgets: List - get() = this.second - -class PickAppWidgetVM : ViewModel() { - fun getAvailableWidgets(context: Context): LiveData?> = 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) - } -} \ No newline at end of file diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/weather/WeatherWidget.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/weather/WeatherWidget.kt index b2ce8e5c..2701fae4 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/weather/WeatherWidget.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/weather/WeatherWidget.kt @@ -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), diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/weather/WeatherWidgetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/weather/WeatherWidgetVM.kt index 9a8049e6..f64048cb 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/weather/WeatherWidgetVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/launcher/widgets/weather/WeatherWidgetVM.kt @@ -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(getCurrentlySelectedForecast()) + val currentForecast = mutableStateOf(getCurrentlySelectedForecast()) /** * List of forecast summaries for each day */ - val dailyForecasts = MutableLiveData>(emptyList()) + val dailyForecasts = mutableStateOf>(emptyList()) /** * Forecasts of the currently selected day (hourly in most cases). * This is [DailyForecast.hourlyForecasts] of [currentDailyForecast] */ - val currentDayForecasts = MutableLiveData>(emptyList()) + val currentDayForecasts = mutableStateOf>(emptyList()) /** * Daily forecast summary for the currently selected day, one of [dailyForecasts] or null */ - val currentDailyForecast = MutableLiveData(null) + val currentDailyForecast = mutableStateOf(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 } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt index 7a06b4ff..8ab66178 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt @@ -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( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt index 856bf1a8..4befa06f 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/BackupSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/BackupSettingsScreen.kt index 981231ae..6021051f 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/BackupSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/BackupSettingsScreen.kt @@ -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(), diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/BackupSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/BackupSettingsScreenVM.kt index 21d55ca4..3a7df897 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/BackupSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/BackupSettingsScreenVM.kt @@ -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(null) + val restoreUri = mutableStateOf(null) fun setShowBackupSheet(show: Boolean) { showBackupSheet.value = show diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/CreateBackupSheet.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/CreateBackupSheet.kt index 06f271b6..eec262eb 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/CreateBackupSheet.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/CreateBackupSheet.kt @@ -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( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/CreateBackupSheetVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/CreateBackupSheetVM.kt index ae1b0cf0..a17a4317 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/CreateBackupSheetVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/backup/CreateBackupSheetVM.kt @@ -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 diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/cards/CardsSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/cards/CardsSettingsScreen.kt index 97a8373b..015656bf 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/cards/CardsSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/cards/CardsSettingsScreen.kt @@ -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, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/cards/CardsSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/cards/CardsSettingsScreenVM.kt index 9c5e46d1..1d20cacf 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/cards/CardsSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/cards/CardsSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreen.kt index 257af212..eb4644db 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreen.kt @@ -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), diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt index b83a77c8..159df54d 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/clockwidget/ClockWidgetSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreen.kt index 9a3e18d8..f35d82f2 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreen.kt @@ -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), diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreenVM.kt index f48b1329..c33d169a 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/ColorSchemeSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreen.kt index fbec6e7b..1b5e356c 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreen.kt @@ -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) }, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreenVM.kt index fd084ab6..3fa1d43a 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/colorscheme/CustomColorSchemeSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreen.kt index 7fcfd77a..a9adc327 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreen.kt @@ -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" diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreenVM.kt index 183c3f5a..633dc2ee 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreenVM.kt @@ -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 { + fun getCrashReport(fileName: String) = flow { emit(CrashReporter.getCrashReport(fileName)) } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreen.kt index 97fc9634..35570447 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreen.kt @@ -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" diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreenVM.kt index 247f7ade..cabd27b4 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreenVM.kt @@ -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?>(null) + val reports = mutableStateOf?>(null) private var _reports: List? = null init { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/easteregg/EasterEggSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/easteregg/EasterEggSettingsScreen.kt index 277d46c7..b83811b0 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/easteregg/EasterEggSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/easteregg/EasterEggSettingsScreen.kt @@ -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( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/easteregg/EasterEggSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/easteregg/EasterEggSettingsScreenVM.kt index 3ad48569..2602208c 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/easteregg/EasterEggSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/easteregg/EasterEggSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/favorites/FavoritesSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/favorites/FavoritesSettingsScreen.kt index 89821bd4..f9b20153 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/favorites/FavoritesSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/favorites/FavoritesSettingsScreen.kt @@ -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), diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/favorites/FavoritesSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/favorites/FavoritesSettingsScreenVM.kt index 6ee460d8..dd7c0280 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/favorites/FavoritesSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/favorites/FavoritesSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filesearch/FileSearchSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filesearch/FileSearchSettingsScreen.kt index 3efe7ab9..b014ac30 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filesearch/FileSearchSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filesearch/FileSearchSettingsScreen.kt @@ -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), diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filesearch/FileSearchSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filesearch/FileSearchSettingsScreenVM.kt index 078c1846..aa4fc8c5 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filesearch/FileSearchSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/filesearch/FileSearchSettingsScreenVM.kt @@ -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(null) - val owncloudAccount = MutableLiveData(null) - val microsoftAccount = MutableLiveData(null) - val googleAccount = MutableLiveData(null) + val loading = mutableStateOf(true) + val nextcloudAccount = mutableStateOf(null) + val owncloudAccount = mutableStateOf(null) + val microsoftAccount = mutableStateOf(null) + val googleAccount = mutableStateOf(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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreen.kt index d44c75eb..d37e7971 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreen.kt @@ -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 diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreenVM.kt index f99731c0..44b0d517 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/gestures/GestureSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreen.kt index 186738fa..4b0bb166 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreen.kt @@ -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) { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreenVM.kt index a13a32bf..8d58bfff 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/hiddenitems/HiddenItemsSettingsScreenVM.kt @@ -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> = liveData { + }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList()) + val hiddenItems: StateFlow> = 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 { return searchableRepository.isHidden(searchable) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreen.kt index a4a83451..02a3e47c 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreen.kt @@ -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) diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreenVM.kt index 0baf3c1b..19b1113e 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/homescreen/HomescreenSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/integrations/IntegrationsSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/integrations/IntegrationsSettingsScreenVM.kt index 67e510e2..4520e570 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/integrations/IntegrationsSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/integrations/IntegrationsSettingsScreenVM.kt @@ -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 diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/license/LicenseScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/license/LicenseScreen.kt index 037e186b..ef3448bf 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/license/LicenseScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/license/LicenseScreen.kt @@ -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, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/license/LicenseScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/license/LicenseScreenVM.kt index cf6118cf..68be7d16 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/license/LicenseScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/license/LicenseScreenVM.kt @@ -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 { + fun getLicenseText(library: OpenSourceLibrary) = flow { val text = withContext(Dispatchers.IO) { context.resources.openRawResource(library.licenseText).reader() .readText() diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/media/MediaIntegrationSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/media/MediaIntegrationSettingsScreen.kt index d767142c..38146981 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/media/MediaIntegrationSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/media/MediaIntegrationSettingsScreen.kt @@ -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 diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt index 67023279..871e7e7b 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt @@ -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 diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt index ee69276e..5715c138 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreen.kt index c7190cd7..9c2087df 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreen.kt @@ -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( diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreenVM.kt index f68e2d69..5619813f 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/searchactions/SearchActionsSettingsScreenVM.kt @@ -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(null) - val showCreateDialog = MutableLiveData(false) + val showEditDialogFor = mutableStateOf(null) + val showCreateDialog = mutableStateOf(false) fun editAction(action: CustomizableSearchActionBuilder) { showEditDialogFor.value = action diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/unitconverter/UnitConverterSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/unitconverter/UnitConverterSettingsScreen.kt index c9f9b8da..ed090fd6 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/unitconverter/UnitConverterSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/unitconverter/UnitConverterSettingsScreen.kt @@ -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), diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/unitconverter/UnitConverterSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/unitconverter/UnitConverterSettingsScreenVM.kt index 4cec43a5..16ec997b 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/unitconverter/UnitConverterSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/unitconverter/UnitConverterSettingsScreenVM.kt @@ -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 { diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreen.kt index b292788c..2292f9cd 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreen.kt @@ -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, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreenVM.kt index 4455c45f..fadecea1 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/weather/WeatherIntegrationSettingsScreenVM.kt @@ -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(null) + val location = mutableStateOf(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 } } } diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/wikipedia/WikipediaSettingsScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/wikipedia/WikipediaSettingsScreen.kt index 11a17c06..e78119a0 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/wikipedia/WikipediaSettingsScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/wikipedia/WikipediaSettingsScreen.kt @@ -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, diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/wikipedia/WikipediaSettingsScreenVM.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/wikipedia/WikipediaSettingsScreenVM.kt index f93997ce..89c32577 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/settings/wikipedia/WikipediaSettingsScreenVM.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/settings/wikipedia/WikipediaSettingsScreenVM.kt @@ -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 { diff --git a/core/database/src/main/java/de/mm20/launcher2/database/IconDao.kt b/core/database/src/main/java/de/mm20/launcher2/database/IconDao.kt index 38feca44..f45ab415 100644 --- a/core/database/src/main/java/de/mm20/launcher2/database/IconDao.kt +++ b/core/database/src/main/java/de/mm20/launcher2/database/IconDao.kt @@ -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 diff --git a/settings.gradle.kts b/settings.gradle.kts index 21c7a4e1..0694ddeb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -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" )