Remove livedata from data module

pull/2883/head
Alex Baker 3 weeks ago
parent ebe5e5c009
commit 0ba901be69

@ -17,6 +17,9 @@ import kotlinx.coroutines.launch
import org.tasks.R
import org.tasks.compose.ListSettingsComposables.PrincipalList
import org.tasks.compose.ShareInvite.ShareInviteDialog
import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.data.PrincipalWithAccess
import org.tasks.data.dao.PrincipalDao
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.entity.CaldavAccount.Companion.SERVER_NEXTCLOUD
import org.tasks.data.entity.CaldavAccount.Companion.SERVER_OWNCLOUD
@ -24,8 +27,6 @@ import org.tasks.data.entity.CaldavAccount.Companion.SERVER_SABREDAV
import org.tasks.data.entity.CaldavAccount.Companion.SERVER_TASKS
import org.tasks.data.entity.CaldavCalendar
import org.tasks.data.entity.CaldavCalendar.Companion.ACCESS_OWNER
import org.tasks.data.dao.PrincipalDao
import org.tasks.data.PrincipalWithAccess
import javax.inject.Inject
@AndroidEntryPoint
@ -51,14 +52,14 @@ class CaldavCalendarSettingsActivity : BaseCaldavCalendarSettingsActivity() {
}
caldavCalendar?.takeIf { it.id > 0 }?.let {
principalDao.getPrincipals(it.id).observe(this) {
findViewById<ComposeView>(R.id.people)
.apply { isVisible = it.isNotEmpty() }
.setContent {
MdcTheme {
PrincipalList(it, if (canRemovePrincipals) this::onRemove else null)
}
}
findViewById<ComposeView>(R.id.people).setContent {
MdcTheme {
val principals = principalDao.getPrincipals(it.id).collectAsStateLifecycleAware(initial = emptyList()).value
PrincipalList(
principals = principals,
onRemove = if (canRemovePrincipals) { { onRemove(it) } } else null,
)
}
}
}
if (caldavAccount.canShare && (isNew || caldavCalendar?.access == ACCESS_OWNER)) {

@ -29,6 +29,7 @@ import org.tasks.R
import org.tasks.compose.Constants.HALF_KEYLINE
import org.tasks.compose.Constants.ICON_ALPHA
import org.tasks.compose.Constants.KEYLINE_FIRST
import org.tasks.data.PrincipalWithAccess
import org.tasks.data.entity.CaldavCalendar.Companion.INVITE_ACCEPTED
import org.tasks.data.entity.CaldavCalendar.Companion.INVITE_DECLINED
import org.tasks.data.entity.CaldavCalendar.Companion.INVITE_INVALID
@ -36,7 +37,6 @@ import org.tasks.data.entity.CaldavCalendar.Companion.INVITE_NO_RESPONSE
import org.tasks.data.entity.CaldavCalendar.Companion.INVITE_UNKNOWN
import org.tasks.data.entity.Principal
import org.tasks.data.entity.PrincipalAccess
import org.tasks.data.PrincipalWithAccess
private val principals = listOf(
PrincipalWithAccess(
@ -69,6 +69,9 @@ object ListSettingsComposables {
principals: List<PrincipalWithAccess>,
onRemove: ((PrincipalWithAccess) -> Unit)?,
) {
if (principals.isEmpty()) {
return
}
Column(
modifier = Modifier
.padding(16.dp)

@ -32,9 +32,9 @@ import org.tasks.activities.PlaceSettingsActivity
import org.tasks.analytics.Firebase
import org.tasks.billing.Inventory
import org.tasks.caldav.GeoUtils.toLikeString
import org.tasks.data.PlaceUsage
import org.tasks.data.dao.LocationDao
import org.tasks.data.entity.Place
import org.tasks.data.PlaceUsage
import org.tasks.data.mapPosition
import org.tasks.databinding.ActivityLocationPickerBinding
import org.tasks.dialogs.DialogBuilder
@ -150,11 +150,9 @@ class LocationPickerActivity : AppCompatActivity(), Toolbar.OnMenuItemClickListe
override fun onLayoutChange(
v: View, l: Int, t: Int, r: Int, b: Int, ol: Int, ot: Int, or: Int, ob: Int) {
coordinatorLayout.removeOnLayoutChangeListener(this)
locationDao
.getPlaceUsage()
.observe(this@LocationPickerActivity) {
places: List<PlaceUsage> -> updatePlaces(places)
}
lifecycleScope.launch {
updatePlaces(locationDao.getPlaceUsage())
}
}
})
if (offset != 0) {

@ -10,12 +10,13 @@ import com.google.api.services.drive.DriveScopes
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.tasks.R
import org.tasks.backup.BackupConstants
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.dao.CaldavDao
import org.tasks.data.entity.CaldavAccount
import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.googleapis.InvokerFactory
import org.tasks.gtasks.GoogleAccountManager
@ -29,13 +30,14 @@ class PreferencesViewModel @Inject constructor(
private val preferences: Preferences,
invokers: InvokerFactory,
private val googleAccountManager: GoogleAccountManager,
caldavDao: CaldavDao,
private val caldavDao: CaldavDao,
) : ViewModel() {
private val driveInvoker = invokers.getDriveInvoker()
val lastBackup = MutableLiveData<Long?>()
val lastDriveBackup = MutableLiveData<Long?>()
val lastAndroidBackup = MutableLiveData<Long>()
var caldavAccounts = caldavDao.watchAccounts()
val caldavAccounts: Flow<List<CaldavAccount>>
get() = caldavDao.watchAccounts()
private fun isStale(timestamp: Long?) =
timestamp != null
@ -63,7 +65,8 @@ class PreferencesViewModel @Inject constructor(
return if (enabled) account else null
}
fun tasksAccount(): CaldavAccount? = caldavAccounts.value?.firstOrNull { it.isTasksOrg }
suspend fun tasksAccount(): CaldavAccount? =
caldavDao.getAccounts(CaldavAccount.TYPE_TASKS).firstOrNull()
fun updateDriveBackup() = viewModelScope.launch {
if (driveAccount.isNullOrBlank()) {

@ -4,20 +4,43 @@ import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import com.todoroo.astrid.service.TaskDeleter
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.tasks.R
import org.tasks.billing.BillingClient
import org.tasks.billing.PurchaseActivity
import org.tasks.data.dao.CaldavDao
import org.tasks.data.entity.CaldavAccount
import org.tasks.injection.InjectingPreferenceFragment
import javax.inject.Inject
abstract class BaseAccountPreference : InjectingPreferenceFragment() {
@Inject lateinit var billingClient: BillingClient
@Inject lateinit var caldavDao: CaldavDao
@Inject lateinit var taskDeleter: TaskDeleter
private val accountState = MutableStateFlow<CaldavAccount?>(null)
val account: CaldavAccount
get() = accountState.value ?: requireArguments().getParcelable(EXTRA_ACCOUNT)!!
override suspend fun setupPreferences(savedInstanceState: Bundle?) {
caldavDao
.watchAccount(requireArguments().getParcelable<CaldavAccount>(EXTRA_ACCOUNT)!!.id)
.onEach {
accountState.value = it
if (it != null) {
refreshUi(it)
}
}
.launchIn(lifecycleScope)
findPreference(R.string.logout).setOnPreferenceClickListener {
dialogBuilder
.newDialog()
@ -36,7 +59,11 @@ abstract class BaseAccountPreference : InjectingPreferenceFragment() {
}
}
protected abstract suspend fun removeAccount()
protected open suspend fun removeAccount() {
taskDeleter.delete(account)
}
protected abstract suspend fun refreshUi(account: CaldavAccount)
protected fun showPurchaseDialog(): Boolean {
startActivityForResult(
@ -59,7 +86,8 @@ abstract class BaseAccountPreference : InjectingPreferenceFragment() {
}
companion object {
@JvmStatic
protected val EXTRA_ACCOUNT = "extra_account"
const val REQUEST_PURCHASE = 10201
}
}

@ -4,10 +4,8 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.LiveData
import androidx.lifecycle.lifecycleScope
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity
import com.todoroo.astrid.service.TaskDeleter
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.tasks.LocalBroadcastManager
@ -15,32 +13,20 @@ import org.tasks.R
import org.tasks.billing.Inventory
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.entity.CaldavAccount.Companion.isPaymentRequired
import org.tasks.data.dao.CaldavDao
import org.tasks.preferences.IconPreference
import javax.inject.Inject
@AndroidEntryPoint
class GoogleTasksAccount : BaseAccountPreference() {
@Inject lateinit var taskDeleter: TaskDeleter
@Inject lateinit var inventory: Inventory
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
@Inject lateinit var caldavDao: CaldavDao
private lateinit var googleTaskAccountLiveData: LiveData<CaldavAccount>
val googleTaskAccount: CaldavAccount
get() = googleTaskAccountLiveData.value ?: requireArguments().getParcelable(EXTRA_ACCOUNT)!!
private val purchaseReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
lifecycleScope.launch {
googleTaskAccount.let {
if (inventory.subscription.value != null && it.error.isPaymentRequired()) {
it.error = null
caldavDao.update(it)
}
refreshUi(it)
if (inventory.subscription.value != null && account.error.isPaymentRequired()) {
caldavDao.update(account.copy(error = null))
}
}
}
@ -51,19 +37,10 @@ class GoogleTasksAccount : BaseAccountPreference() {
override suspend fun setupPreferences(savedInstanceState: Bundle?) {
super.setupPreferences(savedInstanceState)
googleTaskAccountLiveData = caldavDao.watchAccount(
arguments?.getParcelable<CaldavAccount>(EXTRA_ACCOUNT)?.id ?: 0
)
googleTaskAccountLiveData.observe(this) { refreshUi(it) }
findPreference(R.string.reinitialize_account)
.setOnPreferenceClickListener { requestLogin() }
}
override suspend fun removeAccount() {
taskDeleter.delete(googleTaskAccount)
}
override fun onResume() {
super.onResume()
localBroadcastManager.registerPurchaseReceiver(purchaseReceiver)
@ -76,10 +53,7 @@ class GoogleTasksAccount : BaseAccountPreference() {
localBroadcastManager.unregisterReceiver(purchaseReceiver)
}
private fun refreshUi(account: CaldavAccount?) {
if (account == null) {
return
}
override suspend fun refreshUi(account: CaldavAccount) {
(findPreference(R.string.sign_in_with_google) as IconPreference).apply {
if (account.error.isNullOrBlank()) {
isVisible = false
@ -116,8 +90,6 @@ class GoogleTasksAccount : BaseAccountPreference() {
}
companion object {
private const val EXTRA_ACCOUNT = "extra_account"
fun String?.isUnauthorized(): Boolean =
this?.startsWith("401 Unauthorized", ignoreCase = true) == true

@ -11,6 +11,8 @@ import androidx.preference.PreferenceScreen
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity
import com.todoroo.astrid.service.TaskDeleter
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import org.tasks.BuildConfig
import org.tasks.R
@ -21,8 +23,8 @@ import org.tasks.billing.Purchase
import org.tasks.billing.PurchaseActivity
import org.tasks.caldav.BaseCaldavAccountSettingsActivity
import org.tasks.caldav.CaldavAccountSettingsActivity
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.accountSettingsClass
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.prefIcon
import org.tasks.data.prefTitle
import org.tasks.etebase.EtebaseAccountSettingsActivity
@ -89,7 +91,11 @@ class MainSettingsFragment : InjectingPreferenceFragment() {
viewModel.lastBackup.observe(this) { updateBackupWarning() }
viewModel.lastAndroidBackup.observe(this) { updateBackupWarning() }
viewModel.lastDriveBackup.observe(this) { updateBackupWarning() }
viewModel.caldavAccounts.observe(this) { refreshAccounts() }
viewModel
.caldavAccounts
.onEach { refreshAccounts(it) }
.launchIn(lifecycleScope)
if (BuildConfig.FLAVOR == "generic") {
remove(R.string.upgrade_to_pro)
} else {
@ -141,8 +147,7 @@ class MainSettingsFragment : InjectingPreferenceFragment() {
updateWidgetVisibility()
}
private fun refreshAccounts() {
val caldavAccounts = viewModel.caldavAccounts.value ?: emptyList()
private fun refreshAccounts(caldavAccounts: List<CaldavAccount>) {
val addAccount = findPreference(R.string.add_account)
val index = preferenceScreen.indexOf(addAccount)
var current = 0
@ -165,8 +170,10 @@ class MainSettingsFragment : InjectingPreferenceFragment() {
}
private fun addAccount(): Boolean {
newAccountDialog(hasTasksAccount = viewModel.tasksAccount() != null)
.show(parentFragmentManager, FRAG_TAG_ADD_ACCOUNT)
lifecycleScope.launch {
newAccountDialog(hasTasksAccount = viewModel.tasksAccount() != null)
.show(parentFragmentManager, FRAG_TAG_ADD_ACCOUNT)
}
return false
}

@ -5,9 +5,7 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.lifecycleScope
import com.todoroo.astrid.service.TaskDeleter
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.tasks.LocalBroadcastManager
@ -15,7 +13,6 @@ import org.tasks.R
import org.tasks.billing.Inventory
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.entity.CaldavAccount.Companion.isPaymentRequired
import org.tasks.data.dao.CaldavDao
import org.tasks.preferences.IconPreference
import org.tasks.sync.microsoft.MicrosoftSignInViewModel
import javax.inject.Inject
@ -23,26 +20,16 @@ import javax.inject.Inject
@AndroidEntryPoint
class MicrosoftAccount : BaseAccountPreference() {
@Inject lateinit var taskDeleter: TaskDeleter
@Inject lateinit var inventory: Inventory
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
@Inject lateinit var caldavDao: CaldavDao
private val microsoftVM: MicrosoftSignInViewModel by viewModels()
private lateinit var microsoftAccountLiveData: LiveData<CaldavAccount>
val microsoftAccount: CaldavAccount
get() = microsoftAccountLiveData.value ?: requireArguments().getParcelable(EXTRA_ACCOUNT)!!
private val purchaseReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
lifecycleScope.launch {
microsoftAccount.let {
if (inventory.subscription.value != null && it.error.isPaymentRequired()) {
it.error = null
caldavDao.update(it)
}
refreshUi(it)
if (inventory.subscription.value != null && account.error.isPaymentRequired()) {
caldavDao.update(account.copy(error = null))
}
}
}
@ -53,19 +40,10 @@ class MicrosoftAccount : BaseAccountPreference() {
override suspend fun setupPreferences(savedInstanceState: Bundle?) {
super.setupPreferences(savedInstanceState)
microsoftAccountLiveData = caldavDao.watchAccount(
arguments?.getParcelable<CaldavAccount>(EXTRA_ACCOUNT)?.id ?: 0
)
microsoftAccountLiveData.observe(this) { refreshUi(it) }
findPreference(R.string.reinitialize_account)
.setOnPreferenceClickListener { requestLogin() }
}
override suspend fun removeAccount() {
taskDeleter.delete(microsoftAccount)
}
override fun onResume() {
super.onResume()
localBroadcastManager.registerPurchaseReceiver(purchaseReceiver)
@ -78,10 +56,7 @@ class MicrosoftAccount : BaseAccountPreference() {
localBroadcastManager.unregisterReceiver(purchaseReceiver)
}
private fun refreshUi(account: CaldavAccount?) {
if (account == null) {
return
}
override suspend fun refreshUi(account: CaldavAccount) {
(findPreference(R.string.sign_in_with_google) as IconPreference).apply {
if (account.error.isNullOrBlank()) {
isVisible = false
@ -110,7 +85,7 @@ class MicrosoftAccount : BaseAccountPreference() {
}
private fun requestLogin(): Boolean {
microsoftAccount.username?.let {
account.username?.let {
microsoftVM.signIn(requireActivity()) // should force a specific account
}
return false

@ -13,12 +13,10 @@ import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.getSystemService
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceCategory
import com.google.android.material.textfield.TextInputLayout
import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.service.TaskDeleter
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.tasks.BuildConfig
@ -28,9 +26,9 @@ import org.tasks.auth.SignInActivity
import org.tasks.auth.SignInActivity.Platform
import org.tasks.billing.Inventory
import org.tasks.billing.Purchase
import org.tasks.data.dao.CaldavDao
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.entity.CaldavAccount.Companion.isPaymentRequired
import org.tasks.data.dao.CaldavDao
import org.tasks.extensions.Context.openUri
import org.tasks.extensions.Context.toast
import org.tasks.jobs.WorkManager
@ -43,33 +41,27 @@ import javax.inject.Inject
@AndroidEntryPoint
class TasksAccount : BaseAccountPreference() {
@Inject lateinit var taskDeleter: TaskDeleter
@Inject lateinit var inventory: Inventory
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
@Inject lateinit var caldavDao: CaldavDao
@Inject lateinit var workManager: WorkManager
@Inject lateinit var locale: Locale
private val viewModel: TasksAccountViewModel by viewModels()
private lateinit var caldavAccountLiveData: LiveData<CaldavAccount>
val caldavAccount: CaldavAccount
get() = caldavAccountLiveData.value ?: requireArguments().getParcelable(EXTRA_ACCOUNT)!!
private val refreshReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
refreshUi(caldavAccount)
lifecycleScope.launch {
refreshUi(account)
}
}
}
override fun getPreferenceXml() = R.xml.preferences_tasks
private fun clearPurchaseError(purchase: Purchase?) {
if (purchase?.isTasksSubscription == true && caldavAccount.error.isPaymentRequired()) {
caldavAccount.error = null
if (purchase?.isTasksSubscription == true && account.error.isPaymentRequired()) {
lifecycleScope.launch {
caldavDao.update(caldavAccount)
caldavDao.update(account.copy(error = null))
}
}
}
@ -79,21 +71,18 @@ class TasksAccount : BaseAccountPreference() {
inventory.subscription.observe(this) { clearPurchaseError(it) }
caldavAccountLiveData = caldavDao.watchAccount(
requireArguments().getParcelable<CaldavAccount>(EXTRA_ACCOUNT)!!.id
)
if (savedInstanceState == null) {
viewModel.refreshPasswords(caldavAccount)
viewModel.refreshPasswords(account)
}
findPreference(R.string.local_lists).setOnPreferenceClickListener {
workManager.migrateLocalTasks(caldavAccount)
workManager.migrateLocalTasks(account)
context?.toast(R.string.migrating_tasks)
false
}
findPreference(R.string.generate_new_password).setOnPreferenceChangeListener { _, description ->
viewModel.requestNewPassword(caldavAccount, description as String)
viewModel.requestNewPassword(account, description as String)
false
}
@ -101,16 +90,13 @@ class TasksAccount : BaseAccountPreference() {
}
override suspend fun removeAccount() {
// try to delete session from caldav.tasks.org
taskDeleter.delete(caldavAccount)
super.removeAccount()
// TODO: try to delete session from caldav.tasks.org
inventory.updateTasksAccount()
}
override fun onResume() {
super.onResume()
caldavAccountLiveData.observe(this) { account ->
account?.let { refreshUi(it) }
}
viewModel.appPasswords.observe(this) { passwords ->
passwords?.let { refreshPasswords(passwords) }
}
@ -124,7 +110,7 @@ class TasksAccount : BaseAccountPreference() {
.setView(view)
.setPositiveButton(R.string.ok) { _, _ ->
viewModel.clearNewPassword()
viewModel.refreshPasswords(caldavAccount)
viewModel.refreshPasswords(account)
}
.setCancelable(false)
.setNeutralButton(R.string.help) { _, _ ->
@ -155,9 +141,9 @@ class TasksAccount : BaseAccountPreference() {
}
private val isGithub: Boolean
get() = caldavAccount.username?.startsWith("github") == true
get() = account.username?.startsWith("github") == true
private fun refreshUi(account: CaldavAccount) {
override suspend fun refreshUi(account: CaldavAccount) {
(findPreference(R.string.sign_in_with_google) as IconPreference).apply {
if (account.error.isNullOrBlank()) {
isVisible = false
@ -243,7 +229,7 @@ class TasksAccount : BaseAccountPreference() {
.setTitle(R.string.delete_tag_confirmation, description)
.setMessage(R.string.app_password_delete_confirmation)
.setPositiveButton(R.string.ok) { _, _ ->
viewModel.deletePassword(caldavAccount, it.id)
viewModel.deletePassword(account, it.id)
}
.setNegativeButton(R.string.cancel, null)
.show()
@ -269,8 +255,6 @@ class TasksAccount : BaseAccountPreference() {
}
companion object {
private const val EXTRA_ACCOUNT = "extra_account"
fun newTasksAccountPreference(account: CaldavAccount): Fragment {
val fragment = TasksAccount()
fragment.arguments = Bundle().apply {

@ -1,11 +1,14 @@
package org.tasks.ui
import com.todoroo.astrid.api.TagFilter
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.tasks.LocalBroadcastManager
import org.tasks.data.entity.CaldavCalendar
import org.tasks.data.dao.CaldavDao
import org.tasks.data.entity.TagData
import org.tasks.data.dao.TagDataDao
import org.tasks.data.entity.CaldavCalendar
import org.tasks.data.entity.TagData
import javax.inject.Inject
import javax.inject.Singleton
@ -38,7 +41,7 @@ class ChipListCache @Inject internal constructor(
fun getTag(tag: String?): TagFilter? = tagDatas[tag]
init {
caldavDao.subscribeToCalendars().observeForever { updated: List<CaldavCalendar> -> updateCaldavCalendars(updated) }
tagDataDao.subscribeToTags().observeForever { updated: List<TagData> -> updateTags(updated) }
caldavDao.subscribeToCalendars().onEach { updateCaldavCalendars(it) }.launchIn(GlobalScope)
tagDataDao.subscribeToTags().onEach { updateTags(it) }.launchIn(GlobalScope)
}
}

@ -50,7 +50,6 @@ android {
}
dependencies {
implementation(libs.androidx.lifecycle.livedata)
implementation(libs.androidx.room)
implementation(libs.kotlinx.serialization)
implementation(libs.timber)

@ -1,13 +1,18 @@
package org.tasks.data.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import org.tasks.data.entity.Task
import kotlinx.coroutines.flow.Flow
import org.tasks.data.CaldavFilters
import org.tasks.data.CaldavTaskContainer
import org.tasks.data.NO_ORDER
import org.tasks.data.TaskContainer
import org.tasks.data.db.DbUtils.dbchunk
import org.tasks.data.db.SuspendDbUtils.chunkedMap
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.entity.CaldavAccount.Companion.TYPE_ETESYNC
import org.tasks.data.entity.CaldavAccount.Companion.TYPE_GOOGLE_TASKS
@ -15,13 +20,8 @@ import org.tasks.data.entity.CaldavAccount.Companion.TYPE_LOCAL
import org.tasks.data.entity.CaldavAccount.Companion.TYPE_OPENTASKS
import org.tasks.data.entity.CaldavAccount.Companion.TYPE_TASKS
import org.tasks.data.entity.CaldavCalendar
import org.tasks.data.CaldavFilters
import org.tasks.data.entity.CaldavTask
import org.tasks.data.CaldavTaskContainer
import org.tasks.data.NO_ORDER
import org.tasks.data.TaskContainer
import org.tasks.data.db.DbUtils.dbchunk
import org.tasks.data.db.SuspendDbUtils.chunkedMap
import org.tasks.data.entity.Task
import org.tasks.time.DateTimeUtils2.currentTimeMillis
const val APPLE_EPOCH = 978307200000L // 1/1/2001 GMT
@ -32,7 +32,7 @@ abstract class CaldavDao {
abstract fun listCount(account: String): Int
@Query("SELECT * FROM caldav_lists")
abstract fun subscribeToCalendars(): LiveData<List<CaldavCalendar>>
abstract fun subscribeToCalendars(): Flow<List<CaldavCalendar>>
@Query("SELECT * FROM caldav_lists WHERE cdl_uuid = :uuid LIMIT 1")
abstract suspend fun getCalendarByUuid(uuid: String): CaldavCalendar?
@ -55,7 +55,7 @@ abstract class CaldavDao {
abstract suspend fun getAccount(type: Int, username: String): CaldavAccount?
@Query("SELECT * FROM caldav_accounts WHERE cda_id = :id")
abstract fun watchAccount(id: Long): LiveData<CaldavAccount>
abstract fun watchAccount(id: Long): Flow<CaldavAccount?>
@Query("""
SELECT *
@ -66,7 +66,7 @@ ORDER BY CASE cda_account_type
ELSE 1
END, UPPER(cda_name)
""")
abstract fun watchAccounts(): LiveData<List<CaldavAccount>>
abstract fun watchAccounts(): Flow<List<CaldavAccount>>
@Query("""
SELECT *

@ -1,20 +1,19 @@
package org.tasks.data.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import org.tasks.data.entity.Geofence
import org.tasks.data.Location
import org.tasks.data.LocationFilters
import org.tasks.data.MergedGeofence
import org.tasks.data.NO_ORDER
import org.tasks.data.entity.Place
import org.tasks.data.PlaceUsage
import org.tasks.data.entity.Alarm.Companion.TYPE_SNOOZE
import org.tasks.data.entity.Geofence
import org.tasks.data.entity.Place
import org.tasks.time.DateTimeUtils2.currentTimeMillis
@Dao
@ -110,7 +109,7 @@ interface LocationDao {
suspend fun getPlace(uid: String): Place?
@Query("SELECT places.*, IFNULL(COUNT(geofence_id),0) AS count FROM places LEFT OUTER JOIN geofences ON geofences.place = places.uid GROUP BY uid ORDER BY COUNT(geofence_id) DESC")
fun getPlaceUsage(): LiveData<List<PlaceUsage>>
suspend fun getPlaceUsage(): List<PlaceUsage>
@Query("SELECT * FROM places WHERE latitude LIKE :latitude AND longitude LIKE :longitude")
suspend fun findPlace(latitude: String, longitude: String): Place?

@ -1,17 +1,17 @@
package org.tasks.data.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import org.tasks.data.entity.Principal
import org.tasks.data.entity.PrincipalAccess
import kotlinx.coroutines.flow.Flow
import org.tasks.data.PrincipalWithAccess
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.entity.CaldavCalendar
import org.tasks.data.entity.Principal
import org.tasks.data.entity.PrincipalAccess
@Dao
interface PrincipalDao {
@ -72,5 +72,5 @@ WHERE list = :list
@Transaction
@Query("SELECT * FROM principal_access WHERE list = :id")
fun getPrincipals(id: Long): LiveData<List<PrincipalWithAccess>>
fun getPrincipals(id: Long): Flow<List<PrincipalWithAccess>>
}

@ -1,25 +1,25 @@
package org.tasks.data.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import org.tasks.data.entity.Task
import org.tasks.data.UUIDHelper
import kotlinx.coroutines.flow.Flow
import org.tasks.data.NO_ORDER
import org.tasks.data.entity.Tag
import org.tasks.data.entity.TagData
import org.tasks.data.TagFilters
import org.tasks.data.UUIDHelper
import org.tasks.data.db.DbUtils
import org.tasks.data.entity.Tag
import org.tasks.data.entity.TagData
import org.tasks.data.entity.Task
import org.tasks.time.DateTimeUtils2.currentTimeMillis
@Dao
abstract class TagDataDao {
@Query("SELECT * FROM tagdata")
abstract fun subscribeToTags(): LiveData<List<TagData>>
abstract fun subscribeToTags(): Flow<List<TagData>>
@Query("SELECT * FROM tagdata WHERE name = :name COLLATE NOCASE LIMIT 1")
abstract suspend fun getTagByName(name: String): TagData?

@ -7,16 +7,16 @@ import androidx.room.RawQuery
import androidx.room.Update
import androidx.room.withTransaction
import androidx.sqlite.db.SimpleSQLiteQuery
import org.tasks.data.sql.Criterion
import org.tasks.data.sql.Functions
import org.tasks.data.db.Database
import org.tasks.data.entity.Task
import org.tasks.data.UUIDHelper
import org.tasks.data.BuildConfig
import org.tasks.data.TaskContainer
import org.tasks.data.entity.Alarm
import org.tasks.data.UUIDHelper
import org.tasks.data.db.Database
import org.tasks.data.db.SuspendDbUtils.chunkedMap
import org.tasks.data.db.SuspendDbUtils.eachChunk
import org.tasks.data.entity.Alarm
import org.tasks.data.entity.Task
import org.tasks.data.sql.Criterion
import org.tasks.data.sql.Functions
import org.tasks.time.DateTimeUtils2
import timber.log.Timber
@ -149,7 +149,7 @@ FROM (
@Query("UPDATE tasks SET parent = :parent WHERE _id IN (:children) AND _id != :parent")
internal abstract suspend fun setParentInternal(parent: Long, children: List<Long>)
@Query("UPDATE tasks SET lastNotified = :timestamp WHERE _id = :id AND lastNotified != :timestamp")
@Query("UPDATE tasks SET lastNotified = :timestamp WHERE _id = :id")
abstract suspend fun setLastNotified(id: Long, timestamp: Long)
suspend fun getChildren(id: Long): List<Long> = getChildren(listOf(id))

@ -213,7 +213,6 @@
+| \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 (*)
++--- project :data
+| +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 (*)
+| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (*)
+| +--- androidx.room:room-ktx:2.6.1
+| | +--- androidx.room:room-common:2.6.1
+| | | +--- androidx.annotation:annotation:1.3.0 -> 1.7.1 (*)

@ -574,7 +574,6 @@
+| \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 (*)
++--- project :data
+| +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 (*)
+| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0 (*)
+| +--- androidx.room:room-ktx:2.6.1
+| | +--- androidx.room:room-common:2.6.1
+| | | +--- androidx.annotation:annotation:1.3.0 -> 1.7.1 (*)

Loading…
Cancel
Save