Get rid of LiveData

This commit is contained in:
MM20 2023-04-20 21:40:29 +02:00
parent 0e40355ae1
commit d1482ad112
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
77 changed files with 433 additions and 816 deletions

View File

@ -68,7 +68,6 @@ dependencies {
implementation(libs.bundles.kotlin) implementation(libs.bundles.kotlin)
implementation(libs.androidx.compose.runtime) implementation(libs.androidx.compose.runtime)
implementation(libs.androidx.compose.livedata)
implementation(libs.androidx.compose.foundation) implementation(libs.androidx.compose.foundation)
implementation(libs.androidx.compose.foundationlayout) implementation(libs.androidx.compose.foundationlayout)
implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.ui)

View File

@ -58,19 +58,6 @@
android:value="de.mm20.launcher2.ui.launcher.SharedLauncherActivity" /> android:value="de.mm20.launcher2.ui.launcher.SharedLauncherActivity" />
</activity> </activity>
<activity
android:name=".launcher.widgets.picker.PickAppWidgetActivity"
android:exported="true"
android:launchMode="singleTask"
android:parentActivityName=".launcher.SharedLauncherActivity"
android:screenOrientation="portrait"
android:taskAffinity="de.mm20.launcher2.settings"
android:theme="@style/SettingsTheme.NoActionBar">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="de.mm20.launcher2.ui.launcher.SharedLauncherActivity" />
</activity>
<activity <activity
android:name=".launcher.sheets.BindAndConfigureAppWidgetActivity" android:name=".launcher.sheets.BindAndConfigureAppWidgetActivity"
/> />

View File

@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
@ -178,8 +177,8 @@ fun AssistantScaffold(
val value by searchVM.searchQuery val value by searchVM.searchQuery
val searchBarColor by viewModel.searchBarColor.observeAsState(Settings.SearchBarSettings.SearchBarColors.Auto) val searchBarColor by viewModel.searchBarColor.collectAsState()
val searchBarStyle by viewModel.searchBarStyle.observeAsState(Settings.SearchBarSettings.SearchBarStyle.Transparent) val searchBarStyle by viewModel.searchBarStyle.collectAsState()
val launchOnEnter by searchVM.launchOnEnter.collectAsState(false) val launchOnEnter by searchVM.launchOnEnter.collectAsState(false)

View File

@ -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()
}
}

View File

@ -12,7 +12,6 @@ import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -38,9 +37,9 @@ fun RestoreBackupSheet(
viewModel.setInputUri(uri) viewModel.setInputUri(uri)
} }
val state by viewModel.state.observeAsState(RestoreBackupState.Parsing) val state by viewModel.state
val selectedComponents by viewModel.selectedComponents.observeAsState(emptySet()) val selectedComponents by viewModel.selectedComponents
val compatibility by viewModel.compatibility.observeAsState(null) val compatibility by viewModel.compatibility
BottomSheetDialog( BottomSheetDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
@ -103,7 +102,7 @@ fun RestoreBackupSheet(
) )
} }
RestoreBackupState.Ready -> { RestoreBackupState.Ready -> {
val metadata by viewModel.metadata.observeAsState(null) val metadata by viewModel.metadata
if (metadata != null) { if (metadata != null) {
Column { Column {
@ -153,9 +152,7 @@ fun RestoreBackupSheet(
style = MaterialTheme.typography.titleSmall, style = MaterialTheme.typography.titleSmall,
modifier = Modifier.padding(top = 8.dp, bottom = 4.dp) modifier = Modifier.padding(top = 8.dp, bottom = 4.dp)
) )
val components by viewModel.availableComponents.observeAsState( val components by viewModel.availableComponents
emptyList()
)
for (component in components) { for (component in components) {
Row( Row(
modifier = Modifier modifier = Modifier

View File

@ -1,7 +1,7 @@
package de.mm20.launcher2.ui.common package de.mm20.launcher2.ui.common
import android.net.Uri import android.net.Uri
import androidx.lifecycle.MutableLiveData import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.backup.BackupCompatibility import de.mm20.launcher2.backup.BackupCompatibility
@ -18,12 +18,12 @@ class RestoreBackupSheetVM : ViewModel(), KoinComponent {
private var restoreUri: Uri? = null private var restoreUri: Uri? = null
val state = MutableLiveData(RestoreBackupState.Parsing) val state = mutableStateOf(RestoreBackupState.Parsing)
val metadata = MutableLiveData<BackupMetadata?>(null) val metadata = mutableStateOf<BackupMetadata?>(null)
val compatibility = MutableLiveData<BackupCompatibility?>(null) val compatibility = mutableStateOf<BackupCompatibility?>(null)
val selectedComponents = MutableLiveData(setOf<BackupComponent>()) val selectedComponents = mutableStateOf(setOf<BackupComponent>())
val availableComponents = MutableLiveData(emptyList<BackupComponent>()) val availableComponents = mutableStateOf(emptyList<BackupComponent>())
fun setInputUri(uri: Uri) { fun setInputUri(uri: Uri) {
restoreUri = uri restoreUri = uri

View File

@ -12,7 +12,6 @@ import androidx.compose.material.icons.rounded.Error
import androidx.compose.material.icons.rounded.Search import androidx.compose.material.icons.rounded.Search
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -29,8 +28,8 @@ fun WeatherLocationSearchDialog(
) { ) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val viewModel: WeatherLocationSearchDialogVM = viewModel() val viewModel: WeatherLocationSearchDialogVM = viewModel()
val isSearching by viewModel.isSearchingLocation.observeAsState(initial = false) val isSearching by viewModel.isSearchingLocation
val locations by viewModel.locationResults.observeAsState(emptyList()) val locations by viewModel.locationResults
BottomSheetDialog( BottomSheetDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,

View File

@ -1,6 +1,6 @@
package de.mm20.launcher2.ui.common package de.mm20.launcher2.ui.common
import androidx.lifecycle.MutableLiveData import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import de.mm20.launcher2.weather.WeatherLocation import de.mm20.launcher2.weather.WeatherLocation
import de.mm20.launcher2.weather.WeatherRepository import de.mm20.launcher2.weather.WeatherRepository
@ -12,8 +12,8 @@ import kotlin.coroutines.coroutineContext
class WeatherLocationSearchDialogVM: ViewModel(), KoinComponent { class WeatherLocationSearchDialogVM: ViewModel(), KoinComponent {
private val repository: WeatherRepository by inject() private val repository: WeatherRepository by inject()
val isSearchingLocation = MutableLiveData(false) val isSearchingLocation = mutableStateOf(false)
val locationResults = MutableLiveData<List<WeatherLocation>>(emptyList()) val locationResults = mutableStateOf<List<WeatherLocation>>(emptyList())
private var debounceSearchJob: Job? = null private var debounceSearchJob: Job? = null
suspend fun searchLocation(query: String) { suspend fun searchLocation(query: String) {
@ -34,7 +34,7 @@ class WeatherLocationSearchDialogVM: ViewModel(), KoinComponent {
} }
fun setLocation(location: WeatherLocation) { fun setLocation(location: WeatherLocation) {
locationResults.postValue(emptyList()) locationResults.value = emptyList()
repository.setAutoLocation(false) repository.setAutoLocation(false)
repository.setLocation(location) repository.setLocation(location)
} }

View File

@ -6,9 +6,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.core.app.ActivityOptionsCompat import androidx.core.app.ActivityOptionsCompat
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.searchable.SearchableRepository import de.mm20.launcher2.searchable.SearchableRepository
import de.mm20.launcher2.globalactions.GlobalActionsService import de.mm20.launcher2.globalactions.GlobalActionsService
@ -48,13 +46,17 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
) { dim, theme, systemDarkMode -> ) { dim, theme, systemDarkMode ->
dim && (theme == Settings.AppearanceSettings.Theme.Dark || theme == Settings.AppearanceSettings.Theme.System && 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 statusBarColor = dataStore.data.map { it.systemBars.statusBarColor }
val navBarColor = dataStore.data.map { it.systemBars.statusBarColor }.asLiveData() .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 hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }.asLiveData() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
fun setSystemInDarkMode(darkMode: Boolean) { fun setSystemInDarkMode(darkMode: Boolean) {
isSystemInDarkMode.value = darkMode isSystemInDarkMode.value = darkMode
@ -62,15 +64,19 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
val baseLayout = dataStore.data.map { it.layout.baseLayout } val baseLayout = dataStore.data.map { it.layout.baseLayout }
.stateIn(viewModelScope, SharingStarted.Eagerly, null) .stateIn(viewModelScope, SharingStarted.Eagerly, null)
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }.asLiveData() val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }.asLiveData() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }.asLiveData() val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
val fixedRotation = dataStore.data.map { it.layout.fixedRotation }.asLiveData() .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 isSearchOpen = mutableStateOf(false)
val isWidgetEditMode = MutableLiveData(false) val isWidgetEditMode = mutableStateOf(false)
val searchBarFocused = MutableLiveData(false) val searchBarFocused = mutableStateOf(false)
val autoFocusSearch = dataStore.data.map { it.searchBar.autoFocus } val autoFocusSearch = dataStore.data.map { it.searchBar.autoFocus }
@ -103,10 +109,14 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
isWidgetEditMode.value = editMode isWidgetEditMode.value = editMode
} }
val wallpaperBlur = dataStore.data.map { it.appearance.blurWallpaper }.asLiveData() val wallpaperBlur = dataStore.data.map { it.appearance.blurWallpaper }
val fillClockHeight = dataStore.data.map { it.clockWidget.fillHeight }.asLiveData() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
val searchBarColor = dataStore.data.map { it.searchBar.color }.asLiveData() val fillClockHeight = dataStore.data.map { it.clockWidget.fillHeight }
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }.asLiveData() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), true)
val searchBarColor = dataStore.data.map { it.searchBar.color }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Settings.SearchBarSettings.SearchBarColors.Auto)
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Settings.SearchBarSettings.SearchBarStyle.Transparent)
val gestureState: StateFlow<GestureState> = dataStore val gestureState: StateFlow<GestureState> = dataStore
.data.map { it.gestures } .data.map { it.gestures }

View File

@ -46,7 +46,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
@ -101,8 +100,8 @@ fun PagerScaffold(
val context = LocalContext.current val context = LocalContext.current
val isSearchOpen by viewModel.isSearchOpen.observeAsState(false) val isSearchOpen by viewModel.isSearchOpen
val isWidgetEditMode by viewModel.isWidgetEditMode.observeAsState(false) val isWidgetEditMode by viewModel.isWidgetEditMode
val actions by searchVM.searchActionResults 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 { val showNavBarScrim by remember {
derivedStateOf { derivedStateOf {
@ -199,7 +198,7 @@ fun PagerScaffold(
} }
} }
val blurEnabled by viewModel.wallpaperBlur.observeAsState(false) val blurEnabled by viewModel.wallpaperBlur.collectAsState()
val blurWallpaper by remember { val blurWallpaper by remember {
derivedStateOf { derivedStateOf {
@ -369,11 +368,17 @@ fun PagerScaffold(
.fillMaxHeight() .fillMaxHeight()
.pointerInput(gestureManager.shouldDetectDoubleTaps) { .pointerInput(gestureManager.shouldDetectDoubleTaps) {
detectTapGestures( detectTapGestures(
onDoubleTap = if (gestureManager.shouldDetectDoubleTaps) {{ onDoubleTap = if (gestureManager.shouldDetectDoubleTaps) {
if (!isWidgetEditMode) gestureManager.dispatchDoubleTap(it) {
}} else null, if (!isWidgetEditMode) gestureManager.dispatchDoubleTap(
it
)
}
} else null,
onLongPress = { onLongPress = {
if (!isWidgetEditMode) gestureManager.dispatchLongPress(it) if (!isWidgetEditMode) gestureManager.dispatchLongPress(
it
)
}, },
onTap = { onTap = {
if (!isWidgetEditMode) gestureManager.dispatchTap(it) 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( val widgetEditModeOffset by animateDpAsState(
(if (isWidgetEditMode) 128.dp else 0.dp) * (if (bottomSearchBar) 1 else -1) (if (isWidgetEditMode) 128.dp else 0.dp) * (if (bottomSearchBar) 1 else -1)
@ -499,8 +504,8 @@ fun PagerScaffold(
val value by searchVM.searchQuery val value by searchVM.searchQuery
val searchBarColor by viewModel.searchBarColor.observeAsState(SearchBarColors.Auto) val searchBarColor by viewModel.searchBarColor.collectAsState()
val searchBarStyle by viewModel.searchBarStyle.observeAsState(SearchBarStyle.Transparent) val searchBarStyle by viewModel.searchBarStyle.collectAsState()
val launchOnEnter by searchVM.launchOnEnter.collectAsState(false) val launchOnEnter by searchVM.launchOnEnter.collectAsState(false)

View File

@ -43,7 +43,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
@ -100,8 +99,8 @@ fun PullDownScaffold(
val actions by searchVM.searchActionResults val actions by searchVM.searchActionResults
val isSearchOpen by viewModel.isSearchOpen.observeAsState(false) val isSearchOpen by viewModel.isSearchOpen
val isWidgetEditMode by viewModel.isWidgetEditMode.observeAsState(false) val isWidgetEditMode by viewModel.isWidgetEditMode
val widgetsScrollState = rememberScrollState() val widgetsScrollState = rememberScrollState()
val searchState = rememberLazyListState() 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 { val showStatusBarScrim by remember {
derivedStateOf { derivedStateOf {
@ -210,7 +209,7 @@ fun PullDownScaffold(
val maxSearchBarOffset = with(density) { 128.dp.toPx() } val maxSearchBarOffset = with(density) { 128.dp.toPx() }
val blurEnabled by viewModel.wallpaperBlur.observeAsState(false) val blurEnabled by viewModel.wallpaperBlur.collectAsState()
val blurWallpaper by remember { val blurWallpaper by remember {
derivedStateOf { derivedStateOf {
@ -516,15 +515,15 @@ fun PullDownScaffold(
} }
} }
} }
val searchBarFocused by viewModel.searchBarFocused.observeAsState(false) val searchBarFocused by viewModel.searchBarFocused
val editModeSearchBarOffset by animateDpAsState( val editModeSearchBarOffset by animateDpAsState(
(if (isWidgetEditMode) 128.dp else 0.dp) * (if (bottomSearchBar) 1 else -1) (if (isWidgetEditMode) 128.dp else 0.dp) * (if (bottomSearchBar) 1 else -1)
) )
val value by searchVM.searchQuery val value by searchVM.searchQuery
val searchBarColor by viewModel.searchBarColor.observeAsState(Settings.SearchBarSettings.SearchBarColors.Auto) val searchBarColor by viewModel.searchBarColor.collectAsState()
val searchBarStyle by viewModel.searchBarStyle.observeAsState(Settings.SearchBarSettings.SearchBarStyle.Transparent) val searchBarStyle by viewModel.searchBarStyle.collectAsState()
val context = LocalContext.current val context = LocalContext.current

View File

@ -19,7 +19,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.key import androidx.compose.runtime.key
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@ -90,7 +89,7 @@ abstract class SharedLauncherActivity(
setContent { setContent {
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
val wallpaperColors by wallpaperColorsAsState() val wallpaperColors by wallpaperColorsAsState()
val dimBackground by viewModel.dimBackground.observeAsState(false) val dimBackground by viewModel.dimBackground.collectAsState()
CompositionLocalProvider( CompositionLocalProvider(
LocalEnterHomeTransitionManager provides enterHomeTransitionManager, LocalEnterHomeTransitionManager provides enterHomeTransitionManager,
LocalWindowSize provides windowSize, LocalWindowSize provides windowSize,
@ -103,24 +102,24 @@ abstract class SharedLauncherActivity(
LauncherTheme { LauncherTheme {
ProvideCurrentTime { ProvideCurrentTime {
ProvideSettings { ProvideSettings {
val statusBarColor by viewModel.statusBarColor.observeAsState( val statusBarColor by viewModel.statusBarColor.collectAsState()
SystemBarColors.Auto val navBarColor by viewModel.navBarColor.collectAsState()
)
val navBarColor by viewModel.navBarColor.observeAsState(SystemBarColors.Auto)
val lightStatus = val lightStatus =
!dimBackground && (statusBarColor == SystemBarColors.Dark || statusBarColor == SystemBarColors.Auto && wallpaperColors.supportsDarkText) !dimBackground && (statusBarColor == SystemBarColors.Dark || statusBarColor == SystemBarColors.Auto && wallpaperColors.supportsDarkText)
val lightNav = val lightNav =
!dimBackground && (navBarColor == SystemBarColors.Dark || navBarColor == SystemBarColors.Auto && wallpaperColors.supportsDarkText) !dimBackground && (navBarColor == SystemBarColors.Dark || navBarColor == SystemBarColors.Auto && wallpaperColors.supportsDarkText)
val hideStatus by viewModel.hideStatusBar.observeAsState(false) val hideStatus by viewModel.hideStatusBar.collectAsState()
val hideNav by viewModel.hideNavBar.observeAsState(false) val hideNav by viewModel.hideNavBar.collectAsState()
val layout by viewModel.baseLayout.collectAsState(null) val layout by viewModel.baseLayout.collectAsState(null)
val bottomSearchBar by viewModel.bottomSearchBar.observeAsState(false) val bottomSearchBar by viewModel.bottomSearchBar.collectAsState()
val reverseSearchResults by viewModel.reverseSearchResults.observeAsState(false) val reverseSearchResults by viewModel.reverseSearchResults.collectAsState()
val fixedSearchBar by viewModel.fixedSearchBar.observeAsState(false) val fixedSearchBar by viewModel.fixedSearchBar.collectAsState()
viewModel.fixedRotation.observe(this) { fixedRotation -> val fixedRotation by viewModel.fixedRotation.collectAsState()
LaunchedEffect(fixedRotation) {
requestedOrientation = if (fixedRotation) { requestedOrientation = if (fixedRotation) {
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
} else { } else {

View File

@ -13,7 +13,6 @@ import androidx.compose.material3.IconButtonDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester

View File

@ -31,7 +31,6 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
@ -180,11 +179,11 @@ fun CustomizeSearchableSheet(
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val suggestions by remember { viewModel.getIconSuggestions(iconSizePx.toInt()) } val suggestions by remember { viewModel.getIconSuggestions(iconSizePx.toInt()) }
.observeAsState(emptyList()) .collectAsState(emptyList())
val defaultIcon by remember { val defaultIcon by remember {
viewModel.getDefaultIcon(iconSizePx.toInt()) viewModel.getDefaultIcon(iconSizePx.toInt())
}.observeAsState() }.collectAsState(null)
var query by remember { mutableStateOf("") } var query by remember { mutableStateOf("") }
var filterIconPack by remember { mutableStateOf<IconPack?>(null) } var filterIconPack by remember { mutableStateOf<IconPack?>(null) }

View File

@ -1,7 +1,6 @@
package de.mm20.launcher2.ui.launcher.sheets package de.mm20.launcher2.ui.launcher.sheets
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.liveData
import de.mm20.launcher2.data.customattrs.CustomAttributesRepository import de.mm20.launcher2.data.customattrs.CustomAttributesRepository
import de.mm20.launcher2.data.customattrs.CustomIcon import de.mm20.launcher2.data.customattrs.CustomIcon
import de.mm20.launcher2.icons.CustomIconWithPreview import de.mm20.launcher2.icons.CustomIconWithPreview
@ -14,6 +13,7 @@ import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
@ -32,7 +32,7 @@ class CustomizeSearchableSheetVM(
return iconService.getIcon(searchable, size) return iconService.getIcon(searchable, size)
} }
fun getIconSuggestions(size: Int) = liveData { fun getIconSuggestions(size: Int) = flow {
emit(iconService.getCustomIconSuggestions(searchable, size)) emit(iconService.getCustomIconSuggestions(searchable, size))
} }
@ -49,7 +49,7 @@ class CustomizeSearchableSheetVM(
closeIconPicker() closeIconPicker()
} }
fun getDefaultIcon(size: Int) = liveData { fun getDefaultIcon(size: Int) = flow {
emit(iconService.getUncustomizedDefaultIcon(searchable, size)) emit(iconService.getUncustomizedDefaultIcon(searchable, size))
} }

View File

@ -51,7 +51,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@ -102,8 +101,8 @@ fun EditFavoritesSheet(
viewModel.reload() viewModel.reload()
} }
val loading by viewModel.loading.observeAsState(true) val loading by viewModel.loading
val createShortcutTarget by viewModel.createShortcutTarget.observeAsState(null) val createShortcutTarget by viewModel.createShortcutTarget
BottomSheetDialog( BottomSheetDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
@ -157,7 +156,7 @@ fun EditFavoritesSheet(
@Composable @Composable
fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: PaddingValues) { fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: PaddingValues) {
val items by viewModel.gridItems.observeAsState(emptyList()) val items by viewModel.gridItems
val columns = LocalGridSettings.current.columnCount val columns = LocalGridSettings.current.columnCount
val availableTags by viewModel.availableTags val availableTags by viewModel.availableTags
@ -336,10 +335,8 @@ fun ReorderFavoritesGrid(viewModel: EditFavoritesSheetVM, paddingValues: Padding
} }
} }
} }
val enableFrequentlyUsed by viewModel.enableFrequentlyUsed.observeAsState( val enableFrequentlyUsed by viewModel.enableFrequentlyUsed.collectAsState()
null val frequentlyUsedRows by viewModel.frequentlyUsedRows.collectAsState()
)
val frequentlyUsedRows by viewModel.frequentlyUsedRows.observeAsState(1)
AnimatedVisibility(showSettings) { AnimatedVisibility(showSettings) {
Surface( Surface(
modifier = Modifier modifier = Modifier

View File

@ -6,9 +6,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.lazy.LazyListItemInfo import androidx.compose.foundation.lazy.LazyListItemInfo
import androidx.compose.foundation.lazy.grid.LazyGridItemInfo import androidx.compose.foundation.lazy.grid.LazyGridItemInfo
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.appshortcuts.AppShortcutRepository import de.mm20.launcher2.appshortcuts.AppShortcutRepository
import de.mm20.launcher2.badges.Badge 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.search.data.Tag
import de.mm20.launcher2.services.favorites.FavoritesService import de.mm20.launcher2.services.favorites.FavoritesService
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -43,11 +43,11 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
private val permissionsManager: PermissionsManager by inject() private val permissionsManager: PermissionsManager by inject()
private val dataStore: LauncherDataStore by inject() private val dataStore: LauncherDataStore by inject()
val gridItems = MutableLiveData<List<FavoritesSheetGridItem>>(emptyList()) val gridItems = mutableStateOf<List<FavoritesSheetGridItem>>(emptyList())
val loading = MutableLiveData(false) val loading = mutableStateOf(false)
val createShortcutTarget = MutableLiveData<FavoritesSheetSection?>(null) val createShortcutTarget = mutableStateOf<FavoritesSheetSection?>(null)
private var manuallySorted: MutableList<SavableSearchable> = mutableListOf() private var manuallySorted: MutableList<SavableSearchable> = mutableListOf()
private var automaticallySorted: MutableList<SavableSearchable> = mutableListOf() private var automaticallySorted: MutableList<SavableSearchable> = mutableListOf()
@ -245,7 +245,8 @@ class EditFavoritesSheetVM : ViewModel(), KoinComponent {
} }
} }
val enableFrequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }.asLiveData() val enableFrequentlyUsed = dataStore.data.map { it.favorites.frequentlyUsed }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setFrequentlyUsed(frequentlyUsed: Boolean) { fun setFrequentlyUsed(frequentlyUsed: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -59,7 +59,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage import coil.compose.AsyncImage
import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.BottomSheetDialog 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.CalendarWidget
import de.mm20.launcher2.widgets.AppWidget import de.mm20.launcher2.widgets.AppWidget
import de.mm20.launcher2.widgets.AppWidgetConfig import de.mm20.launcher2.widgets.AppWidgetConfig
@ -111,7 +110,7 @@ class BindAndConfigureAppWidgetActivity : Activity() {
AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE, AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE,
appWidgetProviderInfo.profile appWidgetProviderInfo.profile
) )
}, PickAppWidgetActivity.RequestCodeBind }, RequestCodeBind
) )
} }
} }
@ -122,7 +121,7 @@ class BindAndConfigureAppWidgetActivity : Activity() {
this, this,
appWidgetId, appWidgetId,
0, 0,
PickAppWidgetActivity.RequestCodeConfigure, RequestCodeConfigure,
null null
) )
} else { } else {

View File

@ -18,9 +18,9 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.key import androidx.compose.runtime.key
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
@ -77,7 +77,7 @@ fun WidgetColumn(
) { ) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
Column { Column {
val widgets by viewModel.widgets.observeAsState(emptyList()) val widgets by viewModel.widgets.collectAsState()
val swapThresholds = remember(widgets) { val swapThresholds = remember(widgets) {
Array(widgets.size) { floatArrayOf(0f, 0f) } 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) { if (editButton == true) {
val icon = val icon =
AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_edit_add) AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_edit_add)

View File

@ -2,11 +2,13 @@ package de.mm20.launcher2.ui.launcher.widgets
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.widgets.Widget import de.mm20.launcher2.widgets.Widget
import de.mm20.launcher2.widgets.WidgetRepository import de.mm20.launcher2.widgets.WidgetRepository
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -15,12 +17,14 @@ class WidgetsVM : ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject() 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) { fun addWidget(widget: Widget) {
val widgets = widgets.value?.toMutableList() ?: return val widgets = widgets.value.toMutableList()
widgets.add(widget) widgets.add(widget)
widgetRepository.set(widgets) widgetRepository.set(widgets)
} }
@ -34,14 +38,14 @@ class WidgetsVM : ViewModel(), KoinComponent {
} }
fun moveUp(index: Int) { fun moveUp(index: Int) {
val widgets = widgets.value?.toMutableList() ?: return val widgets = widgets.value.toMutableList()
val widget = widgets.removeAt(index) val widget = widgets.removeAt(index)
widgets.add(index - 1, widget) widgets.add(index - 1, widget)
widgetRepository.set(widgets) widgetRepository.set(widgets)
} }
fun moveDown(index: Int) { fun moveDown(index: Int) {
val widgets = widgets.value?.toMutableList() ?: return val widgets = widgets.value.toMutableList()
val widget = widgets.removeAt(index) val widget = widgets.removeAt(index)
widgets.add(index + 1, widget) widgets.add(index + 1, widget)
widgetRepository.set(widgets) widgetRepository.set(widgets)

View File

@ -10,9 +10,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.* import androidx.compose.material.icons.rounded.*
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
@ -61,7 +59,7 @@ fun CalendarWidget(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
val selectedDate by viewModel.selectedDate.observeAsState(LocalDate.now()) val selectedDate by viewModel.selectedDate
var showDropdown by remember { mutableStateOf(false) } var showDropdown by remember { mutableStateOf(false) }
TextButton(onClick = { showDropdown = true }) { TextButton(onClick = { showDropdown = true }) {
Text( Text(
@ -99,8 +97,8 @@ fun CalendarWidget(
Icon(imageVector = Icons.Rounded.OpenInNew, contentDescription = null) Icon(imageVector = Icons.Rounded.OpenInNew, contentDescription = null)
} }
} }
val events by viewModel.calendarEvents.observeAsState(emptyList()) val events by viewModel.calendarEvents
val hasPermission by viewModel.hasPermission.observeAsState() val hasPermission by viewModel.hasPermission.collectAsState()
Column( Column(
modifier = Modifier modifier = Modifier
.animateContentSize() .animateContentSize()
@ -124,7 +122,7 @@ fun CalendarWidget(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
) )
val runningEvents by viewModel.hiddenPastEvents.observeAsState(0) val runningEvents by viewModel.hiddenPastEvents
if (runningEvents > 0) { if (runningEvents > 0) {
Info( Info(
text = pluralStringResource( text = pluralStringResource(
@ -137,7 +135,7 @@ fun CalendarWidget(
} }
) )
} }
val nextEvents by viewModel.nextEvents.observeAsState(emptyList()) val nextEvents by viewModel.nextEvents
if (nextEvents.isNotEmpty()) { if (nextEvents.isNotEmpty()) {
Text( Text(
stringResource(R.string.calendar_widget_next_events), stringResource(R.string.calendar_widget_next_events),
@ -150,7 +148,7 @@ fun CalendarWidget(
.fillMaxWidth() .fillMaxWidth()
) )
} }
val pinnedEvents by viewModel.pinnedCalendarEvents.observeAsState(emptyList()) val pinnedEvents by viewModel.pinnedCalendarEvents.collectAsState()
if (pinnedEvents.isNotEmpty()) { if (pinnedEvents.isNotEmpty()) {
Text( Text(
stringResource(R.string.calendar_widget_pinned_events), stringResource(R.string.calendar_widget_pinned_events),

View File

@ -5,23 +5,22 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.provider.CalendarContract import android.provider.CalendarContract
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.calendar.CalendarRepository import de.mm20.launcher2.calendar.CalendarRepository
import de.mm20.launcher2.searchable.SearchableRepository import de.mm20.launcher2.searchable.SearchableRepository
import de.mm20.launcher2.ktx.tryStartActivity import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.permissions.PermissionGroup import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.search.data.CalendarEvent import de.mm20.launcher2.search.data.CalendarEvent
import de.mm20.launcher2.services.favorites.FavoritesService import de.mm20.launcher2.services.favorites.FavoritesService
import de.mm20.launcher2.widgets.CalendarWidget import de.mm20.launcher2.widgets.CalendarWidget
import de.mm20.launcher2.widgets.CalendarWidgetConfig import de.mm20.launcher2.widgets.CalendarWidgetConfig
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.collectLatest 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.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
import java.lang.Integer.min import java.lang.Integer.min
@ -39,23 +38,24 @@ class CalendarWidgetVM : ViewModel(), KoinComponent {
private val widgetConfig = MutableStateFlow(CalendarWidgetConfig()) private val widgetConfig = MutableStateFlow(CalendarWidgetConfig())
val calendarEvents = MutableLiveData<List<CalendarEvent>>(emptyList()) val calendarEvents = mutableStateOf<List<CalendarEvent>>(emptyList())
val pinnedCalendarEvents = val pinnedCalendarEvents =
favoritesService.getFavorites( favoritesService.getFavorites(
includeTypes = listOf(CalendarEvent.Domain), includeTypes = listOf(CalendarEvent.Domain),
automaticallySorted = true, automaticallySorted = true,
manuallySorted = true, manuallySorted = true,
).asLiveData(viewModelScope.coroutineContext) ).stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
val nextEvents = MutableLiveData<List<CalendarEvent>>(emptyList()) val nextEvents = mutableStateOf<List<CalendarEvent>>(emptyList())
var availableDates = listOf(LocalDate.now()) var availableDates = listOf(LocalDate.now())
private val permissionsManager: PermissionsManager by inject() 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 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) { fun updateWidget(widget: CalendarWidget) {
widgetConfig.value = widget.config widgetConfig.value = widget.config
@ -147,17 +147,17 @@ class CalendarWidgetVM : ViewModel(), KoinComponent {
} }
val hiddenCount = totalCount - events.size val hiddenCount = totalCount - events.size
hiddenPastEvents.postValue(hiddenCount) hiddenPastEvents.value = hiddenCount
} else { } else {
hiddenPastEvents.postValue(0) hiddenPastEvents.value = 0
} }
calendarEvents.postValue(events) calendarEvents.value = events
val e = this.upcomingEvents val e = this.upcomingEvents
if (events.isEmpty() && e.isNotEmpty()) { if (events.isEmpty() && e.isNotEmpty()) {
nextEvents.postValue(listOf(e[0])) nextEvents.value = listOf(e[0])
} else { } else {
nextEvents.postValue(emptyList()) nextEvents.value = emptyList()
} }
} }

View File

@ -16,8 +16,8 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -44,9 +44,9 @@ fun ClockWidget(
) { ) {
val viewModel: ClockWidgetVM = viewModel() val viewModel: ClockWidgetVM = viewModel()
val context = LocalContext.current val context = LocalContext.current
val layout by viewModel.layout.observeAsState() val layout by viewModel.layout.collectAsState()
val clockStyle by viewModel.clockStyle.observeAsState() val clockStyle by viewModel.clockStyle.collectAsState()
val color by viewModel.color.observeAsState() val color by viewModel.color.collectAsState()
val time = LocalTime.current val time = LocalTime.current
LaunchedEffect(time) { LaunchedEffect(time) {

View File

@ -4,7 +4,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.provider.AlarmClock import android.provider.AlarmClock
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.ktx.tryStartActivity import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
@ -55,10 +54,13 @@ class ClockWidgetVM : ViewModel(), KoinComponent {
} }
} }
val layout = dataStore.data.map { it.clockWidget.layout }.asLiveData() val layout = dataStore.data.map { it.clockWidget.layout }
val clockStyle = dataStore.data.map { it.clockWidget.clockStyle }.asLiveData() .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) { fun updateTime(time: Long) {
partProviders.value.forEach { it.setTime(time) } partProviders.value.forEach { it.setTime(time) }

View File

@ -15,12 +15,11 @@ import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue 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.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.lifecycle.MutableLiveData
import de.mm20.launcher2.ktx.tryStartActivity import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
@ -29,7 +28,7 @@ import kotlinx.coroutines.flow.*
class AlarmPartProvider : PartProvider { class AlarmPartProvider : PartProvider {
private val nextAlarmTime = MutableLiveData<Long?>(null) private val nextAlarmTime = mutableStateOf<Long?>(null)
private val time = MutableStateFlow(System.currentTimeMillis()) private val time = MutableStateFlow(System.currentTimeMillis())
@ -75,7 +74,7 @@ class AlarmPartProvider : PartProvider {
override fun Component(layout: ClockWidgetLayout) { override fun Component(layout: ClockWidgetLayout) {
val context = LocalContext.current val context = LocalContext.current
val alarmTime by nextAlarmTime.observeAsState(null) val alarmTime by nextAlarmTime
val time by this.time.collectAsState(System.currentTimeMillis()) val time by this.time.collectAsState(System.currentTimeMillis())
alarmTime?.let { alarmTime?.let {

View File

@ -5,10 +5,7 @@ import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.media.session.PlaybackState.CustomAction import android.media.session.PlaybackState.CustomAction
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.compose.ui.graphics.Color
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import de.mm20.launcher2.crashreporter.CrashReporter import de.mm20.launcher2.crashreporter.CrashReporter
import de.mm20.launcher2.music.MusicService import de.mm20.launcher2.music.MusicService
import de.mm20.launcher2.music.PlaybackState 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.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager import de.mm20.launcher2.permissions.PermissionsManager
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject

View File

@ -1,118 +0,0 @@
package de.mm20.launcher2.ui.launcher.widgets.picker
import android.appwidget.AppWidgetProviderInfo
import android.graphics.drawable.Drawable
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import de.mm20.launcher2.ktx.isAtLeastApiLevel
import de.mm20.launcher2.ui.component.LauncherCard
import de.mm20.launcher2.ui.ktx.toDp
@Composable
fun AppWidgetList(
modifier: Modifier = Modifier,
widgets: List<AppWidgetGroup>,
onWidgetSelected: (AppWidgetProviderInfo) -> Unit = {}
) {
val context = LocalContext.current
val density = (LocalDensity.current.density * 160).toInt()
LazyColumn(
modifier = modifier
) {
for (group in widgets) {
item {
Text(
modifier = Modifier.padding(
top = 16.dp,
start = 8.dp,
end = 8.dp,
bottom = 8.dp
),
text = group.appName,
style = MaterialTheme.typography.titleLarge
)
}
items(group.widgets) {
LauncherCard(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
) {
Column(
modifier = Modifier
.clickable {
onWidgetSelected(it)
}
.padding(16.dp),
) {
val label = remember { it.loadLabel(context.packageManager) }
Text(text = label, style = MaterialTheme.typography.titleMedium)
Box(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp)
) {
val image: Drawable? = remember {
it.loadPreviewImage(context, density) ?: it.loadIcon(
context,
density
)
}
if (image != null) {
val mod =
if (image.intrinsicWidth > 0 && image.intrinsicHeight > 0) {
Modifier
.heightIn(max = image.intrinsicHeight.toDp())
.widthIn(max = image.intrinsicWidth.toDp())
.aspectRatio(
image.intrinsicWidth.toFloat() / image.intrinsicHeight.toFloat(),
matchHeightConstraintsFirst = true
)
} else {
Modifier.size(64.dp)
}
Canvas(
modifier = mod
) {
drawIntoCanvas {
image.setBounds(
0,
0,
size.width.toInt(),
size.height.toInt(),
)
image.draw(it.nativeCanvas)
}
}
}
}
if (isAtLeastApiLevel(31)) {
val description = remember { it.loadDescription(context)?.toString() }
if (description != null) {
Text(text = description, style = MaterialTheme.typography.bodySmall)
}
}
}
}
}
}
}
}

View File

@ -1,168 +0,0 @@
package de.mm20.launcher2.ui.launcher.widgets.picker
import android.appwidget.AppWidgetHost
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProviderInfo
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.base.BaseActivity
import de.mm20.launcher2.ui.base.ProvideSettings
import de.mm20.launcher2.ui.theme.LauncherTheme
class PickAppWidgetActivity : BaseActivity() {
private val viewModel by viewModels<PickAppWidgetVM>()
private lateinit var widgetHost: AppWidgetHost
private lateinit var appWidgetManager: AppWidgetManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
widgetHost = AppWidgetHost(this, 44203)
appWidgetManager = AppWidgetManager.getInstance(this)
val availableWidgets = viewModel.getAvailableWidgets(this)
setContent {
LauncherTheme {
ProvideSettings {
Scaffold(
topBar = {
CenterAlignedTopAppBar(
title = {
Text(stringResource(R.string.widget_add_widget))
},
navigationIcon = {
IconButton(onClick = { finish() }) {
Icon(
imageVector = Icons.Rounded.ArrowBack,
contentDescription = stringResource(
id = R.string.menu_back
)
)
}
}
)
}
) {
val available by availableWidgets.observeAsState()
val widgets = available
if (widgets != null) {
AppWidgetList(
modifier = Modifier
.fillMaxSize()
.padding(it),
widgets = widgets,
onWidgetSelected = {
selectAppWidget(it)
}
)
} else {
Box(
modifier = Modifier
.fillMaxSize()
.padding(it),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
}
}
}
}
}
}
private fun selectAppWidget(widget: AppWidgetProviderInfo) {
val appWidgetId = widgetHost.allocateAppWidgetId()
bindAppWidget(widget, appWidgetId)
}
private fun bindAppWidget(widget: AppWidgetProviderInfo, appWidgetId: Int) {
val canBind = appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, widget.provider)
Log.d("MM20", "Can bind: $canBind")
if (canBind) {
configureAppWidget(widget, appWidgetId)
} else {
startActivityForResult(
Intent(AppWidgetManager.ACTION_APPWIDGET_BIND).apply {
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, widget.provider)
}, RequestCodeBind
)
}
}
private fun configureAppWidget(widget: AppWidgetProviderInfo, appWidgetId: Int) {
if (widget.configure != null) {
widgetHost.startAppWidgetConfigureActivityForResult(
this,
appWidgetId,
0,
RequestCodeConfigure,
null
)
} else {
finishWithResult(appWidgetId)
}
}
@Deprecated("Deprecated in super class")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
RequestCodeBind -> {
val appWidgetId =
data?.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: return
if (resultCode == RESULT_OK) {
val widget = appWidgetManager.getAppWidgetInfo(appWidgetId)
configureAppWidget(widget, appWidgetId)
} else {
widgetHost.deleteAppWidgetId(appWidgetId)
cancel()
}
}
RequestCodeConfigure -> {
val appWidgetId =
data?.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: return cancel()
if (resultCode == RESULT_OK) {
finishWithResult(appWidgetId)
} else {
widgetHost.deleteAppWidgetId(appWidgetId)
cancel()
}
}
}
}
private fun finishWithResult(widgetId: Int) {
val data = Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId)
setResult(RESULT_OK, data)
finish()
}
private fun cancel() {
setResult(RESULT_CANCELED)
finish()
}
companion object {
const val RequestCodeConfigure = 1
const val RequestCodeBind = 2
}
}

View File

@ -1,45 +0,0 @@
package de.mm20.launcher2.ui.launcher.widgets.picker
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProviderInfo
import android.content.Context
import android.content.pm.PackageManager
import androidx.compose.ui.text.toLowerCase
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import de.mm20.launcher2.crashreporter.CrashReporter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
typealias AppWidgetGroup = Pair<String, List<AppWidgetProviderInfo>>
inline val AppWidgetGroup.appName: String
get() = this.first
inline val AppWidgetGroup.widgets: List<AppWidgetProviderInfo>
get() = this.second
class PickAppWidgetVM : ViewModel() {
fun getAvailableWidgets(context: Context): LiveData<List<AppWidgetGroup>?> = liveData {
emit(null)
val appWidgetManager = AppWidgetManager.getInstance(context)
val widgets = withContext(Dispatchers.IO) {
appWidgetManager.installedProviders
.sortedBy { it.loadLabel(context.packageManager).lowercase() }
.groupBy {
val pkg = it.provider.packageName
val appInfo = try {
context.packageManager.getApplicationInfo(pkg, 0)
} catch (e: PackageManager.NameNotFoundException) {
CrashReporter.logException(e)
return@groupBy ""
}
appInfo.loadLabel(context.packageManager).toString()
}
.toList()
.sortedBy { it.first.lowercase() }
}
emit(widgets)
}
}

View File

@ -34,7 +34,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue 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 imperialUnits by viewModel.imperialUnits.collectAsState(false)
val compactMode = !widget.config.showForecast val compactMode = !widget.config.showForecast
@ -93,8 +92,8 @@ fun WeatherWidget(widget: WeatherWidget) {
} }
val forecast = selectedForecast ?: run { val forecast = selectedForecast ?: run {
val hasPermission by viewModel.hasLocationPermission.observeAsState() val hasPermission by viewModel.hasLocationPermission.collectAsState()
val autoLocation by viewModel.autoLocation.observeAsState() val autoLocation by viewModel.autoLocation.collectAsState()
Column { Column {
AnimatedVisibility(hasPermission == false && autoLocation == true) { AnimatedVisibility(hasPermission == false && autoLocation == true) {
MissingPermissionBanner( MissingPermissionBanner(
@ -126,9 +125,9 @@ fun WeatherWidget(widget: WeatherWidget) {
if (!compactMode) { if (!compactMode) {
val dailyForecasts by viewModel.dailyForecasts.observeAsState(emptyList()) val dailyForecasts by viewModel.dailyForecasts
val selectedDayForecast by viewModel.currentDailyForecast.observeAsState() val selectedDayForecast by viewModel.currentDailyForecast
val currentDayForecasts by viewModel.currentDayForecasts.observeAsState(emptyList()) val currentDayForecasts by viewModel.currentDayForecasts
Surface( Surface(
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = LocalCardStyle.current.opacity), color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = LocalCardStyle.current.opacity),

View File

@ -1,6 +1,7 @@
package de.mm20.launcher2.ui.launcher.widgets.weather package de.mm20.launcher2.ui.launcher.widgets.weather
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.* import androidx.lifecycle.*
import de.mm20.launcher2.permissions.PermissionGroup import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager 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.DailyForecast
import de.mm20.launcher2.weather.Forecast import de.mm20.launcher2.weather.Forecast
import de.mm20.launcher2.weather.WeatherRepository import de.mm20.launcher2.weather.WeatherRepository
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -30,16 +33,16 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
set(value) { set(value) {
field = min(value, forecasts.lastIndex) field = min(value, forecasts.lastIndex)
if (field < 0) { if (field < 0) {
currentForecast.postValue(null) currentForecast.value = null
return return
} }
selectedForecastIndex = min( selectedForecastIndex = min(
selectedForecastIndex, selectedForecastIndex,
forecasts[value].hourlyForecasts.lastIndex forecasts[value].hourlyForecasts.lastIndex
) )
currentDayForecasts.postValue(forecasts[value].hourlyForecasts) currentDayForecasts.value = forecasts[value].hourlyForecasts
currentDailyForecast.postValue(forecasts[value]) currentDailyForecast.value = forecasts[value]
currentForecast.postValue(getCurrentlySelectedForecast()) currentForecast.value = getCurrentlySelectedForecast()
} }
/** /**
@ -48,11 +51,11 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
private var selectedForecastIndex = 0 private var selectedForecastIndex = 0
set(value) { set(value) {
if (selectedDayIndex < 0) { if (selectedDayIndex < 0) {
currentForecast.postValue(null) currentForecast.value = null
return return
} }
field = min(value, forecasts[selectedDayIndex].hourlyForecasts.lastIndex) field = min(value, forecasts[selectedDayIndex].hourlyForecasts.lastIndex)
currentForecast.postValue(getCurrentlySelectedForecast()) currentForecast.value = getCurrentlySelectedForecast()
} }
private val forecastsFlow = weatherRepository.forecasts private val forecastsFlow = weatherRepository.forecasts
@ -65,29 +68,29 @@ class WeatherWidgetVM : ViewModel(), KoinComponent {
field = value field = value
selectedDayIndex = 0 selectedDayIndex = 0
selectedForecastIndex = 0 selectedForecastIndex = 0
dailyForecasts.postValue(value) dailyForecasts.value = value
} }
/** /**
* Currently selected forecast, one of [currentDayForecasts] * Currently selected forecast, one of [currentDayForecasts]
*/ */
val currentForecast = MutableLiveData<Forecast?>(getCurrentlySelectedForecast()) val currentForecast = mutableStateOf<Forecast?>(getCurrentlySelectedForecast())
/** /**
* List of forecast summaries for each day * List of forecast summaries for each day
*/ */
val dailyForecasts = MutableLiveData<List<DailyForecast>>(emptyList()) val dailyForecasts = mutableStateOf<List<DailyForecast>>(emptyList())
/** /**
* Forecasts of the currently selected day (hourly in most cases). * Forecasts of the currently selected day (hourly in most cases).
* This is [DailyForecast.hourlyForecasts] of [currentDailyForecast] * This is [DailyForecast.hourlyForecasts] of [currentDailyForecast]
*/ */
val currentDayForecasts = MutableLiveData<List<Forecast>>(emptyList()) val currentDayForecasts = mutableStateOf<List<Forecast>>(emptyList())
/** /**
* Daily forecast summary for the currently selected day, one of [dailyForecasts] or null * Daily forecast summary for the currently selected day, one of [dailyForecasts] or null
*/ */
val currentDailyForecast = MutableLiveData<DailyForecast>(null) val currentDailyForecast = mutableStateOf<DailyForecast?>(null)
init { init {
viewModelScope.launch { 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) { fun requestLocationPermission(context: AppCompatActivity) {
permissionsManager.requestPermission(context, PermissionGroup.Location) 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 } val imperialUnits = dataStore.data.map { it.weather.imperialUnits }

View File

@ -1,82 +1,24 @@
package de.mm20.launcher2.ui.settings.appearance 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.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue 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.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.platform.LocalContext
import androidx.compose.ui.res.stringResource 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 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
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme 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.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.ListPreference
import de.mm20.launcher2.ui.component.preferences.Preference import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen 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.component.preferences.value
import de.mm20.launcher2.ui.locals.LocalNavController import de.mm20.launcher2.ui.locals.LocalNavController
import de.mm20.launcher2.ui.theme.getTypography import de.mm20.launcher2.ui.theme.getTypography
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
@Composable @Composable
fun AppearanceSettingsScreen() { fun AppearanceSettingsScreen() {
@ -86,7 +28,7 @@ fun AppearanceSettingsScreen() {
PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) { PreferenceScreen(title = stringResource(id = R.string.preference_screen_appearance)) {
item { item {
PreferenceCategory { PreferenceCategory {
val theme by viewModel.theme.observeAsState() val theme by viewModel.theme.collectAsState()
ListPreference( ListPreference(
title = stringResource(id = R.string.preference_theme), title = stringResource(id = R.string.preference_theme),
items = listOf( items = listOf(
@ -100,7 +42,7 @@ fun AppearanceSettingsScreen() {
viewModel.setTheme(newValue) viewModel.setTheme(newValue)
} }
) )
val colorScheme by viewModel.colorScheme.observeAsState() val colorScheme by viewModel.colorScheme.collectAsState()
Preference( Preference(
title = stringResource(id = R.string.preference_screen_colors), title = stringResource(id = R.string.preference_screen_colors),
summary = when (colorScheme) { summary = when (colorScheme) {
@ -113,7 +55,7 @@ fun AppearanceSettingsScreen() {
navController?.navigate("settings/appearance/colorscheme") navController?.navigate("settings/appearance/colorscheme")
} }
) )
val font by viewModel.font.observeAsState() val font by viewModel.font.collectAsState()
ListPreference( ListPreference(
title = stringResource(R.string.preference_font), title = stringResource(R.string.preference_font),
items = listOf( items = listOf(

View File

@ -1,26 +1,16 @@
package de.mm20.launcher2.ui.settings.appearance 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.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.icons.IconPack
import de.mm20.launcher2.icons.IconService import de.mm20.launcher2.icons.IconService
import de.mm20.launcher2.ktx.isAtLeastApiLevel
import de.mm20.launcher2.preferences.LauncherDataStore 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.ColorScheme
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Font import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Font
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme 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.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -30,7 +20,8 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
private val iconService: IconService by inject() 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) { fun setTheme(theme: Theme) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setColorScheme(colorScheme: ColorScheme) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setFont(font: Font) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -3,7 +3,6 @@ package de.mm20.launcher2.ui.settings.backup
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@ -19,11 +18,9 @@ import java.time.format.DateTimeFormatter
fun BackupSettingsScreen() { fun BackupSettingsScreen() {
val viewModel: BackupSettingsScreenVM = viewModel() val viewModel: BackupSettingsScreenVM = viewModel()
val restoreUri by viewModel.restoreUri.observeAsState() val restoreUri by viewModel.restoreUri
val showBackupSheet by viewModel.showBackupSheet.observeAsState(false) val showBackupSheet by viewModel.showBackupSheet
val context = LocalContext.current
val restoreLauncher = rememberLauncherForActivityResult( val restoreLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenDocument(), contract = ActivityResultContracts.OpenDocument(),

View File

@ -1,15 +1,15 @@
package de.mm20.launcher2.ui.settings.backup package de.mm20.launcher2.ui.settings.backup
import android.net.Uri import android.net.Uri
import androidx.lifecycle.MutableLiveData import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
class BackupSettingsScreenVM : ViewModel(), KoinComponent { class BackupSettingsScreenVM : ViewModel(), KoinComponent {
val showBackupSheet = MutableLiveData(false) val showBackupSheet = mutableStateOf(false)
val restoreUri = MutableLiveData<Uri?>(null) val restoreUri = mutableStateOf<Uri?>(null)
fun setShowBackupSheet(show: Boolean) { fun setShowBackupSheet(show: Boolean) {
showBackupSheet.value = show showBackupSheet.value = show

View File

@ -12,7 +12,6 @@ import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
@ -38,8 +37,8 @@ fun CreateBackupSheet(
viewModel.reset() viewModel.reset()
} }
val components by viewModel.selectedComponents.observeAsState(emptySet()) val components by viewModel.selectedComponents
val state by viewModel.state.observeAsState(CreateBackupState.Ready) val state by viewModel.state
val backupLauncher = rememberLauncherForActivityResult( val backupLauncher = rememberLauncherForActivityResult(

View File

@ -1,7 +1,7 @@
package de.mm20.launcher2.ui.settings.backup package de.mm20.launcher2.ui.settings.backup
import android.net.Uri import android.net.Uri
import androidx.lifecycle.MutableLiveData import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.backup.BackupComponent import de.mm20.launcher2.backup.BackupComponent
@ -14,9 +14,9 @@ class CreateBackupSheetVM : ViewModel(), KoinComponent {
private val backupManager: BackupManager by inject() 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() { fun reset() {
state.value = CreateBackupState.Ready state.value = CreateBackupState.Ready

View File

@ -9,8 +9,8 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.* import androidx.compose.material.icons.rounded.*
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -43,7 +43,7 @@ fun CardsSettingsScreen() {
} }
item { item {
PreferenceCategory { PreferenceCategory {
val shape by viewModel.shape.observeAsState() val shape by viewModel.shape.collectAsState()
ListPreference( ListPreference(
icon = Icons.Rounded.Rectangle, icon = Icons.Rounded.Rectangle,
title = stringResource(R.string.preference_cards_shape), title = stringResource(R.string.preference_cards_shape),
@ -55,7 +55,7 @@ fun CardsSettingsScreen() {
onValueChanged = { onValueChanged = {
if (it != null) viewModel.setShape(it) if (it != null) viewModel.setShape(it)
}) })
val radius by viewModel.radius.observeAsState(0) val radius by viewModel.radius.collectAsState()
SliderPreference( SliderPreference(
title = stringResource(R.string.preference_cards_corner_radius), title = stringResource(R.string.preference_cards_corner_radius),
icon = Icons.Rounded.RoundedCorner, icon = Icons.Rounded.RoundedCorner,
@ -67,7 +67,7 @@ fun CardsSettingsScreen() {
viewModel.setRadius(it) viewModel.setRadius(it)
} }
) )
val opacity by viewModel.opacity.observeAsState(0f) val opacity by viewModel.opacity.collectAsState()
SliderPreference( SliderPreference(
title = stringResource(R.string.preference_cards_opacity), title = stringResource(R.string.preference_cards_opacity),
icon = Icons.Rounded.Opacity, icon = Icons.Rounded.Opacity,
@ -78,7 +78,7 @@ fun CardsSettingsScreen() {
viewModel.setOpacity(it) viewModel.setOpacity(it)
} }
) )
val borderWidth by viewModel.borderWidth.observeAsState(0) val borderWidth by viewModel.borderWidth.collectAsState()
SliderPreference( SliderPreference(
title = stringResource(R.string.preference_cards_stroke_width), title = stringResource(R.string.preference_cards_stroke_width),
icon = Icons.Rounded.LineWeight, icon = Icons.Rounded.LineWeight,

View File

@ -1,11 +1,12 @@
package de.mm20.launcher2.ui.settings.cards package de.mm20.launcher2.ui.settings.cards
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings import de.mm20.launcher2.preferences.Settings
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -13,7 +14,8 @@ import org.koin.core.component.inject
class CardsSettingsScreenVM: ViewModel(), KoinComponent { class CardsSettingsScreenVM: ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject() 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) { fun setOpacity(opacity: Float) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setRadius(radius: Int) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setBorderWidth(borderWidth: Int) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setShape(shape: Settings.CardSettings.Shape) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -8,17 +8,14 @@ import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.HorizontalPagerIndicator import com.google.accompanist.pager.HorizontalPagerIndicator
import com.google.accompanist.pager.rememberPagerState 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.ClockStyle
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetLayout
@ -35,7 +32,7 @@ fun ClockWidgetSettingsScreen() {
) { ) {
item { item {
PreferenceCategory { PreferenceCategory {
val layout by viewModel.layout.observeAsState() val layout by viewModel.layout.collectAsState()
ListPreference( ListPreference(
title = stringResource(R.string.preference_clockwidget_layout), title = stringResource(R.string.preference_clockwidget_layout),
value = layout, value = layout,
@ -47,7 +44,7 @@ fun ClockWidgetSettingsScreen() {
if (it != null) viewModel.setLayout(it) if (it != null) viewModel.setLayout(it)
} }
) )
val clockStyle by viewModel.clockStyle.observeAsState() val clockStyle by viewModel.clockStyle.collectAsState()
ClockStylePreference( ClockStylePreference(
layout = layout ?: ClockWidgetLayout.Vertical, layout = layout ?: ClockWidgetLayout.Vertical,
value = clockStyle, value = clockStyle,
@ -55,7 +52,7 @@ fun ClockWidgetSettingsScreen() {
viewModel.setClockStyle(it) viewModel.setClockStyle(it)
} }
) )
val color by viewModel.color.observeAsState() val color by viewModel.color.collectAsState()
ListPreference( ListPreference(
title = stringResource(R.string.preference_clock_widget_color), title = stringResource(R.string.preference_clock_widget_color),
value = color, value = color,
@ -68,7 +65,7 @@ fun ClockWidgetSettingsScreen() {
if (it != null) viewModel.setColor(it) if (it != null) viewModel.setColor(it)
} }
) )
val fillHeight by viewModel.fillHeight.observeAsState() val fillHeight by viewModel.fillHeight.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_clock_widget_fill_height), title = stringResource(R.string.preference_clock_widget_fill_height),
summary = stringResource(R.string.preference_clock_widget_fill_height_summary), summary = stringResource(R.string.preference_clock_widget_fill_height_summary),
@ -79,7 +76,7 @@ fun ClockWidgetSettingsScreen() {
} }
item { item {
PreferenceCategory { PreferenceCategory {
val datePart by viewModel.datePart.observeAsState() val datePart by viewModel.datePart.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_clockwidget_date_part), title = stringResource(R.string.preference_clockwidget_date_part),
summary = stringResource(R.string.preference_clockwidget_date_part_summary), summary = stringResource(R.string.preference_clockwidget_date_part_summary),
@ -89,7 +86,7 @@ fun ClockWidgetSettingsScreen() {
viewModel.setDatePart(it) viewModel.setDatePart(it)
}, },
) )
val favoritesPart by viewModel.favoritesPart.observeAsState() val favoritesPart by viewModel.favoritesPart.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_clockwidget_favorites_part), title = stringResource(R.string.preference_clockwidget_favorites_part),
summary = stringResource(R.string.preference_clockwidget_favorites_part_summary), summary = stringResource(R.string.preference_clockwidget_favorites_part_summary),
@ -103,7 +100,7 @@ fun ClockWidgetSettingsScreen() {
} }
item { item {
PreferenceCategory { PreferenceCategory {
val musicPart by viewModel.musicPart.observeAsState() val musicPart by viewModel.musicPart.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_clockwidget_music_part), title = stringResource(R.string.preference_clockwidget_music_part),
summary = stringResource(R.string.preference_clockwidget_music_part_summary), summary = stringResource(R.string.preference_clockwidget_music_part_summary),
@ -113,7 +110,7 @@ fun ClockWidgetSettingsScreen() {
viewModel.setMusicPart(it) viewModel.setMusicPart(it)
} }
) )
val alarmPart by viewModel.alarmPart.observeAsState() val alarmPart by viewModel.alarmPart.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_clockwidget_alarm_part), title = stringResource(R.string.preference_clockwidget_alarm_part),
summary = stringResource(R.string.preference_clockwidget_alarm_part_summary), summary = stringResource(R.string.preference_clockwidget_alarm_part_summary),
@ -123,7 +120,7 @@ fun ClockWidgetSettingsScreen() {
viewModel.setAlarmPart(it) viewModel.setAlarmPart(it)
} }
) )
val batteryPart by viewModel.batteryPart.observeAsState() val batteryPart by viewModel.batteryPart.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_clockwidget_battery_part), title = stringResource(R.string.preference_clockwidget_battery_part),
summary = stringResource(R.string.preference_clockwidget_battery_part_summary), summary = stringResource(R.string.preference_clockwidget_battery_part_summary),

View File

@ -1,20 +1,21 @@
package de.mm20.launcher2.ui.settings.clockwidget package de.mm20.launcher2.ui.settings.clockwidget
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings
import de.mm20.launcher2.preferences.Settings.ClockWidgetSettings.ClockWidgetColors 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.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent { class ClockWidgetSettingsScreenVM : ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject() 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) { fun setLayout(layout: ClockWidgetSettings.ClockWidgetLayout) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setClockStyle(clockStyle: ClockWidgetSettings.ClockStyle) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setColor(color: ClockWidgetColors) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setFillHeight(fillHeight: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setDatePart(datePart: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setFavoritesPart(favoritesPart: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setBatteryPart(batteryPart: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setMusicPart(musicPart: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setAlarmPart(alarmPart: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -8,8 +8,8 @@ import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -34,7 +34,7 @@ fun ColorSchemeSettingsScreen() {
PreferenceScreen(title = stringResource(R.string.preference_screen_colors)) { PreferenceScreen(title = stringResource(R.string.preference_screen_colors)) {
item { item {
PreferenceCategory { PreferenceCategory {
val colorScheme by viewModel.colorScheme.observeAsState() val colorScheme by viewModel.colorScheme.collectAsState()
val items = mutableListOf( val items = mutableListOf(
AppearanceSettings.ColorScheme.Default to stringResource(R.string.preference_colors_default), AppearanceSettings.ColorScheme.Default to stringResource(R.string.preference_colors_default),

View File

@ -1,11 +1,12 @@
package de.mm20.launcher2.ui.settings.colorscheme package de.mm20.launcher2.ui.settings.colorscheme
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings.AppearanceSettings import de.mm20.launcher2.preferences.Settings.AppearanceSettings
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -13,9 +14,11 @@ import org.koin.core.component.inject
class ColorSchemeSettingsScreenVM : ViewModel(), KoinComponent { class ColorSchemeSettingsScreenVM : ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject() 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) { fun setColorScheme(colorScheme: AppearanceSettings.ColorScheme) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -4,7 +4,6 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.MoreVert import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -18,7 +17,7 @@ import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
fun CustomColorSchemeSettingsScreen() { fun CustomColorSchemeSettingsScreen() {
val viewModel: CustomColorSchemeSettingsScreenVM = viewModel() val viewModel: CustomColorSchemeSettingsScreenVM = viewModel()
val advancedMode by viewModel.advancedMode.observeAsState() val advancedMode by viewModel.advancedMode.collectAsState()
PreferenceScreen( PreferenceScreen(
title = stringResource(R.string.preference_screen_colors), title = stringResource(R.string.preference_screen_colors),
@ -64,7 +63,7 @@ fun CustomColorSchemeSettingsScreen() {
if (advancedMode == false) { if (advancedMode == false) {
item { item {
PreferenceCategory { PreferenceCategory {
val baseColors by viewModel.baseColors.observeAsState() val baseColors by viewModel.baseColors.collectAsState()
ColorPreference( ColorPreference(
title = stringResource(R.string.preference_custom_colors_a1), title = stringResource(R.string.preference_custom_colors_a1),
value = baseColors?.let { Color(it.accent1) }, value = baseColors?.let { Color(it.accent1) },
@ -149,7 +148,7 @@ fun CustomColorSchemeSettingsScreen() {
if (advancedMode == true) { if (advancedMode == true) {
item { item {
PreferenceCategory(stringResource(R.string.preference_category_custom_colors_light)) { PreferenceCategory(stringResource(R.string.preference_category_custom_colors_light)) {
val lightScheme by viewModel.lightScheme.observeAsState() val lightScheme by viewModel.lightScheme.collectAsState()
ColorPreference( ColorPreference(
title = "Primary", title = "Primary",
value = lightScheme?.let { Color(it.primary) }, value = lightScheme?.let { Color(it.primary) },
@ -513,7 +512,7 @@ fun CustomColorSchemeSettingsScreen() {
} }
PreferenceCategory(stringResource(R.string.preference_category_custom_colors_dark)) { PreferenceCategory(stringResource(R.string.preference_category_custom_colors_dark)) {
val darkScheme by viewModel.darkScheme.observeAsState() val darkScheme by viewModel.darkScheme.collectAsState()
ColorPreference( ColorPreference(
title = "Primary", title = "Primary",
value = darkScheme?.let { Color(it.primary) }, value = darkScheme?.let { Color(it.primary) },

View File

@ -1,13 +1,13 @@
package de.mm20.launcher2.ui.settings.colorscheme package de.mm20.launcher2.ui.settings.colorscheme
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.CustomColors import de.mm20.launcher2.preferences.Settings.AppearanceSettings.CustomColors
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -17,7 +17,8 @@ import scheme.Scheme
class CustomColorSchemeSettingsScreenVM : ViewModel(), KoinComponent { class CustomColorSchemeSettingsScreenVM : ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject() 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) { fun setAdvancedMode(advancedMode: Boolean) {
viewModelScope.launch { viewModelScope.launch {
val lightScheme = dataStore.updateData { 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) { fun setBaseColors(baseColors: CustomColors.BaseColors) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setDarkScheme(darkScheme: CustomColors.Scheme) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setLightScheme(lightScheme: CustomColors.Scheme) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -6,14 +6,13 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.BugReport import androidx.compose.material.icons.rounded.BugReport
import androidx.compose.material.icons.rounded.Share import androidx.compose.material.icons.rounded.Share
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@ -26,7 +25,7 @@ import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
fun CrashReportScreen(fileName: String) { fun CrashReportScreen(fileName: String) {
val viewModel: CrashReportScreenVM = viewModel() val viewModel: CrashReportScreenVM = viewModel()
val context = LocalContext.current val context = LocalContext.current
val crashReport by remember(fileName) { viewModel.getCrashReport(fileName) }.observeAsState() val crashReport by remember(fileName) { viewModel.getCrashReport(fileName) }.collectAsState(null)
PreferenceScreen( PreferenceScreen(
title = when (crashReport?.type) { title = when (crashReport?.type) {
CrashReportType.Exception -> "Exception" CrashReportType.Exception -> "Exception"

View File

@ -5,14 +5,14 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import de.mm20.launcher2.crashreporter.CrashReport import de.mm20.launcher2.crashreporter.CrashReport
import de.mm20.launcher2.crashreporter.CrashReporter import de.mm20.launcher2.crashreporter.CrashReporter
import kotlinx.coroutines.flow.flow
import java.io.File import java.io.File
import java.net.URLEncoder import java.net.URLEncoder
class CrashReportScreenVM : ViewModel() { class CrashReportScreenVM : ViewModel() {
fun getCrashReport(fileName: String) = liveData<CrashReport?> { fun getCrashReport(fileName: String) = flow<CrashReport?> {
emit(CrashReporter.getCrashReport(fileName)) emit(CrashReporter.getCrashReport(fileName))
} }

View File

@ -13,7 +13,6 @@ import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
@ -32,9 +31,9 @@ import java.net.URLEncoder
fun CrashReporterScreen() { fun CrashReporterScreen() {
val viewModel: CrashReporterScreenVM = viewModel() val viewModel: CrashReporterScreenVM = viewModel()
val navController = LocalNavController.current val navController = LocalNavController.current
val reports by viewModel.reports.observeAsState() val reports by viewModel.reports
val showExceptions by viewModel.showExceptions.observeAsState(true) val showExceptions by viewModel.showExceptions
val showCrashes by viewModel.showCrashes.observeAsState(true) val showCrashes by viewModel.showCrashes
PreferenceScreen( PreferenceScreen(
title = stringResource(R.string.preference_crash_reporter), title = stringResource(R.string.preference_crash_reporter),
helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/troubleshooting/crashreporter" helpUrl = "https://kvaesitso.mm20.de/docs/user-guide/troubleshooting/crashreporter"

View File

@ -1,6 +1,6 @@
package de.mm20.launcher2.ui.settings.crashreporter package de.mm20.launcher2.ui.settings.crashreporter
import androidx.lifecycle.MutableLiveData import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.crashreporter.BuildConfig import de.mm20.launcher2.crashreporter.BuildConfig
@ -29,10 +29,10 @@ class CrashReporterScreenVM: ViewModel() {
} }
} }
val showExceptions = MutableLiveData(false) val showExceptions = mutableStateOf(false)
val showCrashes = MutableLiveData(true) val showCrashes = mutableStateOf(true)
val reports = MutableLiveData<List<CrashReport>?>(null) val reports = mutableStateOf<List<CrashReport>?>(null)
private var _reports: List<CrashReport>? = null private var _reports: List<CrashReport>? = null
init { init {

View File

@ -12,8 +12,8 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -30,7 +30,7 @@ fun EasterEggSettingsScreen() {
val viewModel: EasterEggSettingsScreenVM = viewModel() val viewModel: EasterEggSettingsScreenVM = viewModel()
PreferenceScreen(title = stringResource(R.string.preference_screen_about)) { PreferenceScreen(title = stringResource(R.string.preference_screen_about)) {
item { item {
val easterEgg by viewModel.easterEgg.observeAsState(false) val easterEgg by viewModel.easterEgg.collectAsState()
val bgAlpha by animateFloatAsState(if (easterEgg) 1f else 0f) val bgAlpha by animateFloatAsState(if (easterEgg) 1f else 0f)
val textColor by animateColorAsState(if (easterEgg) MaterialTheme.colorScheme.onSecondaryContainer else MaterialTheme.colorScheme.onBackground) val textColor by animateColorAsState(if (easterEgg) MaterialTheme.colorScheme.onSecondaryContainer else MaterialTheme.colorScheme.onBackground)
Column( Column(

View File

@ -1,10 +1,11 @@
package de.mm20.launcher2.ui.settings.easteregg package de.mm20.launcher2.ui.settings.easteregg
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -12,7 +13,8 @@ import org.koin.core.component.inject
class EasterEggSettingsScreenVM: ViewModel(), KoinComponent { class EasterEggSettingsScreenVM: ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject() 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) { fun setEasterEgg(easterEgg: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -7,8 +7,8 @@ import androidx.compose.material.icons.rounded.Sort
import androidx.compose.material.icons.rounded.SwapVert import androidx.compose.material.icons.rounded.SwapVert
import androidx.compose.material.icons.rounded.TableRows import androidx.compose.material.icons.rounded.TableRows
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@ -45,7 +45,7 @@ fun FavoritesSettingsScreen() {
} }
item { item {
PreferenceCategory(stringResource(R.string.preference_category_favorites_frequently_used)) { PreferenceCategory(stringResource(R.string.preference_category_favorites_frequently_used)) {
val frequentlyUsed by viewModel.frequentlyUsed.observeAsState() val frequentlyUsed by viewModel.frequentlyUsed.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.frequently_used_show_in_favorites), title = stringResource(R.string.frequently_used_show_in_favorites),
summary = stringResource(R.string.preference_favorites_frequently_used_summary), summary = stringResource(R.string.preference_favorites_frequently_used_summary),
@ -55,7 +55,7 @@ fun FavoritesSettingsScreen() {
}, },
icon = Icons.Rounded.Insights icon = Icons.Rounded.Insights
) )
val frequentlyUsedRows by viewModel.frequentlyUsedRows.observeAsState(1) val frequentlyUsedRows by viewModel.frequentlyUsedRows.collectAsState()
SliderPreference( SliderPreference(
title = stringResource(R.string.frequently_used_rows), title = stringResource(R.string.frequently_used_rows),
value = frequentlyUsedRows, value = frequentlyUsedRows,
@ -67,7 +67,7 @@ fun FavoritesSettingsScreen() {
}, },
icon = Icons.Rounded.TableRows icon = Icons.Rounded.TableRows
) )
val searchResultWeightFactor by viewModel.searchResultWeightFactor.observeAsState(WeightFactor.Default) val searchResultWeightFactor by viewModel.searchResultWeightFactor.collectAsState()
ListPreference( ListPreference(
title = stringResource(R.string.preference_search_result_ordering_weight_factor), title = stringResource(R.string.preference_search_result_ordering_weight_factor),
icon = Icons.Rounded.SwapVert, icon = Icons.Rounded.SwapVert,
@ -82,7 +82,7 @@ fun FavoritesSettingsScreen() {
} }
} }
item { item {
val editButton by viewModel.editButton.observeAsState() val editButton by viewModel.editButton.collectAsState()
PreferenceCategory { PreferenceCategory {
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_edit_button), title = stringResource(R.string.preference_edit_button),

View File

@ -1,11 +1,12 @@
package de.mm20.launcher2.ui.settings.favorites package de.mm20.launcher2.ui.settings.favorites
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.WeightFactor import de.mm20.launcher2.preferences.Settings.SearchResultOrderingSettings.WeightFactor
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -13,7 +14,8 @@ import org.koin.core.component.inject
class FavoritesSettingsScreenVM: ViewModel(), KoinComponent { class FavoritesSettingsScreenVM: ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject() 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) { fun setFrequentlyUsed(frequentlyUsed: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setFrequentlyUsedRows(frequentlyUsedRows: Int) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setEditButton(editButton: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setSearchResultWeightFactor(searchResultWeightFactor: WeightFactor) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -11,8 +11,8 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
@ -40,7 +40,7 @@ fun FileSearchSettingsScreen() {
viewModel.onResume() viewModel.onResume()
} }
} }
val loading by viewModel.loading.observeAsState() val loading by viewModel.loading
PreferenceScreen(title = stringResource(R.string.preference_search_files)) { PreferenceScreen(title = stringResource(R.string.preference_search_files)) {
if (loading == true) { if (loading == true) {
item { item {
@ -52,8 +52,8 @@ fun FileSearchSettingsScreen() {
} }
item { item {
PreferenceCategory { PreferenceCategory {
val localFiles by viewModel.localFiles.observeAsState() val localFiles by viewModel.localFiles.collectAsState()
val hasFilePermission by viewModel.hasFilePermission.observeAsState() val hasFilePermission by viewModel.hasFilePermission.collectAsState()
AnimatedVisibility(hasFilePermission == false) { AnimatedVisibility(hasFilePermission == false) {
MissingPermissionBanner( MissingPermissionBanner(
text = stringResource( text = stringResource(
@ -74,8 +74,8 @@ fun FileSearchSettingsScreen() {
enabled = hasFilePermission == true enabled = hasFilePermission == true
) )
val nextcloud by viewModel.nextcloud.observeAsState() val nextcloud by viewModel.nextcloud.collectAsState()
val nextcloudAccount by viewModel.nextcloudAccount.observeAsState() val nextcloudAccount by viewModel.nextcloudAccount
AnimatedVisibility(nextcloudAccount == null) { AnimatedVisibility(nextcloudAccount == null) {
Banner( Banner(
text = stringResource(R.string.no_account_nextcloud), text = stringResource(R.string.no_account_nextcloud),
@ -107,8 +107,8 @@ fun FileSearchSettingsScreen() {
enabled = nextcloudAccount != null enabled = nextcloudAccount != null
) )
val owncloud by viewModel.owncloud.observeAsState() val owncloud by viewModel.owncloud.collectAsState()
val owncloudAccount by viewModel.owncloudAccount.observeAsState() val owncloudAccount by viewModel.owncloudAccount
AnimatedVisibility(owncloudAccount == null) { AnimatedVisibility(owncloudAccount == null) {
Banner( Banner(
text = stringResource(R.string.no_account_owncloud), text = stringResource(R.string.no_account_owncloud),
@ -141,8 +141,8 @@ fun FileSearchSettingsScreen() {
) )
if (viewModel.microsoftAvailable) { if (viewModel.microsoftAvailable) {
val onedrive by viewModel.onedrive.observeAsState() val onedrive by viewModel.onedrive.collectAsState()
val microsoftAccount by viewModel.microsoftAccount.observeAsState() val microsoftAccount by viewModel.microsoftAccount
AnimatedVisibility(microsoftAccount == null) { AnimatedVisibility(microsoftAccount == null) {
Banner( Banner(
text = stringResource(R.string.no_account_microsoft), text = stringResource(R.string.no_account_microsoft),
@ -176,8 +176,8 @@ fun FileSearchSettingsScreen() {
} }
if (viewModel.googleAvailable) { if (viewModel.googleAvailable) {
val gdrive by viewModel.gdrive.observeAsState() val gdrive by viewModel.gdrive.collectAsState()
val googleAccount by viewModel.googleAccount.observeAsState() val googleAccount by viewModel.googleAccount
AnimatedVisibility(googleAccount == null) { AnimatedVisibility(googleAccount == null) {
Banner( Banner(
text = stringResource(R.string.no_account_google), text = stringResource(R.string.no_account_google),

View File

@ -1,9 +1,8 @@
package de.mm20.launcher2.ui.settings.filesearch package de.mm20.launcher2.ui.settings.filesearch
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.accounts.Account import de.mm20.launcher2.accounts.Account
import de.mm20.launcher2.accounts.AccountType 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.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -21,14 +22,14 @@ class FileSearchSettingsScreenVM : ViewModel(), KoinComponent {
private val accountsRepository: AccountsRepository by inject() private val accountsRepository: AccountsRepository by inject()
private val permissionsManager: PermissionsManager by inject() private val permissionsManager: PermissionsManager by inject()
val hasFilePermission = val hasFilePermission = permissionsManager.hasPermission(PermissionGroup.ExternalStorage)
permissionsManager.hasPermission(PermissionGroup.ExternalStorage).asLiveData() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val loading = MutableLiveData(true) val loading = mutableStateOf(true)
val nextcloudAccount = MutableLiveData<Account?>(null) val nextcloudAccount = mutableStateOf<Account?>(null)
val owncloudAccount = MutableLiveData<Account?>(null) val owncloudAccount = mutableStateOf<Account?>(null)
val microsoftAccount = MutableLiveData<Account?>(null) val microsoftAccount = mutableStateOf<Account?>(null)
val googleAccount = MutableLiveData<Account?>(null) val googleAccount = mutableStateOf<Account?>(null)
val microsoftAvailable = accountsRepository.isSupported(AccountType.Microsoft) val microsoftAvailable = accountsRepository.isSupported(AccountType.Microsoft)
val googleAvailable = accountsRepository.isSupported(AccountType.Google) 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) { fun setLocalFiles(localFiles: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setNextcloud(nextcloud: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setGdrive(gdrive: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setOneDrive(onedrive: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setOwncloud(owncloud: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -14,7 +14,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue

View File

@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.settings.gestures
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.searchable.SearchableRepository import de.mm20.launcher2.searchable.SearchableRepository
import de.mm20.launcher2.icons.IconService import de.mm20.launcher2.icons.IconService
@ -29,8 +28,10 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
private val iconService: IconService by inject() private val iconService: IconService by inject()
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility) val hasPermission = permissionsManager.hasPermission(PermissionGroup.Accessibility)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val baseLayout = dataStore.data.map { it.layout.baseLayout } val baseLayout = dataStore.data.map { it.layout.baseLayout }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setBaseLayout(baseLayout: Settings.LayoutSettings.Layout) { fun setBaseLayout(baseLayout: Settings.LayoutSettings.Layout) {
viewModelScope.launch { viewModelScope.launch {
@ -43,10 +44,15 @@ class GestureSettingsScreenVM : ViewModel(), KoinComponent {
} }
val swipeDown = dataStore.data.map { it.gestures.swipeDown } val swipeDown = dataStore.data.map { it.gestures.swipeDown }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val swipeLeft = dataStore.data.map { it.gestures.swipeLeft } val swipeLeft = dataStore.data.map { it.gestures.swipeLeft }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val swipeRight = dataStore.data.map { it.gestures.swipeRight } val swipeRight = dataStore.data.map { it.gestures.swipeRight }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val doubleTap = dataStore.data.map { it.gestures.doubleTap } val doubleTap = dataStore.data.map { it.gestures.doubleTap }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val longPress = dataStore.data.map { it.gestures.longPress } val longPress = dataStore.data.map { it.gestures.longPress }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setSwipeDown(action: GestureAction) { fun setSwipeDown(action: GestureAction) {
viewModelScope.launch { viewModelScope.launch {

View File

@ -9,7 +9,6 @@ import androidx.compose.material.icons.rounded.Visibility
import androidx.compose.material.icons.rounded.VisibilityOff import androidx.compose.material.icons.rounded.VisibilityOff
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
@ -31,8 +30,8 @@ fun HiddenItemsSettingsScreen() {
val context = LocalContext.current val context = LocalContext.current
val density = LocalDensity.current val density = LocalDensity.current
val apps by viewModel.allApps.observeAsState(emptyList()) val apps by viewModel.allApps.collectAsState()
val other by viewModel.hiddenItems.observeAsState(emptyList()) val other by viewModel.hiddenItems.collectAsState()
PreferenceScreen(title = stringResource(R.string.preference_hidden_items)) { PreferenceScreen(title = stringResource(R.string.preference_hidden_items)) {
items(apps, key = { it.key }) { searchable -> items(apps, key = { it.key }) { searchable ->
val icon by remember(searchable.key) { val icon by remember(searchable.key) {

View File

@ -5,10 +5,8 @@ import android.content.Context
import android.content.pm.LauncherApps import android.content.pm.LauncherApps
import android.os.Bundle import android.os.Bundle
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope
import androidx.lifecycle.liveData
import de.mm20.launcher2.applications.AppRepository import de.mm20.launcher2.applications.AppRepository
import de.mm20.launcher2.searchable.SearchableRepository import de.mm20.launcher2.searchable.SearchableRepository
import de.mm20.launcher2.icons.IconService import de.mm20.launcher2.icons.IconService
@ -18,8 +16,12 @@ import de.mm20.launcher2.search.SavableSearchable
import de.mm20.launcher2.search.data.LauncherApp import de.mm20.launcher2.search.data.LauncherApp
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -31,11 +33,11 @@ class HiddenItemsSettingsScreenVM : ViewModel(), KoinComponent {
val allApps = appRepository.getAllInstalledApps().map { val allApps = appRepository.getAllInstalledApps().map {
withContext(Dispatchers.Default) { it.sorted() } withContext(Dispatchers.Default) { it.sorted() }
}.asLiveData() }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
val hiddenItems: LiveData<List<SavableSearchable>> = liveData { val hiddenItems: StateFlow<List<SavableSearchable>> = flow {
val hidden = searchableRepository.get(hidden = true).first().filter { it !is LauncherApp }.sorted() val hidden = searchableRepository.get(hidden = true).first().filter { it !is LauncherApp }.sorted()
emit(hidden) emit(hidden)
} }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
fun isHidden(searchable: SavableSearchable): Flow<Boolean> { fun isHidden(searchable: SavableSearchable): Flow<Boolean> {
return searchableRepository.isHidden(searchable) return searchableRepository.isHidden(searchable)

View File

@ -55,8 +55,8 @@ fun HomescreenSettingsScreen() {
val bottomSearchBar by viewModel.bottomSearchBar.collectAsStateWithLifecycle(null) val bottomSearchBar by viewModel.bottomSearchBar.collectAsStateWithLifecycle(null)
val fixedSearchBar by viewModel.fixedSearchBar.collectAsStateWithLifecycle(null) val fixedSearchBar by viewModel.fixedSearchBar.collectAsStateWithLifecycle(null)
val lightStatusBar by viewModel.statusBarIcons.collectAsStateWithLifecycle(null) val lightStatusBar by viewModel.statusBarIcons.collectAsStateWithLifecycle(null)
val dimWallpaper by viewModel.dimWallpaper.collectAsStateWithLifecycle(false) val dimWallpaper by viewModel.dimWallpaper.collectAsStateWithLifecycle()
val blurWallpaper by viewModel.blurWallpaper.collectAsStateWithLifecycle(false) val blurWallpaper by viewModel.blurWallpaper.collectAsStateWithLifecycle()
val lightNavBar by viewModel.navBarIcons.collectAsStateWithLifecycle(null) val lightNavBar by viewModel.navBarIcons.collectAsStateWithLifecycle(null)
val hideStatusBar by viewModel.hideStatusBar.collectAsStateWithLifecycle(null) val hideStatusBar by viewModel.hideStatusBar.collectAsStateWithLifecycle(null)
val hideNavBar by viewModel.hideNavBar.collectAsStateWithLifecycle(null) val hideNavBar by viewModel.hideNavBar.collectAsStateWithLifecycle(null)

View File

@ -6,14 +6,15 @@ import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory import androidx.lifecycle.viewmodel.viewModelFactory
import de.mm20.launcher2.ktx.isAtLeastApiLevel import de.mm20.launcher2.ktx.isAtLeastApiLevel
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings import de.mm20.launcher2.preferences.Settings
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.get import org.koin.core.component.get
@ -24,6 +25,7 @@ class HomescreenSettingsScreenVM(
val dimWallpaper = dataStore.data.map { it.appearance.dimWallpaper } val dimWallpaper = dataStore.data.map { it.appearance.dimWallpaper }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
fun setDimWallpaper(dimWallpaper: Boolean) { fun setDimWallpaper(dimWallpaper: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -37,6 +39,7 @@ class HomescreenSettingsScreenVM(
} }
val blurWallpaper = dataStore.data.map { it.appearance.blurWallpaper } val blurWallpaper = dataStore.data.map { it.appearance.blurWallpaper }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false)
fun setBlurWallpaper(blurWallpaper: Boolean) { fun setBlurWallpaper(blurWallpaper: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -59,6 +62,7 @@ class HomescreenSettingsScreenVM(
} }
val statusBarIcons = dataStore.data.map { it.systemBars.statusBarColor } val statusBarIcons = dataStore.data.map { it.systemBars.statusBarColor }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setLightStatusBar(statusBarColor: Settings.SystemBarsSettings.SystemBarColors) { fun setLightStatusBar(statusBarColor: Settings.SystemBarsSettings.SystemBarColors) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -73,6 +77,7 @@ class HomescreenSettingsScreenVM(
} }
val navBarIcons = dataStore.data.map { it.systemBars.navBarColor } val navBarIcons = dataStore.data.map { it.systemBars.navBarColor }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setLightNavBar(navBarColors: Settings.SystemBarsSettings.SystemBarColors) { fun setLightNavBar(navBarColors: Settings.SystemBarsSettings.SystemBarColors) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -87,6 +92,7 @@ class HomescreenSettingsScreenVM(
} }
val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar } val hideStatusBar = dataStore.data.map { it.systemBars.hideStatusBar }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setHideStatusBar(hideStatusBar: Boolean) { fun setHideStatusBar(hideStatusBar: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -101,6 +107,7 @@ class HomescreenSettingsScreenVM(
} }
val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar } val hideNavBar = dataStore.data.map { it.systemBars.hideNavBar }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setHideNavBar(hideNavBar: Boolean) { fun setHideNavBar(hideNavBar: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -115,6 +122,7 @@ class HomescreenSettingsScreenVM(
} }
val searchBarColor = dataStore.data.map { it.searchBar.color } val searchBarColor = dataStore.data.map { it.searchBar.color }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setSearchBarColor(color: Settings.SearchBarSettings.SearchBarColors) { fun setSearchBarColor(color: Settings.SearchBarSettings.SearchBarColors) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -128,9 +136,8 @@ class HomescreenSettingsScreenVM(
} }
} }
val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle } val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setSearchBarStyle(searchBarStyle: Settings.SearchBarSettings.SearchBarStyle) { fun setSearchBarStyle(searchBarStyle: Settings.SearchBarSettings.SearchBarStyle) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -145,6 +152,7 @@ class HomescreenSettingsScreenVM(
} }
val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar } val fixedSearchBar = dataStore.data.map { it.layout.fixedSearchBar }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setFixedSearchBar(fixedSearchBar: Boolean) { fun setFixedSearchBar(fixedSearchBar: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -156,6 +164,7 @@ class HomescreenSettingsScreenVM(
} }
val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar } val bottomSearchBar = dataStore.data.map { it.layout.bottomSearchBar }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setBottomSearchBar(bottomSearchBar: Boolean) { fun setBottomSearchBar(bottomSearchBar: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -167,6 +176,7 @@ class HomescreenSettingsScreenVM(
} }
val fixedRotation = dataStore.data.map { it.layout.fixedRotation } val fixedRotation = dataStore.data.map { it.layout.fixedRotation }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setFixedRotation(fixedRotation: Boolean) { fun setFixedRotation(fixedRotation: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -178,6 +188,7 @@ class HomescreenSettingsScreenVM(
} }
val widgetEditButton = dataStore.data.map { it.widgets.editButton } val widgetEditButton = dataStore.data.map { it.widgets.editButton }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setWidgetEditButton(editButton: Boolean) { fun setWidgetEditButton(editButton: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -2,7 +2,6 @@ package de.mm20.launcher2.ui.settings.integrations
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.accounts.Account import de.mm20.launcher2.accounts.Account

View File

@ -11,8 +11,8 @@ import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material.icons.rounded.OpenInBrowser import androidx.compose.material.icons.rounded.OpenInBrowser
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
@ -102,7 +102,7 @@ fun LicenseScreen(library: OpenSourceLibrary) {
style = MaterialTheme.typography.bodySmall style = MaterialTheme.typography.bodySmall
) )
} }
val licenseText by viewModel.getLicenseText(library).observeAsState() val licenseText by viewModel.getLicenseText(library).collectAsState(null)
licenseText?.let { licenseText?.let {
Text( Text(
text = it, text = it,

View File

@ -2,13 +2,13 @@ package de.mm20.launcher2.ui.settings.license
import android.app.Application import android.app.Application
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.liveData
import de.mm20.launcher2.licenses.OpenSourceLibrary import de.mm20.launcher2.licenses.OpenSourceLibrary
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
class LicenseScreenVM(private val context: Application) : AndroidViewModel(context) { class LicenseScreenVM(private val context: Application) : AndroidViewModel(context) {
fun getLicenseText(library: OpenSourceLibrary) = liveData<String?> { fun getLicenseText(library: OpenSourceLibrary) = flow<String?> {
val text = withContext(Dispatchers.IO) { val text = withContext(Dispatchers.IO) {
context.resources.openRawResource(library.licenseText).reader() context.resources.openRawResource(library.licenseText).reader()
.readText() .readText()

View File

@ -9,7 +9,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity

View File

@ -7,7 +7,6 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.* import androidx.compose.material.icons.rounded.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource

View File

@ -2,14 +2,15 @@ package de.mm20.launcher2.ui.settings.search
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.permissions.PermissionGroup import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings import de.mm20.launcher2.preferences.Settings
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -19,6 +20,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
private val permissionsManager: PermissionsManager by inject() private val permissionsManager: PermissionsManager by inject()
val favorites = dataStore.data.map { it.favorites.enabled } val favorites = dataStore.data.map { it.favorites.enabled }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setFavorites(favorites: Boolean) { fun setFavorites(favorites: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -31,7 +33,10 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
val hasContactsPermission = permissionsManager.hasPermission(PermissionGroup.Contacts) val hasContactsPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val contacts = dataStore.data.map { it.contactsSearch.enabled } val contacts = dataStore.data.map { it.contactsSearch.enabled }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setContacts(contacts: Boolean) { fun setContacts(contacts: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -47,7 +52,9 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
} }
val hasCalendarPermission = permissionsManager.hasPermission(PermissionGroup.Calendar) val hasCalendarPermission = permissionsManager.hasPermission(PermissionGroup.Calendar)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val calendar = dataStore.data.map { it.calendarSearch.enabled } val calendar = dataStore.data.map { it.calendarSearch.enabled }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setCalendar(calendar: Boolean) { fun setCalendar(calendar: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -63,6 +70,8 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
} }
val calculator = dataStore.data.map { it.calculatorSearch.enabled } val calculator = dataStore.data.map { it.calculatorSearch.enabled }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setCalculator(calculator: Boolean) { fun setCalculator(calculator: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -74,6 +83,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
} }
val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled } val unitConverter = dataStore.data.map { it.unitConverterSearch.enabled }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setUnitConverter(unitConverter: Boolean) { fun setUnitConverter(unitConverter: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -85,6 +95,8 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
} }
val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled } val wikipedia = dataStore.data.map { it.wikipediaSearch.enabled }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setWikipedia(wikipedia: Boolean) { fun setWikipedia(wikipedia: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -96,6 +108,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
} }
val websites = dataStore.data.map { it.websiteSearch.enabled } val websites = dataStore.data.map { it.websiteSearch.enabled }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setWebsites(websites: Boolean) { fun setWebsites(websites: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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 } val autoFocus = dataStore.data.map { it.searchBar.autoFocus }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setAutoFocus(autoFocus: Boolean) { fun setAutoFocus(autoFocus: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -129,6 +132,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
} }
val launchOnEnter = dataStore.data.map { it.searchBar.launchOnEnter } val launchOnEnter = dataStore.data.map { it.searchBar.launchOnEnter }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setLaunchOnEnter(launchOnEnter: Boolean) { fun setLaunchOnEnter(launchOnEnter: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -140,7 +144,9 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
} }
val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts) val hasAppShortcutPermission = permissionsManager.hasPermission(PermissionGroup.AppShortcuts)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
val appShortcuts = dataStore.data.map { it.appShortcutSearch.enabled } val appShortcuts = dataStore.data.map { it.appShortcutSearch.enabled }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setAppShortcuts(appShortcuts: Boolean) { fun setAppShortcuts(appShortcuts: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -152,6 +158,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
} }
val searchResultOrdering = dataStore.data.map { it.resultOrdering.ordering } val searchResultOrdering = dataStore.data.map { it.resultOrdering.ordering }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setSearchResultOrdering(searchResultOrdering: Settings.SearchResultOrderingSettings.Ordering) { fun setSearchResultOrdering(searchResultOrdering: Settings.SearchResultOrderingSettings.Ordering) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {
@ -164,6 +171,7 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent {
val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults } val reverseSearchResults = dataStore.data.map { it.layout.reverseSearchResults }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setReverseSearchResults(reverseSearchResults: Boolean) { fun setReverseSearchResults(reverseSearchResults: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -25,8 +25,8 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
@ -69,8 +69,8 @@ fun SearchActionsSettingsScreen() {
onItemMove = { from, to -> viewModel.moveItem(from.index, to.index) } onItemMove = { from, to -> viewModel.moveItem(from.index, to.index) }
) )
val searchActions by viewModel.searchActions.observeAsState(emptyList()) val searchActions by viewModel.searchActions.collectAsState()
val disabledActions by viewModel.disabledActions.observeAsState(emptyList()) val disabledActions by viewModel.disabledActions.collectAsState()
Scaffold( Scaffold(
floatingActionButton = { floatingActionButton = {
@ -187,8 +187,8 @@ fun SearchActionsSettingsScreen() {
} }
} }
val editAction by viewModel.showEditDialogFor.observeAsState(null) val editAction by viewModel.showEditDialogFor
val createAction by viewModel.showCreateDialog.observeAsState(false) val createAction by viewModel.showCreateDialog
if (createAction) { if (createAction) {
EditSearchActionSheet( EditSearchActionSheet(

View File

@ -1,13 +1,14 @@
package de.mm20.launcher2.ui.settings.searchactions package de.mm20.launcher2.ui.settings.searchactions
import androidx.lifecycle.MutableLiveData import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.searchactions.SearchActionService import de.mm20.launcher2.searchactions.SearchActionService
import de.mm20.launcher2.searchactions.builders.CustomizableSearchActionBuilder import de.mm20.launcher2.searchactions.builders.CustomizableSearchActionBuilder
import de.mm20.launcher2.searchactions.builders.SearchActionBuilder import de.mm20.launcher2.searchactions.builders.SearchActionBuilder
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -18,11 +19,11 @@ class SearchActionsSettingsScreenVM : ViewModel(), KoinComponent {
val searchActions = searchActionService val searchActions = searchActionService
.getSearchActionBuilders() .getSearchActionBuilders()
.asLiveData() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
val disabledActions = searchActionService val disabledActions = searchActionService
.getDisabledActionBuilders() .getDisabledActionBuilders()
.asLiveData() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), emptyList())
fun addAction(searchAction: SearchActionBuilder) { fun addAction(searchAction: SearchActionBuilder) {
val actions = val actions =
@ -60,8 +61,8 @@ class SearchActionsSettingsScreenVM : ViewModel(), KoinComponent {
searchActionService.saveSearchActionBuilders(actions) searchActionService.saveSearchActionBuilders(actions)
} }
val showEditDialogFor = MutableLiveData<CustomizableSearchActionBuilder?>(null) val showEditDialogFor = mutableStateOf<CustomizableSearchActionBuilder?>(null)
val showCreateDialog = MutableLiveData(false) val showCreateDialog = mutableStateOf(false)
fun editAction(action: CustomizableSearchActionBuilder) { fun editAction(action: CustomizableSearchActionBuilder) {
showEditDialogFor.value = action showEditDialogFor.value = action

View File

@ -1,19 +1,14 @@
package de.mm20.launcher2.ui.settings.unitconverter 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.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue 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.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.PreferenceCategory import de.mm20.launcher2.ui.component.preferences.PreferenceCategory
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen 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.component.preferences.SwitchPreference
import de.mm20.launcher2.ui.settings.search.SearchSettingsScreenVM
@Composable @Composable
fun UnitConverterSettingsScreen() { fun UnitConverterSettingsScreen() {
@ -21,7 +16,7 @@ fun UnitConverterSettingsScreen() {
PreferenceScreen(title = stringResource(R.string.preference_search_unitconverter)) { PreferenceScreen(title = stringResource(R.string.preference_search_unitconverter)) {
item { item {
PreferenceCategory { PreferenceCategory {
val unitConverter by viewModel.unitConverter.observeAsState() val unitConverter by viewModel.unitConverter.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_search_unitconverter), title = stringResource(R.string.preference_search_unitconverter),
summary = stringResource(R.string.preference_search_unitconverter_summary), summary = stringResource(R.string.preference_search_unitconverter_summary),
@ -30,7 +25,7 @@ fun UnitConverterSettingsScreen() {
viewModel.setUnitConverter(it) viewModel.setUnitConverter(it)
} }
) )
val currencyConverter by viewModel.currencyConverter.observeAsState() val currencyConverter by viewModel.currencyConverter.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_search_currencyconverter), title = stringResource(R.string.preference_search_currencyconverter),
summary = stringResource(R.string.preference_search_currencyconverter_summary), summary = stringResource(R.string.preference_search_currencyconverter_summary),

View File

@ -1,10 +1,11 @@
package de.mm20.launcher2.ui.settings.unitconverter package de.mm20.launcher2.ui.settings.unitconverter
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -13,7 +14,8 @@ class UnitConverterSettingsScreenVM: ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject() 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) { fun setUnitConverter(unitConverter: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setCurrencyConverter(currencyConverter: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -4,7 +4,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -29,7 +28,7 @@ fun WeatherIntegrationSettingsScreen() {
) { ) {
item { item {
PreferenceCategory { PreferenceCategory {
val weatherProvider by viewModel.weatherProvider.observeAsState() val weatherProvider by viewModel.weatherProvider.collectAsState()
ListPreference( ListPreference(
title = stringResource(R.string.preference_weather_provider), title = stringResource(R.string.preference_weather_provider),
items = viewModel.availableProviders.map { items = viewModel.availableProviders.map {
@ -60,7 +59,7 @@ fun WeatherIntegrationSettingsScreen() {
} }
item { item {
PreferenceCategory(title = stringResource(R.string.preference_category_location)) { PreferenceCategory(title = stringResource(R.string.preference_category_location)) {
val hasPermission by viewModel.hasLocationPermission.observeAsState() val hasPermission by viewModel.hasLocationPermission.collectAsState()
AnimatedVisibility(hasPermission == false) { AnimatedVisibility(hasPermission == false) {
MissingPermissionBanner( MissingPermissionBanner(
text = stringResource(R.string.missing_permission_auto_location), text = stringResource(R.string.missing_permission_auto_location),
@ -70,7 +69,7 @@ fun WeatherIntegrationSettingsScreen() {
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
) )
} }
val autoLocation by viewModel.autoLocation.observeAsState(false) val autoLocation by viewModel.autoLocation.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_automatic_location), title = stringResource(R.string.preference_automatic_location),
summary = stringResource(R.string.preference_automatic_location_summary), summary = stringResource(R.string.preference_automatic_location_summary),
@ -79,7 +78,7 @@ fun WeatherIntegrationSettingsScreen() {
viewModel.setAutoLocation(it) viewModel.setAutoLocation(it)
} }
) )
val location by viewModel.location.observeAsState() val location by viewModel.location
LocationPreference( LocationPreference(
title = stringResource(R.string.preference_location), title = stringResource(R.string.preference_location),
value = location, value = location,

View File

@ -1,9 +1,8 @@
package de.mm20.launcher2.ui.settings.weather package de.mm20.launcher2.ui.settings.weather
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.permissions.PermissionGroup import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager 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.WeatherLocation
import de.mm20.launcher2.weather.WeatherRepository import de.mm20.launcher2.weather.WeatherRepository
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -25,7 +26,8 @@ class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
val availableProviders = repository.getAvailableProviders() val availableProviders = repository.getAvailableProviders()
val weatherProvider = repository.selectedProvider.asLiveData() val weatherProvider = repository.selectedProvider
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun setWeatherProvider(provider: WeatherSettings.WeatherProvider) { fun setWeatherProvider(provider: WeatherSettings.WeatherProvider) {
repository.selectProvider(provider) 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) { fun setAutoLocation(autoLocation: Boolean) {
repository.setAutoLocation(autoLocation) repository.setAutoLocation(autoLocation)
} }
val location = MutableLiveData<WeatherLocation?>(null) val location = mutableStateOf<WeatherLocation?>(null)
val hasLocationPermission = permissionsManager.hasPermission(PermissionGroup.Location).asLiveData() val hasLocationPermission = permissionsManager.hasPermission(PermissionGroup.Location)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null)
fun requestLocationPermission(activity: AppCompatActivity) { fun requestLocationPermission(activity: AppCompatActivity) {
permissionsManager.requestPermission(activity, PermissionGroup.Location) permissionsManager.requestPermission(activity, PermissionGroup.Location)
@ -64,7 +68,7 @@ class WeatherIntegrationSettingsScreenVM : ViewModel(), KoinComponent {
if (autoLoc) lastLoc if (autoLoc) lastLoc
else loc else loc
}.collectLatest { }.collectLatest {
this@WeatherIntegrationSettingsScreenVM.location.postValue(it) this@WeatherIntegrationSettingsScreenVM.location.value = it
} }
} }
} }

View File

@ -1,8 +1,8 @@
package de.mm20.launcher2.ui.settings.wikipedia package de.mm20.launcher2.ui.settings.wikipedia
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.R
@ -15,7 +15,7 @@ fun WikipediaSettingsScreen() {
val viewModel: WikipediaSettingsScreenVM = viewModel() val viewModel: WikipediaSettingsScreenVM = viewModel()
PreferenceScreen(title = stringResource(R.string.preference_search_wikipedia)) { PreferenceScreen(title = stringResource(R.string.preference_search_wikipedia)) {
item { item {
val wikipedia by viewModel.wikipedia.observeAsState() val wikipedia by viewModel.wikipedia.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_search_wikipedia), title = stringResource(R.string.preference_search_wikipedia),
summary = stringResource(R.string.preference_search_wikipedia_summary), summary = stringResource(R.string.preference_search_wikipedia_summary),
@ -24,7 +24,7 @@ fun WikipediaSettingsScreen() {
viewModel.setWikipedia(it) viewModel.setWikipedia(it)
} }
) )
val images by viewModel.images.observeAsState() val images by viewModel.images.collectAsState()
SwitchPreference( SwitchPreference(
title = stringResource(R.string.preference_search_wikipedia_pictures), title = stringResource(R.string.preference_search_wikipedia_pictures),
summary = stringResource(R.string.preference_search_wikipedia_pictures_summary), summary = stringResource(R.string.preference_search_wikipedia_pictures_summary),
@ -34,7 +34,7 @@ fun WikipediaSettingsScreen() {
viewModel.setImages(it) viewModel.setImages(it)
} }
) )
val customUrl by viewModel.customUrl.observeAsState("") val customUrl by viewModel.customUrl.collectAsState()
TextPreference( TextPreference(
title = stringResource(R.string.preference_wikipedia_customurl), title = stringResource(R.string.preference_wikipedia_customurl),
value = customUrl, value = customUrl,

View File

@ -1,10 +1,11 @@
package de.mm20.launcher2.ui.settings.wikipedia package de.mm20.launcher2.ui.settings.wikipedia
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherDataStore
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@ -12,7 +13,8 @@ import org.koin.core.component.inject
class WikipediaSettingsScreenVM: ViewModel(), KoinComponent { class WikipediaSettingsScreenVM: ViewModel(), KoinComponent {
private val dataStore: LauncherDataStore by inject() 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) { fun setWikipedia(wikipedia: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setImages(images: Boolean) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { 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) { fun setCustomUrl(customUrl: String) {
viewModelScope.launch { viewModelScope.launch {
dataStore.updateData { dataStore.updateData {

View File

@ -1,13 +1,10 @@
package de.mm20.launcher2.database package de.mm20.launcher2.database
import androidx.lifecycle.LiveData
import androidx.room.* import androidx.room.*
import de.mm20.launcher2.database.entities.IconEntity import de.mm20.launcher2.database.entities.IconEntity
import de.mm20.launcher2.database.entities.IconPackEntity import de.mm20.launcher2.database.entities.IconPackEntity
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
internal val AppTypes = listOf("app", "calendar", "clock")
@Dao @Dao
interface IconDao { interface IconDao {
@Insert @Insert

View File

@ -37,8 +37,6 @@ dependencyResolutionManagement {
version("androidx.compose.compiler", "1.4.5") version("androidx.compose.compiler", "1.4.5")
library("androidx.compose.runtime", "androidx.compose.runtime", "runtime") library("androidx.compose.runtime", "androidx.compose.runtime", "runtime")
.version("1.5.0-alpha03") .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") library("androidx.compose.foundation", "androidx.compose.foundation", "foundation")
.version("1.5.0-alpha03") .version("1.5.0-alpha03")
library("androidx.compose.foundationlayout", "androidx.compose.foundation", "foundation-layout") library("androidx.compose.foundationlayout", "androidx.compose.foundation", "foundation-layout")
@ -61,8 +59,6 @@ dependencyResolutionManagement {
version("androidx.lifecycle", "2.6.1") version("androidx.lifecycle", "2.6.1")
library("androidx.lifecycle.viewmodel", "androidx.lifecycle", "lifecycle-viewmodel-ktx") library("androidx.lifecycle.viewmodel", "androidx.lifecycle", "lifecycle-viewmodel-ktx")
.versionRef("androidx.lifecycle") .versionRef("androidx.lifecycle")
library("androidx.lifecycle.livedata", "androidx.lifecycle", "lifecycle-livedata-ktx")
.versionRef("androidx.lifecycle")
library("androidx.lifecycle.common", "androidx.lifecycle", "lifecycle-common-java8") library("androidx.lifecycle.common", "androidx.lifecycle", "lifecycle-common-java8")
.versionRef("androidx.lifecycle") .versionRef("androidx.lifecycle")
library("androidx.lifecycle.runtime", "androidx.lifecycle", "lifecycle-runtime-ktx") library("androidx.lifecycle.runtime", "androidx.lifecycle", "lifecycle-runtime-ktx")
@ -75,7 +71,6 @@ dependencyResolutionManagement {
"androidx.lifecycle", "androidx.lifecycle",
listOf( listOf(
"androidx.lifecycle.viewmodel", "androidx.lifecycle.viewmodel",
"androidx.lifecycle.livedata",
"androidx.lifecycle.common", "androidx.lifecycle.common",
"androidx.lifecycle.runtime" "androidx.lifecycle.runtime"
) )