diff --git a/favorites/src/main/java/de/mm20/launcher2/favorites/FavoritesRepository.kt b/favorites/src/main/java/de/mm20/launcher2/favorites/FavoritesRepository.kt index 7238ee78..427d0fd0 100644 --- a/favorites/src/main/java/de/mm20/launcher2/favorites/FavoritesRepository.kt +++ b/favorites/src/main/java/de/mm20/launcher2/favorites/FavoritesRepository.kt @@ -4,6 +4,7 @@ import android.content.Context import de.mm20.launcher2.database.AppDatabase import de.mm20.launcher2.database.entities.FavoritesItemEntity import de.mm20.launcher2.ktx.ceilToInt +import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherPreferences import de.mm20.launcher2.search.SearchableDeserializer import de.mm20.launcher2.search.data.CalendarEvent @@ -33,7 +34,8 @@ interface FavoritesRepository { internal class FavoritesRepositoryImpl( private val context: Context, - private val database: AppDatabase + private val database: AppDatabase, + private val dataStore: LauncherDataStore ) : FavoritesRepository, KoinComponent { private val scope = CoroutineScope(Job() + Dispatchers.Default) @@ -42,16 +44,7 @@ internal class FavoritesRepositoryImpl( withContext(Dispatchers.IO) { - val gridColumns = callbackFlow { - send(LauncherPreferences.instance.gridColumnCount) - val unregister = - LauncherPreferences.instance.doOnPreferenceChange("grid_column_count") { - trySendBlocking(LauncherPreferences.instance.gridColumnCount) - } - awaitClose { - unregister() - } - } + val gridColumns = dataStore.data.map { it.grid.columnCount }.distinctUntilChanged() val dao = database.searchDao() val pinnedFavorites = dao.getFavorites().map { diff --git a/favorites/src/main/java/de/mm20/launcher2/favorites/Module.kt b/favorites/src/main/java/de/mm20/launcher2/favorites/Module.kt index f04615c3..3759ef60 100644 --- a/favorites/src/main/java/de/mm20/launcher2/favorites/Module.kt +++ b/favorites/src/main/java/de/mm20/launcher2/favorites/Module.kt @@ -91,5 +91,5 @@ val favoritesModule = module { return@factory NullDeserializer() } - single { FavoritesRepositoryImpl(androidContext(), get()) } + single { FavoritesRepositoryImpl(androidContext(), get(), get()) } } \ No newline at end of file diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt index e01710e8..e3897eca 100644 --- a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt @@ -4,81 +4,101 @@ import android.content.Context fun createFactorySettings(context: Context): Settings { return Settings.newBuilder() - .setAppearance(Settings.AppearanceSettings - .newBuilder() - .setTheme(Settings.AppearanceSettings.Theme.System) - .setColorScheme(Settings.AppearanceSettings.ColorScheme.Default) - .build() + .setAppearance( + Settings.AppearanceSettings + .newBuilder() + .setTheme(Settings.AppearanceSettings.Theme.System) + .setColorScheme(Settings.AppearanceSettings.ColorScheme.Default) + .build() ) - .setWeather(Settings.WeatherSettings - .newBuilder() - .setProvider(Settings.WeatherSettings.WeatherProvider.MetNo) - .setImperialUnits(context.resources.getBoolean(R.bool.default_imperialUnits)) - .build() + .setWeather( + Settings.WeatherSettings + .newBuilder() + .setProvider(Settings.WeatherSettings.WeatherProvider.MetNo) + .setImperialUnits(context.resources.getBoolean(R.bool.default_imperialUnits)) + .build() ) - .setMusicWidget(Settings.MusicWidgetSettings - .newBuilder() - .setFilterSources(true) - .build() + .setMusicWidget( + Settings.MusicWidgetSettings + .newBuilder() + .setFilterSources(true) + .build() ) - .setCalendarWidget(Settings.CalendarWidgetSettings - .newBuilder() - .setHideAlldayEvents(false) + .setCalendarWidget( + Settings.CalendarWidgetSettings + .newBuilder() + .setHideAlldayEvents(false) ) - .setClockWidget(Settings.ClockWidgetSettings - .newBuilder() - .setLayout(Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical) - .setClockStyle(Settings.ClockWidgetSettings.ClockStyle.DigitalClock1) - .build() + .setClockWidget( + Settings.ClockWidgetSettings + .newBuilder() + .setLayout(Settings.ClockWidgetSettings.ClockWidgetLayout.Vertical) + .setClockStyle(Settings.ClockWidgetSettings.ClockStyle.DigitalClock1) + .build() ) - .setFavorites(Settings.FavoritesSettings - .newBuilder() - .setEnabled(true) + .setFavorites( + Settings.FavoritesSettings + .newBuilder() + .setEnabled(true) ) - .setFileSearch(Settings.FilesSearchSettings - .newBuilder() - .setLocalFiles(true) - .setNextcloud(false) - .setGdrive(false) - .setOnedrive(false) - .setNextcloud(false) + .setFileSearch( + Settings.FilesSearchSettings + .newBuilder() + .setLocalFiles(true) + .setNextcloud(false) + .setGdrive(false) + .setOnedrive(false) + .setNextcloud(false) ) - .setContactsSearch(Settings.ContactsSearchSettings - .newBuilder() - .setEnabled(true) + .setContactsSearch( + Settings.ContactsSearchSettings + .newBuilder() + .setEnabled(true) ) - .setCalendarSearch(Settings.CalendarSearchSettings - .newBuilder() - .setEnabled(true) + .setCalendarSearch( + Settings.CalendarSearchSettings + .newBuilder() + .setEnabled(true) ) - .setCalculatorSearch(Settings.CalculatorSearchSettings - .newBuilder() - .setEnabled(true) + .setCalculatorSearch( + Settings.CalculatorSearchSettings + .newBuilder() + .setEnabled(true) ) - .setUnitConverterSearch(Settings.UnitConverterSearchSettings - .newBuilder() - .setEnabled(true) + .setUnitConverterSearch( + Settings.UnitConverterSearchSettings + .newBuilder() + .setEnabled(true) ) - .setWikipediaSearch(Settings.WikipediaSearchSettings - .newBuilder() - .setEnabled(false) - .setImages(false) - .setCustomUrl("") + .setWikipediaSearch( + Settings.WikipediaSearchSettings + .newBuilder() + .setEnabled(false) + .setImages(false) + .setCustomUrl("") ) - .setWebsiteSearch(Settings.WebsiteSearchSettings - .newBuilder() - .setEnabled(false) + .setWebsiteSearch( + Settings.WebsiteSearchSettings + .newBuilder() + .setEnabled(false) ) - .setWebSearch(Settings.WebSearchSettings - .newBuilder() - .setEnabled(true) + .setWebSearch( + Settings.WebSearchSettings + .newBuilder() + .setEnabled(true) ) - .setBadges(Settings.BadgeSettings - .newBuilder() - .setNotifications(true) - .setCloudFiles(true) - .setShortcuts(true) - .setSuspendedApps(true) + .setBadges( + Settings.BadgeSettings + .newBuilder() + .setNotifications(true) + .setCloudFiles(true) + .setShortcuts(true) + .setSuspendedApps(true) + ) + .setGrid( + Settings.GridSettings.newBuilder() + .setColumnCount(context.resources.getInteger(R.integer.config_columnCount)) + .build() ) .build() } \ No newline at end of file diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherPreferences.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherPreferences.kt index b2bc54a6..e52d15dd 100644 --- a/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherPreferences.kt +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/LauncherPreferences.kt @@ -74,19 +74,6 @@ class LauncherPreferences(val context: Application, version: Int = 3) { var easterEggEnabled by BooleanPreference("easter_egg", default = false) - var gridColumnCount by IntPreference("grid_column_count", default = context.resources.getInteger(R.integer.config_columnCount)) - - - fun doOnPreferenceChange(vararg keys: String, action: (String) -> Unit): () -> Unit { - val listener = { _: SharedPreferences, key: String -> - if (keys.contains(key)) action(key) - } - preferences.registerOnSharedPreferenceChangeListener(listener) - return { - preferences.unregisterOnSharedPreferenceChangeListener(listener) - } - } - companion object { lateinit var instance: LauncherPreferences fun initialize(app: Application) { diff --git a/preferences/src/main/proto/settings.proto b/preferences/src/main/proto/settings.proto index cca5caaf..9be2089d 100644 --- a/preferences/src/main/proto/settings.proto +++ b/preferences/src/main/proto/settings.proto @@ -117,4 +117,9 @@ message Settings { } BadgeSettings badges = 18; + message GridSettings { + uint32 column_count = 1; + } + GridSettings grid = 19; + } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/SearchGridView.kt b/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/SearchGridView.kt index c3aefb9f..2990210b 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/SearchGridView.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/SearchGridView.kt @@ -6,36 +6,61 @@ import android.util.AttributeSet import android.view.View import android.view.ViewGroup import androidx.core.view.children +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListUpdateCallback import de.mm20.launcher2.ktx.ceilToInt +import de.mm20.launcher2.ktx.lifecycleOwner import de.mm20.launcher2.ktx.lifecycleScope import de.mm20.launcher2.legacy.helper.ActivityStarter import de.mm20.launcher2.legacy.helper.ActivityStarterCallback +import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.preferences.LauncherPreferences import de.mm20.launcher2.search.data.Searchable import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.legacy.searchable.SearchableView -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ObsoleteCoroutinesApi +import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.actor -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject import java.util.* import kotlin.math.min -class SearchGridView : ViewGroup, ActivityStarterCallback { +class SearchGridView : ViewGroup, ActivityStarterCallback, KoinComponent { override fun onResume() { while (postponedDiffs.isNotEmpty()) { postponedDiffs.poll()?.let { applyDiff(it, true) } } } + val dataStore: LauncherDataStore by inject() + + var job: Job? = null + override fun onAttachedToWindow() { + super.onAttachedToWindow() + job?.cancel() + lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + dataStore.data.map { it.grid.columnCount }.distinctUntilChanged().collectLatest { + columnCount = it + } + } + } + } + var columnCount: Int = 1 set(value) { - if (value > 0) field = value + if (value > 0) { + field = value + requestLayout() + } else throw IllegalArgumentException("columnCount must be positive (is $value)") } @@ -100,8 +125,9 @@ class SearchGridView : ViewGroup, ActivityStarterCallback { } init { - columnCount = LauncherPreferences.instance.gridColumnCount.takeIf { it > 1 } - ?: context.resources.getInteger(R.integer.config_columnCount) + columnCount = runBlocking { + dataStore.data.map { it.grid.columnCount }.first().takeIf { it > 0 } ?: 5 + } } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt index 5592d5f0..2dbec317 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt @@ -45,6 +45,19 @@ fun AppearanceSettingsScreen() { } ) } + PreferenceCategory(title = stringResource(R.string.preference_category_grid)) { + val columnCount by viewModel.columnCount.observeAsState() + ListPreference( + title = stringResource(R.string.preference_grid_column_count), + items = (3..8).map { + it.toString() to it + }, + value = columnCount, + onValueChanged = { + if (it != null) viewModel.setColumnCount(it) + } + ) + } } } } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt index c380d4cf..1d4f4c85 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt @@ -35,4 +35,15 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent { } } } + + val columnCount = dataStore.data.map { it.grid.columnCount }.asLiveData() + fun setColumnCount(columnCount: Int) { + viewModelScope.launch { + dataStore.updateData { + it.toBuilder() + .setGrid(it.grid.toBuilder().setColumnCount(columnCount)) + .build() + } + } + } } \ No newline at end of file