From 0e65173a40077964374885817fe2b7cad3f17a21 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Sat, 17 Jan 2026 18:55:26 -0600 Subject: [PATCH] Prompt user to create a new list If no writable lists exist, open up create list screen --- .../astrid/activity/TaskListFragment.kt | 15 +++++++++++-- .../BaseCaldavCalendarSettingsActivity.kt | 21 +++++++++---------- .../tasks/caldav/LocalListSettingsActivity.kt | 6 ++++++ .../kotlin/org/tasks/data/dao/CaldavDao.kt | 3 +++ .../org/tasks/data/CaldavDaoExtensions.kt | 8 +++++++ 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.kt b/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.kt index 2477026ac..a4dcad7af 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.kt @@ -89,6 +89,7 @@ import org.tasks.activities.TagSettingsActivity import org.tasks.analytics.Firebase import org.tasks.billing.PurchaseActivity import org.tasks.caldav.BaseCaldavCalendarSettingsActivity +import org.tasks.caldav.LocalListSettingsActivity import org.tasks.compose.AlarmsDisabledBanner import org.tasks.compose.AppUpdatedBanner import org.tasks.compose.FilterSelectionActivity.Companion.launch @@ -201,6 +202,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL private var onClickMenu: () -> Unit = {} private lateinit var binding: FragmentTaskListBinding private var windowInsets: PaddingValues? = null + private var hasWritableList = true private val listPickerLauncher = registerForListPickerResult { val selected = taskAdapter.getSelected() lifecycleScope.launch { @@ -279,6 +281,10 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL .onEach(this::process) .launchIn(viewLifecycleOwner.lifecycleScope) + caldavDao.watchHasWritableList() + .onEach { hasWritableList = it } + .launchIn(viewLifecycleOwner.lifecycleScope) + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { if ((mainViewModel.state.value.filter as? SearchFilter)?.query?.isNotBlank() == true) { @@ -757,11 +763,16 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL } } - private fun createNewTask() { - lifecycleScope.launch { + private fun createNewTask() = lifecycleScope.launch { + if (hasWritableList) { shortcutManager.reportShortcutUsed(ShortcutManager.SHORTCUT_NEW_TASK) onTaskListItemClicked(addTask("")) firebase.addTask("fab") + } else { + Timber.e("createNewTask(): No writable list") + listSettingsRequest.launch( + Intent(activity, LocalListSettingsActivity::class.java) + ) } } diff --git a/app/src/main/java/org/tasks/caldav/BaseCaldavCalendarSettingsActivity.kt b/app/src/main/java/org/tasks/caldav/BaseCaldavCalendarSettingsActivity.kt index 89865afd6..197dc6c06 100644 --- a/app/src/main/java/org/tasks/caldav/BaseCaldavCalendarSettingsActivity.kt +++ b/app/src/main/java/org/tasks/caldav/BaseCaldavCalendarSettingsActivity.kt @@ -35,20 +35,18 @@ abstract class BaseCaldavCalendarSettingsActivity : BaseListSettingsActivity() { protected var caldavCalendar: CaldavCalendar? = null - protected lateinit var caldavAccount: CaldavAccount + protected open val caldavAccount: CaldavAccount by lazy { + caldavCalendar?.account + ?.let { runBlocking { caldavDao.getAccountByUuid(it)!! } } + ?: intent.getParcelableExtra(EXTRA_CALDAV_ACCOUNT)!! + } override val defaultIcon = TasksIcons.LIST protected val snackbar = SnackbarHostState() // to be used by descendants override fun onCreate(savedInstanceState: Bundle?) { - val intent = intent caldavCalendar = intent.getParcelableExtra(EXTRA_CALDAV_CALENDAR) super.onCreate(savedInstanceState) - caldavAccount = if (caldavCalendar == null) { - intent.getParcelableExtra(EXTRA_CALDAV_ACCOUNT)!! - } else { - runBlocking { caldavDao.getAccountByUuid(caldavCalendar!!.account!!)!! } - } if (savedInstanceState == null) { if (caldavCalendar != null) { baseViewModel.setTitle(caldavCalendar!!.name ?: "") @@ -134,10 +132,11 @@ abstract class BaseCaldavCalendarSettingsActivity : BaseListSettingsActivity() { firebase.logEvent(R.string.event_create_list) setResult( Activity.RESULT_OK, - Intent().putExtra( - MainActivity.OPEN_FILTER, - CaldavFilter(calendar = caldavCalendar, account = caldavAccount) - ) + Intent(TaskListFragment.ACTION_RELOAD) + .putExtra( + MainActivity.OPEN_FILTER, + CaldavFilter(calendar = caldavCalendar, account = caldavAccount) + ) ) finish() } diff --git a/app/src/main/java/org/tasks/caldav/LocalListSettingsActivity.kt b/app/src/main/java/org/tasks/caldav/LocalListSettingsActivity.kt index 676aa87d3..c32b61845 100644 --- a/app/src/main/java/org/tasks/caldav/LocalListSettingsActivity.kt +++ b/app/src/main/java/org/tasks/caldav/LocalListSettingsActivity.kt @@ -10,10 +10,12 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.res.stringResource import com.todoroo.astrid.activity.MainActivity import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.runBlocking import org.tasks.R import org.tasks.compose.DeleteButton import org.tasks.compose.components.AnimatedBanner import org.tasks.data.entity.CaldavAccount +import org.tasks.data.getOrCreateLocalAccount import org.tasks.data.entity.CaldavCalendar import org.tasks.preferences.Preferences import org.tasks.themes.TasksTheme @@ -24,6 +26,10 @@ class LocalListSettingsActivity : BaseCaldavCalendarSettingsActivity() { @Inject lateinit var preferences: Preferences + override val caldavAccount: CaldavAccount by lazy { + runBlocking { caldavDao.getOrCreateLocalAccount() } + } + private val showLocalListBanner: Boolean get() = isNew && !preferences.getBoolean(R.string.p_local_list_banner_dismissed, false) diff --git a/data/src/commonMain/kotlin/org/tasks/data/dao/CaldavDao.kt b/data/src/commonMain/kotlin/org/tasks/data/dao/CaldavDao.kt index 04537449c..89cbf45ee 100644 --- a/data/src/commonMain/kotlin/org/tasks/data/dao/CaldavDao.kt +++ b/data/src/commonMain/kotlin/org/tasks/data/dao/CaldavDao.kt @@ -63,6 +63,9 @@ abstract class CaldavDao { @Query("SELECT EXISTS(SELECT 1 FROM caldav_accounts LIMIT 1)") abstract fun watchAccountExists(): Flow + @Query("SELECT EXISTS(SELECT 1 FROM caldav_lists WHERE cdl_access != ${CaldavCalendar.ACCESS_READ_ONLY} LIMIT 1)") + abstract fun watchHasWritableList(): Flow + @Query(""" SELECT * FROM caldav_accounts diff --git a/kmp/src/commonMain/kotlin/org/tasks/data/CaldavDaoExtensions.kt b/kmp/src/commonMain/kotlin/org/tasks/data/CaldavDaoExtensions.kt index 0b3f99ffe..97d5d3f36 100644 --- a/kmp/src/commonMain/kotlin/org/tasks/data/CaldavDaoExtensions.kt +++ b/kmp/src/commonMain/kotlin/org/tasks/data/CaldavDaoExtensions.kt @@ -22,6 +22,14 @@ suspend fun CaldavDao.getLocalList() = mutex.withLock { suspend fun CaldavDao.getLocalAccount() = getAccounts(CaldavAccount.TYPE_LOCAL).firstOrNull() ?: newLocalAccountUnsafe() +suspend fun CaldavDao.getOrCreateLocalAccount(): CaldavAccount = mutex.withLock { + getAccounts(CaldavAccount.TYPE_LOCAL).firstOrNull() + ?: CaldavAccount( + accountType = CaldavAccount.TYPE_LOCAL, + uuid = UUIDHelper.newUUID(), + ).let { it.copy(id = insert(it)) } +} + private suspend fun CaldavDao.newLocalAccountUnsafe(): CaldavAccount { val account = CaldavAccount( accountType = CaldavAccount.TYPE_LOCAL,