diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 420fcfb5a..886e3da5a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -310,6 +310,10 @@ android:name=".billing.PurchaseActivity" android:theme="@style/Tasks" /> + + diff --git a/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt b/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt index dc47895e6..f60ce93a8 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt @@ -86,7 +86,7 @@ import org.tasks.preferences.DefaultFilterProvider import org.tasks.preferences.Preferences import org.tasks.preferences.TasksPreferences import org.tasks.preferences.fragments.FRAG_TAG_IMPORT_TASKS -import org.tasks.sync.AddAccountDialog +import org.tasks.compose.accounts.Platform import org.tasks.sync.SyncAdapters import org.tasks.sync.microsoft.MicrosoftSignInViewModel import org.tasks.themes.ColorProvider @@ -277,30 +277,30 @@ class MainActivity : AppCompatActivity() { signIn = { platform -> firebase.logEvent(R.string.event_onboarding_sync, R.string.param_selection to platform) when (platform) { - AddAccountDialog.Platform.TASKS_ORG -> + Platform.TASKS_ORG -> syncLauncher.launch( Intent(this@MainActivity, SignInActivity::class.java) ) - AddAccountDialog.Platform.GOOGLE_TASKS -> + Platform.GOOGLE_TASKS -> syncLauncher.launch( Intent(this@MainActivity, GtasksLoginActivity::class.java) ) - AddAccountDialog.Platform.MICROSOFT -> + Platform.MICROSOFT -> microsoftVM.signIn(this@MainActivity) - AddAccountDialog.Platform.CALDAV -> + Platform.CALDAV -> syncLauncher.launch( Intent(this@MainActivity, CaldavAccountSettingsActivity::class.java) ) - AddAccountDialog.Platform.ETESYNC -> + Platform.ETESYNC -> syncLauncher.launch( Intent(this@MainActivity, EtebaseAccountSettingsActivity::class.java) ) - AddAccountDialog.Platform.LOCAL -> + Platform.LOCAL -> addAccountViewModel.createLocalAccount() else -> throw IllegalArgumentException() diff --git a/app/src/main/java/org/tasks/compose/AddAccountDialog.kt b/app/src/main/java/org/tasks/compose/AddAccountDialog.kt deleted file mode 100644 index de8c75250..000000000 --- a/app/src/main/java/org/tasks/compose/AddAccountDialog.kt +++ /dev/null @@ -1,95 +0,0 @@ -package org.tasks.compose - -import android.content.res.Configuration -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import org.tasks.R -import org.tasks.sync.AddAccountDialog.Platform -import org.tasks.themes.TasksTheme - -@Composable -fun AddAccountDialog( - hasTasksAccount: Boolean, - hasPro: Boolean, - selected: (Platform) -> Unit, -) { - Column(modifier = Modifier.verticalScroll(rememberScrollState())) { - if (!hasTasksAccount) { - SyncAccount( - title = R.string.tasks_org, - cost = R.string.cost_more_money, - description = R.string.tasks_org_description, - icon = R.drawable.ic_round_icon, - onClick = { selected(Platform.TASKS_ORG) } - ) - } - SyncAccount( - title = R.string.gtasks_GPr_header, - cost = if (hasPro) null else R.string.cost_free, - description = R.string.google_tasks_selection_description, - icon = R.drawable.ic_google, - onClick = { selected(Platform.GOOGLE_TASKS) } - ) - SyncAccount( - title = R.string.microsoft, - cost = if (hasPro) null else R.string.cost_free, - description = R.string.microsoft_selection_description, - icon = R.drawable.ic_microsoft_tasks, - onClick = { selected(Platform.MICROSOFT) } - ) - SyncAccount( - title = R.string.davx5, - cost = if (hasPro) null else R.string.cost_money, - description = R.string.davx5_selection_description, - icon = R.drawable.ic_davx5_icon_green_bg, - onClick = { selected(Platform.DAVX5) } - ) - SyncAccount( - title = R.string.caldav, - cost = if (hasPro) null else R.string.cost_money, - description = R.string.caldav_selection_description, - icon = R.drawable.ic_webdav_logo, - tint = MaterialTheme.colorScheme.onSurface.copy( - alpha = .8f - ), - onClick = { selected(Platform.CALDAV) } - ) - SyncAccount( - title = R.string.etesync, - cost = if (hasPro) null else R.string.cost_money, - description = R.string.etesync_selection_description, - icon = R.drawable.ic_etesync, - onClick = { selected(Platform.ETESYNC) } - ) - SyncAccount( - title = R.string.decsync, - cost = if (hasPro) null else R.string.cost_money, - description = R.string.decsync_selection_description, - icon = R.drawable.ic_decsync, - onClick = { selected(Platform.DECSYNC_CC) } - ) - } -} - -@Preview(showBackground = true, widthDp = 320) -@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, widthDp = 320) -@Composable -fun AddAccountDialogPreview() { - TasksTheme { - AddAccountDialog(hasTasksAccount = false, hasPro = false, selected = {}) - } -} - -@Preview(showBackground = true, widthDp = 320) -@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, widthDp = 320) -@Composable -fun AddAccountDialogPreviewWithPro() { - TasksTheme { - AddAccountDialog(hasTasksAccount = false, hasPro = true, selected = {}) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/compose/accounts/AddAccountActivity.kt b/app/src/main/java/org/tasks/compose/accounts/AddAccountActivity.kt new file mode 100644 index 000000000..cd87ec496 --- /dev/null +++ b/app/src/main/java/org/tasks/compose/accounts/AddAccountActivity.kt @@ -0,0 +1,122 @@ +package org.tasks.compose.accounts + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity +import dagger.hilt.android.AndroidEntryPoint +import org.tasks.R +import org.tasks.analytics.Firebase +import org.tasks.auth.SignInActivity +import org.tasks.billing.Inventory +import org.tasks.caldav.CaldavAccountSettingsActivity +import org.tasks.data.dao.CaldavDao +import org.tasks.etebase.EtebaseAccountSettingsActivity +import org.tasks.sync.microsoft.MicrosoftSignInViewModel +import org.tasks.themes.TasksTheme +import org.tasks.themes.Theme +import javax.inject.Inject + +@AndroidEntryPoint +class AddAccountActivity : ComponentActivity() { + @Inject lateinit var theme: Theme + @Inject lateinit var inventory: Inventory + @Inject lateinit var firebase: Firebase + @Inject lateinit var caldavDao: CaldavDao + + private val viewModel: AddAccountViewModel by viewModels() + private val microsoftVM: MicrosoftSignInViewModel by viewModels() + + private val syncLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == Activity.RESULT_OK) { + setResult(Activity.RESULT_OK) + finish() + } else { + result.data + ?.getStringExtra(GtasksLoginActivity.EXTRA_ERROR) + ?.let { /* ignore error, user can try again */ } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + theme.themeBase.set(this) + + setContent { + val accounts by caldavDao + .watchAccounts() + .collectAsStateWithLifecycle(initialValue = emptyList()) + var initialAccountCount by remember { mutableStateOf(null) } + var hasTasksAccount by remember { mutableStateOf(inventory.hasTasksAccount) } + LaunchedEffect(Unit) { + inventory.updateTasksAccount() + hasTasksAccount = inventory.hasTasksAccount + initialAccountCount = caldavDao.getAccounts().size + } + LaunchedEffect(accounts, initialAccountCount) { + if (initialAccountCount != null && accounts.size > initialAccountCount!!) { + setResult(Activity.RESULT_OK) + finish() + } + } + TasksTheme( + theme = theme.themeBase.index, + primary = theme.themeColor.primaryColor, + ) { + AddAccountScreen( + hasTasksAccount = hasTasksAccount, + hasPro = inventory.hasPro, + onBack = { finish() }, + signIn = { platform -> + firebase.logEvent( + R.string.event_onboarding_sync, + R.string.param_selection to platform + ) + when (platform) { + Platform.TASKS_ORG -> + syncLauncher.launch( + Intent(this, SignInActivity::class.java) + ) + Platform.GOOGLE_TASKS -> + syncLauncher.launch( + Intent(this, GtasksLoginActivity::class.java) + ) + Platform.MICROSOFT -> + microsoftVM.signIn(this) + Platform.CALDAV -> + syncLauncher.launch( + Intent(this, CaldavAccountSettingsActivity::class.java) + ) + Platform.ETESYNC -> + syncLauncher.launch( + Intent(this, EtebaseAccountSettingsActivity::class.java) + ) + Platform.LOCAL -> + viewModel.createLocalAccount() + else -> throw IllegalArgumentException() + } + }, + openUrl = { platform -> + firebase.logEvent( + R.string.event_onboarding_sync, + R.string.param_selection to platform.name + ) + viewModel.openUrl(this, platform) + }, + ) + } + } + } +} diff --git a/app/src/main/java/org/tasks/compose/accounts/AddAccountScreen.kt b/app/src/main/java/org/tasks/compose/accounts/AddAccountScreen.kt index 2ba267c73..f8b65477a 100644 --- a/app/src/main/java/org/tasks/compose/accounts/AddAccountScreen.kt +++ b/app/src/main/java/org/tasks/compose/accounts/AddAccountScreen.kt @@ -44,7 +44,6 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.tooling.preview.PreviewScreenSizes import androidx.compose.ui.unit.dp import org.tasks.R -import org.tasks.sync.AddAccountDialog.Platform import org.tasks.themes.TasksTheme @OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) diff --git a/app/src/main/java/org/tasks/compose/accounts/AddAccountViewModel.kt b/app/src/main/java/org/tasks/compose/accounts/AddAccountViewModel.kt index 9dc7ee676..9a20edea1 100644 --- a/app/src/main/java/org/tasks/compose/accounts/AddAccountViewModel.kt +++ b/app/src/main/java/org/tasks/compose/accounts/AddAccountViewModel.kt @@ -9,7 +9,6 @@ import org.tasks.R import org.tasks.data.dao.CaldavDao import org.tasks.data.newLocalAccount import org.tasks.extensions.Context.openUri -import org.tasks.sync.AddAccountDialog import javax.inject.Inject @HiltViewModel @@ -20,11 +19,11 @@ class AddAccountViewModel @Inject constructor( caldavDao.newLocalAccount() } - fun openUrl(context: Context, platform: AddAccountDialog.Platform) { + fun openUrl(context: Context, platform: Platform) { val url = when (platform) { - AddAccountDialog.Platform.DAVX5 -> R.string.url_davx5 - AddAccountDialog.Platform.DECSYNC_CC -> R.string.url_decsync - AddAccountDialog.Platform.LOCAL -> R.string.help_url_sync + Platform.DAVX5 -> R.string.url_davx5 + Platform.DECSYNC_CC -> R.string.url_decsync + Platform.LOCAL -> R.string.help_url_sync else -> return } context.openUri(context.getString(url)) diff --git a/app/src/main/java/org/tasks/compose/accounts/Platform.kt b/app/src/main/java/org/tasks/compose/accounts/Platform.kt new file mode 100644 index 000000000..52fca5ed1 --- /dev/null +++ b/app/src/main/java/org/tasks/compose/accounts/Platform.kt @@ -0,0 +1,12 @@ +package org.tasks.compose.accounts + +enum class Platform { + TASKS_ORG, + GOOGLE_TASKS, + MICROSOFT, + DAVX5, + CALDAV, + ETESYNC, + DECSYNC_CC, + LOCAL, +} diff --git a/app/src/main/java/org/tasks/preferences/fragments/MainSettingsFragment.kt b/app/src/main/java/org/tasks/preferences/fragments/MainSettingsFragment.kt index b51998860..0a103bd1b 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/MainSettingsFragment.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/MainSettingsFragment.kt @@ -4,11 +4,9 @@ import android.content.Intent import android.os.Bundle import androidx.core.content.ContextCompat import androidx.fragment.app.activityViewModels -import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.preference.Preference 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 @@ -16,19 +14,15 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.tasks.BuildConfig import org.tasks.R -import org.tasks.auth.SignInActivity import org.tasks.billing.BillingClient import org.tasks.billing.Inventory import org.tasks.billing.Purchase import org.tasks.billing.PurchaseActivity import org.tasks.caldav.BaseCaldavAccountSettingsActivity -import org.tasks.caldav.CaldavAccountSettingsActivity 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 -import org.tasks.extensions.Context.openUri import org.tasks.extensions.Context.toast import org.tasks.injection.InjectingPreferenceFragment import org.tasks.preferences.IconPreference @@ -38,11 +32,7 @@ import org.tasks.preferences.PreferencesViewModel import org.tasks.preferences.fragments.GoogleTasksAccount.Companion.newGoogleTasksAccountPreference import org.tasks.preferences.fragments.MicrosoftAccount.Companion.newMicrosoftAccountPreference import org.tasks.preferences.fragments.TasksAccount.Companion.newTasksAccountPreference -import org.tasks.sync.AddAccountDialog -import org.tasks.sync.AddAccountDialog.Companion.EXTRA_SELECTED -import org.tasks.sync.AddAccountDialog.Companion.newAccountDialog -import org.tasks.sync.AddAccountDialog.Platform -import org.tasks.sync.microsoft.MicrosoftSignInViewModel +import org.tasks.compose.accounts.AddAccountActivity import org.tasks.widget.AppWidgetManager import javax.inject.Inject @@ -56,7 +46,6 @@ class MainSettingsFragment : InjectingPreferenceFragment() { @Inject lateinit var billingClient: BillingClient private val viewModel: PreferencesViewModel by activityViewModels() - private val microsoftVM: MicrosoftSignInViewModel by viewModels() override fun getPreferenceXml() = R.xml.preferences @@ -101,45 +90,6 @@ class MainSettingsFragment : InjectingPreferenceFragment() { } else { inventory.subscription.observe(this) { refreshSubscription(it) } } - - parentFragmentManager.setFragmentResultListener( - AddAccountDialog.ADD_ACCOUNT, - this - ) { _, result -> - val platform = - result.getSerializable(EXTRA_SELECTED) as? Platform - ?: return@setFragmentResultListener - when (platform) { - Platform.TASKS_ORG -> - startActivityForResult( - Intent(requireContext(), SignInActivity::class.java), - REQUEST_TASKS_ORG - ) - Platform.GOOGLE_TASKS -> - startActivityForResult( - Intent(requireContext(), GtasksLoginActivity::class.java), - REQUEST_GOOGLE_TASKS - ) - Platform.MICROSOFT -> - microsoftVM.signIn(requireActivity()) - Platform.DAVX5 -> - context?.openUri(R.string.url_davx5) - Platform.CALDAV -> - startActivityForResult( - Intent(requireContext(), CaldavAccountSettingsActivity::class.java), - REQUEST_CALDAV_SETTINGS - ) - Platform.ETESYNC -> - startActivityForResult( - Intent(requireContext(), EtebaseAccountSettingsActivity::class.java), - REQUEST_CALDAV_SETTINGS - ) - Platform.DECSYNC_CC -> - context?.openUri(R.string.url_decsync) - - Platform.LOCAL -> {} - } - } } override fun onResume() { @@ -166,13 +116,10 @@ class MainSettingsFragment : InjectingPreferenceFragment() { } private fun addAccount(): Boolean { - lifecycleScope.launch { - newAccountDialog( - hasTasksAccount = viewModel.tasksAccount() != null, - hasPro = inventory.hasPro, - ) - .show(parentFragmentManager, FRAG_TAG_ADD_ACCOUNT) - } + startActivityForResult( + Intent(requireContext(), AddAccountActivity::class.java), + REQUEST_ADD_ACCOUNT + ) return false } @@ -294,10 +241,10 @@ class MainSettingsFragment : InjectingPreferenceFragment() { } companion object { - private const val FRAG_TAG_ADD_ACCOUNT = "frag_tag_add_account" const val REQUEST_CALDAV_SETTINGS = 10013 const val REQUEST_GOOGLE_TASKS = 10014 const val REQUEST_TASKS_ORG = 10016 + private const val REQUEST_ADD_ACCOUNT = 10017 fun PreferenceScreen.removeAt(index: Int, count: Int = 1) { repeat(count) { diff --git a/app/src/main/java/org/tasks/sync/AddAccountDialog.kt b/app/src/main/java/org/tasks/sync/AddAccountDialog.kt deleted file mode 100644 index 2f6b33d1d..000000000 --- a/app/src/main/java/org/tasks/sync/AddAccountDialog.kt +++ /dev/null @@ -1,85 +0,0 @@ -package org.tasks.sync - -import android.app.Dialog -import android.os.Bundle -import androidx.core.os.bundleOf -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.setFragmentResult -import dagger.hilt.android.AndroidEntryPoint -import org.tasks.R -import org.tasks.compose.AddAccountDialog -import org.tasks.dialogs.DialogBuilder -import org.tasks.extensions.Context.openUri -import org.tasks.preferences.Preferences -import org.tasks.themes.TasksTheme -import org.tasks.themes.Theme -import javax.inject.Inject - -@AndroidEntryPoint -class AddAccountDialog : DialogFragment() { - - @Inject lateinit var dialogBuilder: DialogBuilder - @Inject lateinit var theme: Theme - @Inject lateinit var preferences: Preferences - - private val hasTasksAccount: Boolean - get() = arguments?.getBoolean(EXTRA_HAS_TASKS_ACCOUNT) ?: false - - private val hasPro: Boolean - get() = arguments?.getBoolean(EXTRA_HAS_PRO) ?: false - - enum class Platform { - TASKS_ORG, - GOOGLE_TASKS, - MICROSOFT, - DAVX5, - CALDAV, - ETESYNC, - DECSYNC_CC, - LOCAL, - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - return dialogBuilder - .newDialog() - .setTitle(R.string.choose_synchronization_service) - .setContent { - TasksTheme( - theme = theme.themeBase.index, - primary = theme.themeColor.primaryColor, - ) { - AddAccountDialog( - hasTasksAccount = hasTasksAccount, - hasPro = hasPro, - selected = this::selected - ) - } - } - .setNeutralButton(R.string.help) { _, _ -> activity?.openUri(R.string.help_url_sync) } - .setNegativeButton(R.string.cancel, null) - .show() - } - - private fun selected(platform: Platform) { - setFragmentResult(ADD_ACCOUNT, bundleOf(EXTRA_SELECTED to platform)) - dismiss() - } - - companion object { - const val ADD_ACCOUNT = "add_account" - const val EXTRA_SELECTED = "selected" - private const val EXTRA_HAS_TASKS_ACCOUNT = "extra_has_tasks_account" - private const val EXTRA_HAS_PRO = "extra_has_pro" - - fun newAccountDialog( - hasTasksAccount: Boolean, - hasPro: Boolean, - ) = - AddAccountDialog().apply { - arguments = bundleOf( - EXTRA_HAS_TASKS_ACCOUNT to hasTasksAccount, - EXTRA_HAS_PRO to hasPro, - ) - } - } -} \ No newline at end of file