Move FilterProvider to kmp

pull/2945/head
Alex Baker 3 months ago
parent 83e43ba72c
commit a067651c23

@ -178,6 +178,7 @@ dependencies {
ksp(libs.androidx.hilt.compiler)
implementation(libs.androidx.hilt.work)
implementation(libs.androidx.datastore)
implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.lifecycle.runtime)
implementation(libs.androidx.lifecycle.runtime.compose)

@ -3,6 +3,7 @@ package com.todoroo.astrid.activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@ -32,8 +33,8 @@ import org.tasks.filters.Filter
import org.tasks.filters.FilterProvider
import org.tasks.filters.NavigationDrawerSubheader
import org.tasks.filters.getIcon
import org.tasks.preferences.TasksPreferences
import org.tasks.preferences.DefaultFilterProvider
import org.tasks.preferences.Preferences
import org.tasks.themes.ColorProvider
import timber.log.Timber
import javax.inject.Inject
@ -48,7 +49,7 @@ class MainActivityViewModel @Inject constructor(
private val inventory: Inventory,
private val colorProvider: ColorProvider,
private val caldavDao: CaldavDao,
private val preferences: Preferences,
private val tasksPreferences: TasksPreferences,
) : ViewModel() {
data class State(
@ -193,7 +194,7 @@ class MainActivityViewModel @Inject constructor(
val collapsed = !subheader.isCollapsed
when (subheader.subheaderType) {
NavigationDrawerSubheader.SubheaderType.PREFERENCE -> {
preferences.setBoolean(subheader.id.toInt(), collapsed)
tasksPreferences.set(booleanPreferencesKey(subheader.id), collapsed)
localBroadcastManager.broadcastRefreshList()
}
NavigationDrawerSubheader.SubheaderType.GOOGLE_TASKS,

@ -3,6 +3,7 @@ package com.todoroo.astrid.adapter
import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import org.tasks.LocalBroadcastManager
@ -21,15 +22,15 @@ import org.tasks.filters.NavigationDrawerSubheader.SubheaderType.CALDAV
import org.tasks.filters.NavigationDrawerSubheader.SubheaderType.GOOGLE_TASKS
import org.tasks.filters.NavigationDrawerSubheader.SubheaderType.PREFERENCE
import org.tasks.filters.NavigationDrawerSubheader.SubheaderType.TASKS
import org.tasks.preferences.TasksPreferences
import org.tasks.location.LocationPickerActivity
import org.tasks.preferences.MainPreferences
import org.tasks.preferences.Preferences
import timber.log.Timber
import javax.inject.Inject
class SubheaderClickHandler @Inject constructor(
private val activity: Activity,
private val preferences: Preferences,
private val tasksPreferences: TasksPreferences,
private val caldavDao: CaldavDao,
private val localBroadcastManager: LocalBroadcastManager,
): SubheaderViewHolder.ClickHandler {
@ -37,7 +38,7 @@ class SubheaderClickHandler @Inject constructor(
(activity as AppCompatActivity).lifecycleScope.launch {
val collapsed = !subheader.isCollapsed
when (subheader.subheaderType) {
PREFERENCE -> preferences.setBoolean(subheader.id.toInt(), collapsed)
PREFERENCE -> tasksPreferences.set(booleanPreferencesKey(subheader.id), collapsed)
GOOGLE_TASKS,
CALDAV,
TASKS -> caldavDao.setCollapsed(subheader.id, collapsed)

@ -1,42 +0,0 @@
/*
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.core
import org.tasks.R
import org.tasks.data.dao.TaskDao
import org.tasks.filters.Filter
import org.tasks.filters.NotificationsFilter
import org.tasks.filters.RecentlyModifiedFilter
import org.tasks.filters.SnoozedFilter
import org.tasks.filters.TimerFilter
import org.tasks.filters.TodayFilter
import org.tasks.preferences.Preferences
import javax.inject.Inject
class BuiltInFilterExposer @Inject constructor(
private val preferences: Preferences,
private val taskDao: TaskDao
) {
suspend fun filters(): List<Filter> {
val filters: MutableList<Filter> = ArrayList()
if (preferences.getBoolean(R.string.p_show_today_filter, true)) {
filters.add(TodayFilter.create())
}
if (preferences.getBoolean(R.string.p_show_recently_modified_filter, true)) {
filters.add(RecentlyModifiedFilter.create())
}
if (taskDao.snoozedReminders() > 0) {
filters.add(SnoozedFilter.create())
}
if (taskDao.activeTimers() > 0) {
filters.add(TimerFilter.create())
}
if (taskDao.hasNotifications() > 0) {
filters.add(NotificationsFilter.create())
}
return filters
}
}

@ -0,0 +1,33 @@
package org.tasks.filters
import org.tasks.R
import org.tasks.compose.drawer.DrawerConfiguration
import org.tasks.preferences.Preferences
class PreferenceDrawerConfiguration(
private val preferences: Preferences
) : DrawerConfiguration {
override val filtersEnabled: Boolean
get() = preferences.getBoolean(R.string.p_filters_enabled, super.filtersEnabled)
override val placesEnabled: Boolean
get() = preferences.getBoolean(R.string.p_places_enabled, super.placesEnabled)
override val hideUnusedPlaces: Boolean
get() = preferences.getBoolean(R.string.p_places_hide_unused, super.hideUnusedPlaces)
override val tagsEnabled: Boolean
get() = preferences.getBoolean(R.string.p_tags_enabled, super.tagsEnabled)
override val hideUnusedTags: Boolean
get() = preferences.getBoolean(R.string.p_tags_hide_unused, super.hideUnusedTags)
override val todayFilter: Boolean
get() = preferences.getBoolean(R.string.p_show_today_filter, super.todayFilter)
override val recentlyModifiedFilter: Boolean
get() = preferences.getBoolean(R.string.p_show_recently_modified_filter, super.recentlyModifiedFilter)
override val localListsEnabled: Boolean
get() = preferences.getBoolean(R.string.p_lists_enabled, super.localListsEnabled)
}

@ -3,7 +3,6 @@ package org.tasks.injection
import android.app.NotificationManager
import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
import org.tasks.data.db.Database
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -17,21 +16,28 @@ import org.tasks.billing.BillingClient
import org.tasks.billing.BillingClientImpl
import org.tasks.billing.Inventory
import org.tasks.data.dao.AlarmDao
import org.tasks.data.dao.CaldavDao
import org.tasks.data.dao.Astrid2ContentProviderDao
import org.tasks.data.dao.CaldavDao
import org.tasks.data.dao.DeletionDao
import org.tasks.data.dao.FilterDao
import org.tasks.data.dao.GoogleTaskDao
import org.tasks.data.dao.GoogleTaskListDao
import org.tasks.data.dao.LocationDao
import org.tasks.data.dao.NotificationDao
import org.tasks.data.dao.TagDao
import org.tasks.data.dao.TagDataDao
import org.tasks.data.dao.TaskAttachmentDao
import org.tasks.data.dao.TaskDao
import org.tasks.data.dao.TaskListMetadataDao
import org.tasks.data.dao.UserActivityDao
import org.tasks.data.db.Database
import org.tasks.filters.PreferenceDrawerConfiguration
import org.tasks.jobs.WorkManager
import org.tasks.data.dao.NotificationDao
import org.tasks.kmp.createDataStore
import org.tasks.compose.drawer.DrawerConfiguration
import org.tasks.filters.FilterProvider
import org.tasks.preferences.TasksPreferences
import org.tasks.preferences.Preferences
import java.util.Locale
import javax.inject.Singleton
@ -134,4 +140,34 @@ class ApplicationModule {
@Provides
fun providesNotificationManager(@ApplicationContext context: Context) =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@Singleton
@Provides
fun providesTasksPreferences(@ApplicationContext context: Context) =
TasksPreferences(createDataStore(context))
@Provides
fun providesDrawerConfiguration(preferences: Preferences): DrawerConfiguration =
PreferenceDrawerConfiguration(preferences)
@Provides
fun providesFilterProvider(
filterDao: FilterDao,
tagDataDao: TagDataDao,
googleTaskListDao: GoogleTaskListDao,
caldavDao: CaldavDao,
drawerConfiguration: DrawerConfiguration,
locationDao: LocationDao,
taskDao: TaskDao,
tasksPreferences: TasksPreferences,
) = FilterProvider(
filterDao = filterDao,
tagDataDao = tagDataDao,
googleTaskListDao = googleTaskListDao,
caldavDao = caldavDao,
configuration = drawerConfiguration,
locationDao = locationDao,
taskDao = taskDao,
tasksPreferences = tasksPreferences,
)
}

@ -390,10 +390,6 @@
<string name="p_list_chips">chips_list</string>
<string name="p_tag_chips">chips_tag</string>
<string name="p_desaturate_colors">desaturate_colors</string>
<string name="p_collapse_filters">collapse_filters</string>
<string name="p_collapse_debug">collapse_debug</string>
<string name="p_collapse_tags">collapse_tags</string>
<string name="p_collapse_locations">collapse_locations</string>
<string name="p_auto_dismiss_datetime_edit_screen">auto_dismiss_datetime_edit_screen</string>
<string name="p_auto_dismiss_datetime_list_screen">auto_dismiss_datetime_list_screen</string>
<string name="p_auto_dismiss_datetime_widget">auto_dismiss_datetime_widget</string>

@ -55,7 +55,7 @@ abstract class CaldavDao(private val database: Database) {
abstract suspend fun getAccount(type: Int, username: String): CaldavAccount?
@Query("SELECT * FROM caldav_accounts WHERE cda_id = :id")
abstract suspend fun getAccount(id: Long): CaldavAccount?
abstract suspend fun getAccount(id: String): CaldavAccount?
@Query("SELECT * FROM caldav_accounts WHERE cda_id = :id")
abstract fun watchAccount(id: Long): Flow<CaldavAccount?>
@ -83,7 +83,7 @@ ORDER BY CASE cda_account_type
abstract suspend fun getAccounts(): List<CaldavAccount>
@Query("UPDATE caldav_accounts SET cda_collapsed = :collapsed WHERE cda_id = :id")
abstract suspend fun setCollapsed(id: Long, collapsed: Boolean)
abstract suspend fun setCollapsed(id: String, collapsed: Boolean)
@Insert
abstract suspend fun insert(caldavAccount: CaldavAccount): Long

@ -611,6 +611,56 @@
+| | +--- androidx.compose.material:material-icons-core:1.6.8 (c)
+| | \--- androidx.compose.material:material-ripple:1.6.8 (c)
+| +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*)
+| +--- androidx.datastore:datastore-preferences:1.1.1
+| | \--- androidx.datastore:datastore-preferences-android:1.1.1
+| | +--- androidx.datastore:datastore:1.1.1
+| | | \--- androidx.datastore:datastore-android:1.1.1
+| | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.0 (*)
+| | | +--- androidx.datastore:datastore-core:1.1.1
+| | | | \--- androidx.datastore:datastore-core-android:1.1.1
+| | | | +--- androidx.annotation:annotation:1.7.0 -> 1.8.0 (*)
+| | | | +--- org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22 -> 2.0.0 (*)
+| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.0 (*)
+| | | | +--- androidx.datastore:datastore:1.1.1 (c)
+| | | | +--- androidx.datastore:datastore-core-okio:1.1.1 (c)
+| | | | +--- androidx.datastore:datastore-preferences:1.1.1 (c)
+| | | | \--- androidx.datastore:datastore-preferences-core:1.1.1 (c)
+| | | +--- androidx.datastore:datastore-core-okio:1.1.1
+| | | | \--- androidx.datastore:datastore-core-okio-jvm:1.1.1
+| | | | +--- androidx.datastore:datastore-core:1.1.1 (*)
+| | | | +--- com.squareup.okio:okio:3.4.0 -> 3.8.0
+| | | | | \--- com.squareup.okio:okio-jvm:3.8.0
+| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.0 (*)
+| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.0 (*)
+| | | | +--- androidx.datastore:datastore:1.1.1 (c)
+| | | | +--- androidx.datastore:datastore-core:1.1.1 (c)
+| | | | +--- androidx.datastore:datastore-preferences:1.1.1 (c)
+| | | | \--- androidx.datastore:datastore-preferences-core:1.1.1 (c)
+| | | +--- com.squareup.okio:okio:3.4.0 -> 3.8.0 (*)
+| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.0 (*)
+| | | +--- androidx.datastore:datastore-core:1.1.1 (c)
+| | | +--- androidx.datastore:datastore-core-okio:1.1.1 (c)
+| | | +--- androidx.datastore:datastore-preferences:1.1.1 (c)
+| | | \--- androidx.datastore:datastore-preferences-core:1.1.1 (c)
+| | +--- androidx.datastore:datastore-preferences-core:1.1.1
+| | | \--- androidx.datastore:datastore-preferences-core-jvm:1.1.1
+| | | +--- androidx.datastore:datastore-core:1.1.1 (*)
+| | | +--- androidx.datastore:datastore-core-okio:1.1.1 (*)
+| | | +--- com.squareup.okio:okio:3.4.0 -> 3.8.0 (*)
+| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | +--- androidx.datastore:datastore:1.1.1 (c)
+| | | +--- androidx.datastore:datastore-core:1.1.1 (c)
+| | | +--- androidx.datastore:datastore-core-okio:1.1.1 (c)
+| | | \--- androidx.datastore:datastore-preferences:1.1.1 (c)
+| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.0 (*)
+| | +--- androidx.datastore:datastore:1.1.1 (c)
+| | +--- androidx.datastore:datastore-preferences-core:1.1.1 (c)
+| | +--- androidx.datastore:datastore-core:1.1.1 (c)
+| | \--- androidx.datastore:datastore-core-okio:1.1.1 (c)
+| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2
+| | \--- androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.2
+| | +--- androidx.annotation:annotation:1.8.0 (*)
@ -720,9 +770,7 @@
+| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.20 -> 2.0.0 (*)
+| +--- org.apache.commons:commons-lang3:3.8.1 -> 3.12.0
+| \--- com.squareup.okhttp3:okhttp:4.10.0 -> 4.12.0
+| +--- com.squareup.okio:okio:3.6.0 -> 3.8.0
+| | \--- com.squareup.okio:okio-jvm:3.8.0
+| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.0 (*)
+| +--- com.squareup.okio:okio:3.6.0 -> 3.8.0 (*)
+| \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 2.0.0 (*)
++--- com.github.tasks:ical4android:12fe73a
+| +--- org.mnode.ical4j:ical4j:3.2.7
@ -886,6 +934,7 @@
+| | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava
+| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.21 -> 2.0.0 (*)
+| \--- com.google.dagger:hilt-android:2.49 -> 2.50 (*)
++--- androidx.datastore:datastore-preferences:1.1.1 (*)
++--- androidx.fragment:fragment-ktx:1.8.0
+| +--- androidx.activity:activity-ktx:1.8.1 -> 1.9.0 (*)
+| +--- androidx.collection:collection-ktx:1.1.0 -> 1.4.0 (*)

@ -375,19 +375,59 @@
+| | | | +--- com.google.firebase:firebase-encoders-json:18.0.0 -> 18.0.1 (*)
+| | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.0 (*)
+| | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.0 (*)
+| | +--- androidx.datastore:datastore-preferences:1.0.0
+| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.0 (*)
+| | | +--- androidx.datastore:datastore:1.0.0
+| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.0 (*)
+| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.8.0 (*)
+| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.0 (*)
+| | | | \--- androidx.datastore:datastore-core:1.0.0
+| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.0 (*)
+| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.8.0 (*)
+| | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.0 (*)
+| | | \--- androidx.datastore:datastore-preferences-core:1.0.0
+| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.0 (*)
+| | | \--- androidx.datastore:datastore-core:1.0.0 (*)
+| | +--- androidx.datastore:datastore-preferences:1.0.0 -> 1.1.1
+| | | \--- androidx.datastore:datastore-preferences-android:1.1.1
+| | | +--- androidx.datastore:datastore:1.1.1
+| | | | \--- androidx.datastore:datastore-android:1.1.1
+| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.0 (*)
+| | | | +--- androidx.datastore:datastore-core:1.1.1
+| | | | | \--- androidx.datastore:datastore-core-android:1.1.1
+| | | | | +--- androidx.annotation:annotation:1.7.0 -> 1.8.0 (*)
+| | | | | +--- org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22 -> 2.0.0
+| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
+| | | | | | \--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.0
+| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
+| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.0 (*)
+| | | | | +--- androidx.datastore:datastore:1.1.1 (c)
+| | | | | +--- androidx.datastore:datastore-core-okio:1.1.1 (c)
+| | | | | +--- androidx.datastore:datastore-preferences:1.1.1 (c)
+| | | | | \--- androidx.datastore:datastore-preferences-core:1.1.1 (c)
+| | | | +--- androidx.datastore:datastore-core-okio:1.1.1
+| | | | | \--- androidx.datastore:datastore-core-okio-jvm:1.1.1
+| | | | | +--- androidx.datastore:datastore-core:1.1.1 (*)
+| | | | | +--- com.squareup.okio:okio:3.4.0 -> 3.8.0
+| | | | | | \--- com.squareup.okio:okio-jvm:3.8.0
+| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.0 (*)
+| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.0 (*)
+| | | | | +--- androidx.datastore:datastore:1.1.1 (c)
+| | | | | +--- androidx.datastore:datastore-core:1.1.1 (c)
+| | | | | +--- androidx.datastore:datastore-preferences:1.1.1 (c)
+| | | | | \--- androidx.datastore:datastore-preferences-core:1.1.1 (c)
+| | | | +--- com.squareup.okio:okio:3.4.0 -> 3.8.0 (*)
+| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.0 (*)
+| | | | +--- androidx.datastore:datastore-core:1.1.1 (c)
+| | | | +--- androidx.datastore:datastore-core-okio:1.1.1 (c)
+| | | | +--- androidx.datastore:datastore-preferences:1.1.1 (c)
+| | | | \--- androidx.datastore:datastore-preferences-core:1.1.1 (c)
+| | | +--- androidx.datastore:datastore-preferences-core:1.1.1
+| | | | \--- androidx.datastore:datastore-preferences-core-jvm:1.1.1
+| | | | +--- androidx.datastore:datastore-core:1.1.1 (*)
+| | | | +--- androidx.datastore:datastore-core-okio:1.1.1 (*)
+| | | | +--- com.squareup.okio:okio:3.4.0 -> 3.8.0 (*)
+| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | | +--- androidx.datastore:datastore:1.1.1 (c)
+| | | | +--- androidx.datastore:datastore-core:1.1.1 (c)
+| | | | +--- androidx.datastore:datastore-core-okio:1.1.1 (c)
+| | | | \--- androidx.datastore:datastore-preferences:1.1.1 (c)
+| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.0 (*)
+| | | +--- androidx.datastore:datastore:1.1.1 (c)
+| | | +--- androidx.datastore:datastore-preferences-core:1.1.1 (c)
+| | | +--- androidx.datastore:datastore-core:1.1.1 (c)
+| | | \--- androidx.datastore:datastore-core-okio:1.1.1 (c)
+| | +--- com.google.android.datatransport:transport-api:3.0.0 (*)
+| | \--- androidx.annotation:annotation:1.5.0 -> 1.8.0 (*)
+| +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*)
@ -590,10 +630,7 @@
+| +--- com.google.android.gms:play-services-base:18.5.0 (*)
+| +--- com.google.android.gms:play-services-basement:18.4.0 (*)
+| \--- com.google.android.gms:play-services-tasks:18.2.0 (*)
++--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.0
+| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
+| \--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.0
+| \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
++--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.0 (*)
++--- project :data
+| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
+| +--- androidx.room:room-runtime:2.7.0-alpha04
@ -920,6 +957,7 @@
+| | +--- androidx.compose.material:material-icons-core:1.6.8 (c)
+| | \--- androidx.compose.material:material-ripple:1.6.8 (c)
+| +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*)
+| +--- androidx.datastore:datastore-preferences:1.1.1 (*)
+| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2
+| | \--- androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.2
+| | +--- androidx.annotation:annotation:1.8.0 (*)
@ -965,9 +1003,7 @@
+| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.20 -> 2.0.0 (*)
+| +--- org.apache.commons:commons-lang3:3.8.1 -> 3.12.0
+| \--- com.squareup.okhttp3:okhttp:4.10.0 -> 4.12.0
+| +--- com.squareup.okio:okio:3.6.0 -> 3.8.0
+| | \--- com.squareup.okio:okio-jvm:3.8.0
+| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.0 (*)
+| +--- com.squareup.okio:okio:3.6.0 -> 3.8.0 (*)
+| \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 2.0.0 (*)
++--- com.github.tasks:ical4android:12fe73a
+| +--- org.mnode.ical4j:ical4j:3.2.7
@ -1122,6 +1158,7 @@
+| | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava
+| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.21 -> 2.0.0 (*)
+| \--- com.google.dagger:hilt-android:2.49 -> 2.50 (*)
++--- androidx.datastore:datastore-preferences:1.1.1 (*)
++--- androidx.fragment:fragment-ktx:1.8.0
+| +--- androidx.activity:activity-ktx:1.8.1 -> 1.9.0 (*)
+| +--- androidx.collection:collection-ktx:1.1.0 -> 1.4.0 (*)

@ -72,6 +72,7 @@ androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "a
androidx-compose = { module = "androidx.compose:compose-bom", version.ref = "compose" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" }
androidx-datastore = { module = "androidx.datastore:datastore-preferences", version = "1.1.1" }
androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragment-ktx" }
androidx-hilt-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "hilt" }
androidx-hilt-work = { module = "androidx.hilt:hilt-work", version.ref = "hilt" }

@ -32,6 +32,7 @@ kotlin {
implementation(compose.material3)
implementation(compose.materialIconsExtended)
implementation(compose.runtime)
implementation(libs.androidx.datastore)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.kermit)
implementation(libs.kotlinx.datetime)

@ -1,6 +1,16 @@
package org.tasks.kmp
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import org.tasks.data.BuildConfig
import org.tasks.extensions.formatNumber
import java.util.Locale
actual fun formatNumber(number: Int) = Locale.getDefault().formatNumber(number)
actual fun formatNumber(number: Int) = Locale.getDefault().formatNumber(number)
fun createDataStore(context: Context): DataStore<Preferences> = createDataStore(
producePath = { context.filesDir.resolve(dataStoreFileName).absolutePath }
)
actual val IS_DEBUG = BuildConfig.DEBUG

@ -34,7 +34,7 @@ fun MenuPreview() {
false,
false,
NavigationDrawerSubheader.SubheaderType.PREFERENCE,
0L,
"",
),
)
),

@ -26,7 +26,7 @@ fun FilterPickerPreview() {
false,
false,
NavigationDrawerSubheader.SubheaderType.PREFERENCE,
0L,
"",
),
),
query = "",

@ -14,4 +14,8 @@
<string name="default_list">Default list</string>
<string name="help_and_feedback">Help &amp; feedback</string>
<string name="settings">Settings</string>
<string name="drawer_filters">Filters</string>
<string name="drawer_tags">Tags</string>
<string name="drawer_places">Places</string>
<string name="drawer_local_lists">Local lists</string>
</resources>

@ -1,3 +1,17 @@
package org.tasks.kmp
expect fun formatNumber(number: Int): String
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import okio.Path.Companion.toPath
expect fun formatNumber(number: Int): String
expect val IS_DEBUG: Boolean
fun createDataStore(producePath: () -> String): DataStore<Preferences> =
PreferenceDataStoreFactory.createWithPath(
produceFile = { producePath().toPath() }
)
const val dataStoreFileName = "tasks.preferences_pb"

@ -0,0 +1,27 @@
package org.tasks.compose.drawer
interface DrawerConfiguration {
val filtersEnabled: Boolean
get() = true
val placesEnabled: Boolean
get() = true
val hideUnusedPlaces: Boolean
get() = false
val tagsEnabled: Boolean
get() = true
val hideUnusedTags: Boolean
get() = false
val todayFilter: Boolean
get() = true
val recentlyModifiedFilter: Boolean
get() = true
val localListsEnabled: Boolean
get() = true
}

@ -1,10 +1,6 @@
package org.tasks.filters
import android.content.Context
import com.todoroo.astrid.core.BuiltInFilterExposer
import dagger.hilt.android.qualifiers.ApplicationContext
import org.tasks.BuildConfig
import org.tasks.R
import org.jetbrains.compose.resources.getString
import org.tasks.data.GoogleTaskFilters
import org.tasks.data.LocationFilters
import org.tasks.data.NO_ORDER
@ -14,26 +10,37 @@ import org.tasks.data.dao.FilterDao
import org.tasks.data.dao.GoogleTaskListDao
import org.tasks.data.dao.LocationDao
import org.tasks.data.dao.TagDataDao
import org.tasks.data.dao.TaskDao
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.entity.CaldavAccount.Companion.TYPE_LOCAL
import org.tasks.data.entity.CaldavAccount.Companion.TYPE_OPENTASKS
import org.tasks.data.setupLocalAccount
import org.tasks.data.toGtasksFilter
import org.tasks.filters.NavigationDrawerSubheader.SubheaderType
import org.tasks.kmp.IS_DEBUG
import org.tasks.compose.drawer.DrawerConfiguration
import org.tasks.data.toLocationFilter
import org.tasks.data.toTagFilter
import org.tasks.filters.NavigationDrawerSubheader.SubheaderType
import org.tasks.preferences.Preferences
import javax.inject.Inject
import org.tasks.preferences.TasksPreferences
import org.tasks.preferences.TasksPreferences.Companion.collapseDebug
import org.tasks.preferences.TasksPreferences.Companion.collapseFilters
import org.tasks.preferences.TasksPreferences.Companion.collapsePlaces
import org.tasks.preferences.TasksPreferences.Companion.collapseTags
import tasks.kmp.generated.resources.Res
import tasks.kmp.generated.resources.drawer_filters
import tasks.kmp.generated.resources.drawer_local_lists
import tasks.kmp.generated.resources.drawer_places
import tasks.kmp.generated.resources.drawer_tags
class FilterProvider @Inject constructor(
@param:ApplicationContext private val context: Context,
private val builtInFilterExposer: BuiltInFilterExposer,
class FilterProvider(
private val filterDao: FilterDao,
private val tagDataDao: TagDataDao,
private val googleTaskListDao: GoogleTaskListDao,
private val caldavDao: CaldavDao,
private val preferences: Preferences,
private val locationDao: LocationDao
private val configuration: DrawerConfiguration,
private val locationDao: LocationDao,
private val taskDao: TaskDao,
private val tasksPreferences: TasksPreferences,
) {
suspend fun listPickerItems(): List<FilterListItem> =
caldavFilters(showCreate = false, forceExpand = false)
@ -41,7 +48,6 @@ class FilterProvider @Inject constructor(
suspend fun drawerItems(): List<FilterListItem> =
getAllFilters(showCreate = true, hideUnused = true)
suspend fun allLists(): List<Filter> =
caldavFilters(showCreate = false, forceExpand = true)
.filterIsInstance<Filter>()
@ -56,27 +62,27 @@ class FilterProvider @Inject constructor(
suspend fun drawerCustomizationItems(): List<FilterListItem> =
getAllFilters(showBuiltIn = false, showCreate = true)
private fun getDebugFilters(): List<FilterListItem> =
if (BuildConfig.DEBUG) {
val collapsed = preferences.getBoolean(R.string.p_collapse_debug, false)
private suspend fun getDebugFilters(): List<FilterListItem> =
if (IS_DEBUG) {
val collapsed = tasksPreferences.get(collapseDebug, false)
listOf(
NavigationDrawerSubheader(
context.getString(R.string.debug),
"Debug",
false,
collapsed,
SubheaderType.PREFERENCE,
R.string.p_collapse_debug.toLong(),
collapseDebug.name,
)
)
.apply { if (collapsed) return this }
.plus(listOf(
DebugFilters.getNoListFilter(),
DebugFilters.getNoTitleFilter(),
DebugFilters.getMissingListFilter(),
DebugFilters.getMissingAccountFilter(),
DebugFilters.getNoCreateDateFilter(),
DebugFilters.getNoModificationDateFilter(),
DebugFilters.getDeleted()
DebugFilters.getNoListFilter(),
DebugFilters.getNoTitleFilter(),
DebugFilters.getMissingListFilter(),
DebugFilters.getMissingAccountFilter(),
DebugFilters.getNoCreateDateFilter(),
DebugFilters.getNoModificationDateFilter(),
DebugFilters.getDeleted()
))
} else {
@ -88,23 +94,23 @@ class FilterProvider @Inject constructor(
showBuiltIn: Boolean,
forceExpand: Boolean,
): List<FilterListItem> =
if (!preferences.getBoolean(R.string.p_filters_enabled, true)) {
if (!configuration.filtersEnabled) {
emptyList()
} else {
val collapsed = !forceExpand && preferences.getBoolean(R.string.p_collapse_filters, false)
val collapsed = !forceExpand && tasksPreferences.get(collapseFilters, false)
listOf(
NavigationDrawerSubheader(
context.getString(R.string.filters),
getString(Res.string.drawer_filters),
false,
collapsed,
SubheaderType.PREFERENCE,
R.string.p_collapse_filters.toLong(),
collapseFilters.name,
if (showCreate) REQUEST_NEW_FILTER else 0,
)
)
.apply { if (collapsed) return this }
.plusAllIf(showBuiltIn) {
builtInFilterExposer.filters()
builtInFilters()
}
.plus(filterDao.getFilters().map(::CustomFilter).sort())
}
@ -114,23 +120,23 @@ class FilterProvider @Inject constructor(
hideUnused: Boolean,
forceExpand: Boolean,
): List<FilterListItem> =
if (!preferences.getBoolean(R.string.p_tags_enabled, true)) {
if (!configuration.tagsEnabled) {
emptyList()
} else {
val collapsed = !forceExpand && preferences.getBoolean(R.string.p_collapse_tags, false)
val collapsed = !forceExpand && tasksPreferences.get(collapseTags, false)
listOf(
NavigationDrawerSubheader(
context.getString(R.string.tags),
getString(Res.string.drawer_tags),
false,
collapsed,
SubheaderType.PREFERENCE,
R.string.p_collapse_tags.toLong(),
collapseTags.name,
if (showCreate) REQUEST_NEW_TAGS else 0,
)
)
.apply { if (collapsed) return this }
.plus(tagDataDao.getTagFilters()
.filterIf(hideUnused && preferences.getBoolean(R.string.p_tags_hide_unused, false)) {
.filterIf(hideUnused && configuration.hideUnusedTags) {
it.count > 0
}
.map(TagFilters::toTagFilter)
@ -142,23 +148,23 @@ class FilterProvider @Inject constructor(
hideUnused: Boolean,
forceExpand: Boolean,
): List<FilterListItem> =
if (!preferences.getBoolean(R.string.p_places_enabled, true)) {
if (!configuration.placesEnabled) {
emptyList()
} else {
val collapsed = !forceExpand && preferences.getBoolean(R.string.p_collapse_locations, false)
val collapsed = !forceExpand && tasksPreferences.get(collapsePlaces, false)
listOf(
NavigationDrawerSubheader(
context.getString(R.string.places),
getString(Res.string.drawer_places),
false,
collapsed,
SubheaderType.PREFERENCE,
R.string.p_collapse_locations.toLong(),
collapsePlaces.name,
if (showCreate) REQUEST_NEW_PLACE else 0,
)
)
.apply { if (collapsed) return this }
.plus(locationDao.getPlaceFilters()
.filterIf(hideUnused && preferences.getBoolean(R.string.p_places_hide_unused, false)) {
.filterIf(hideUnused && configuration.hideUnusedPlaces) {
it.count > 0
}
.map(LocationFilters::toLocationFilter)
@ -182,7 +188,7 @@ class FilterProvider @Inject constructor(
.plus(addPlaces(showCreate, hideUnused, forceExpand))
.plus(caldavFilters(showCreate, forceExpand))
.toList()
.plusAllIf(BuildConfig.DEBUG) { getDebugFilters() }
.plusAllIf(IS_DEBUG) { getDebugFilters() }
private suspend fun googleTaskFilter(
account: CaldavAccount,
@ -196,7 +202,7 @@ class FilterProvider @Inject constructor(
account.error?.isNotBlank() ?: false,
collapsed,
SubheaderType.GOOGLE_TASKS,
account.id,
account.id.toString(),
if (showCreate) REQUEST_NEW_LIST else 0,
)
)
@ -215,7 +221,7 @@ class FilterProvider @Inject constructor(
): List<FilterListItem> =
caldavDao.getAccounts()
.ifEmpty { listOf(caldavDao.setupLocalAccount()) }
.filter { it.accountType != TYPE_LOCAL || preferences.getBoolean(R.string.p_lists_enabled, true) }
.filter { it.accountType != TYPE_LOCAL || configuration.localListsEnabled }
.flatMap {
if (it.isGoogleTasks) {
googleTaskFilter(it, showCreate, forceExpand)
@ -237,7 +243,7 @@ class FilterProvider @Inject constructor(
return listOf(
NavigationDrawerSubheader(
if (account.accountType == TYPE_LOCAL) {
context.getString(R.string.local_lists)
getString(Res.string.drawer_local_lists)
} else {
account.name
},
@ -247,7 +253,7 @@ class FilterProvider @Inject constructor(
account.isTasksOrg -> SubheaderType.TASKS
else -> SubheaderType.CALDAV
},
account.id,
account.id.toString(),
if (showCreate) REQUEST_NEW_LIST else 0,
)
)
@ -264,6 +270,26 @@ class FilterProvider @Inject constructor(
.sort())
}
private suspend fun builtInFilters(): List<Filter> {
val filters: MutableList<Filter> = ArrayList()
if (configuration.todayFilter) {
filters.add(TodayFilter.create())
}
if (configuration.recentlyModifiedFilter) {
filters.add(RecentlyModifiedFilter.create())
}
if (taskDao.snoozedReminders() > 0) {
filters.add(SnoozedFilter.create())
}
if (taskDao.activeTimers() > 0) {
filters.add(TimerFilter.create())
}
if (taskDao.hasNotifications() > 0) {
filters.add(NotificationsFilter.create())
}
return filters
}
companion object {
const val REQUEST_NEW_LIST = 10100
const val REQUEST_NEW_TAGS = 10101

@ -5,7 +5,7 @@ data class NavigationDrawerSubheader(
val error: Boolean,
val isCollapsed: Boolean,
val subheaderType: SubheaderType,
val id: Long,
val id: String,
val addIntentRc: Int = 0,
) : FilterListItem {
override fun areItemsTheSame(other: FilterListItem): Boolean {

@ -0,0 +1,29 @@
package org.tasks.preferences
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
class TasksPreferences(private val dataStore: DataStore<Preferences>) {
suspend fun <T> get(key: Preferences.Key<T>, defaultValue: T): T =
dataStore.data.map { it[key] }.firstOrNull() ?: defaultValue
fun <T> flow(key: Preferences.Key<T>, defaultValue: T): Flow<T> =
dataStore.data.map { it[key] ?: defaultValue }
suspend fun <T> set(key: Preferences.Key<T>, value: T) {
dataStore.edit { it[key] = value }
}
companion object {
val collapseFilters = booleanPreferencesKey("drawer_collapse_filters")
val collapseTags = booleanPreferencesKey("drawer_collapse_tags")
val collapseDebug = booleanPreferencesKey("drawer_collapse_debug")
val collapsePlaces = booleanPreferencesKey("drawer_collapse_places")
}
}

@ -1,3 +1,5 @@
package org.tasks.kmp
actual fun formatNumber(number: Int) = number.toString()
actual fun formatNumber(number: Int) = number.toString()
actual val IS_DEBUG = true
Loading…
Cancel
Save