Add Tasks.org to synchronization options

pull/1208/head
Alex Baker 5 years ago
parent e10d78c712
commit a67d62f1ea

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="app_name" tools:ignore="PrivateResource">Tasks Debug</string>
<string name="tasks_caldav_url">https://caldav.tasks.org</string>
<string name="debug_strict_mode_thread">Strict mode - Thread</string>
<string name="debug_strict_mode_vm">Strict mode - VM</string>
<string name="debug_leakcanary">LeakCanary</string>

@ -0,0 +1,3 @@
package org.tasks.auth
class SignInActivity

@ -14,6 +14,11 @@
android:value="@integer/google_play_services_version"/>
<service android:name=".location.GeofenceTransitionsIntentService"/>
<activity
android:name=".auth.SignInActivity"
android:theme="@style/TranslucentDialog" />
</application>
</manifest>

@ -0,0 +1,77 @@
package org.tasks.auth
import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.lifecycle.lifecycleScope
import at.bitfire.dav4jvm.exception.HttpException
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.tasks.R
import org.tasks.analytics.Firebase
import org.tasks.billing.PurchaseDialog.Companion.FRAG_TAG_PURCHASE_DIALOG
import org.tasks.billing.PurchaseDialog.Companion.newPurchaseDialog
import org.tasks.caldav.CaldavClientProvider
import org.tasks.data.CaldavAccount
import org.tasks.gtasks.PlayServices
import org.tasks.injection.InjectingAppCompatActivity
import org.tasks.ui.Toaster
import javax.inject.Inject
@AndroidEntryPoint
class SignInActivity : InjectingAppCompatActivity() {
@Inject lateinit var toaster: Toaster
@Inject lateinit var provider: CaldavClientProvider
@Inject lateinit var playServices: PlayServices
@Inject lateinit var firebase: Firebase
val viewModel: SignInViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.observe(this, this::onSignIn, this::onError)
lifecycleScope.launch {
playServices
.getSignedInAccount()
?.let { validate(it) }
?: startActivityForResult(playServices.signInIntent, RC_SIGN_IN)
}
}
private fun onSignIn(account: CaldavAccount?) {
account?.let { toaster.longToast(getString(R.string.logged_in, it.name)) }
finish()
}
private fun onError(t: Throwable) {
if (t is HttpException && t.code == 402) {
newPurchaseDialog(true).show(supportFragmentManager, FRAG_TAG_PURCHASE_DIALOG)
} else {
firebase.reportException(t)
toaster.longToast(t.message)
finish()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == RC_SIGN_IN) {
playServices
.signInFromIntent(data)
?.let { validate(it) }
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
private fun validate(account: OauthSignIn) = lifecycleScope.launch(Dispatchers.IO) {
viewModel.validate(account.id!!, account.email!!, account.idToken!!)
}
companion object {
private const val RC_SIGN_IN = 10000
}
}

@ -0,0 +1,45 @@
package org.tasks.auth
import android.content.Context
import androidx.hilt.lifecycle.ViewModelInject
import com.todoroo.astrid.helper.UUIDHelper
import dagger.hilt.android.qualifiers.ApplicationContext
import org.tasks.R
import org.tasks.caldav.CaldavClientProvider
import org.tasks.data.CaldavAccount
import org.tasks.data.CaldavAccount.Companion.TYPE_TASKS
import org.tasks.data.CaldavDao
import org.tasks.ui.CompletableViewModel
class SignInViewModel @ViewModelInject constructor(
@ApplicationContext private val context: Context,
private val provider: CaldavClientProvider,
private val caldavDao: CaldavDao
) : CompletableViewModel<CaldavAccount?>() {
suspend fun validate(id: String, email: String, idToken: String) {
run {
val homeSet = provider
.forUrl(
"${context.getString(R.string.tasks_caldav_url)}/google_login",
token = idToken
)
.setForeground()
.homeSet(token = idToken)
val username = "google_$id"
caldavDao.getAccount(TYPE_TASKS, username)
?.apply {
error = null
caldavDao.update(this)
}
?: CaldavAccount().apply {
accountType = TYPE_TASKS
uuid = UUIDHelper.newUUID()
url = homeSet
this.username = username
name = email
caldavDao.insert(this)
}
}
}
}

@ -4,6 +4,7 @@ import android.app.Activity.RESULT_OK
import android.app.Dialog
import android.content.BroadcastReceiver
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.text.method.LinkMovementMethod
@ -229,16 +230,31 @@ class PurchaseDialog : DialogFragment(), OnPurchasesUpdated {
}
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
if (arguments?.getBoolean(EXTRA_FINISH_ACTIVITY, false) == true) {
activity?.finish()
}
}
companion object {
private const val EXTRA_PRICE = "extra_price"
private const val EXTRA_PRICE_CHANGED = "extra_price_changed"
private const val EXTRA_NAME_YOUR_PRICE = "extra_name_your_price"
const val EXTRA_FINISH_ACTIVITY = "extra_activity_rc"
@JvmStatic
val FRAG_TAG_PURCHASE_DIALOG = "frag_tag_purchase_dialog"
@JvmStatic
fun newPurchaseDialog(): PurchaseDialog {
return PurchaseDialog()
fun newPurchaseDialog() = newPurchaseDialog(false)
fun newPurchaseDialog(finishActivity: Boolean): PurchaseDialog {
val dialog = PurchaseDialog()
val args = Bundle()
args.putBoolean(EXTRA_FINISH_ACTIVITY, finishActivity)
dialog.arguments = args
return dialog
}
fun newPurchaseDialog(target: Fragment, rc: Int): PurchaseDialog {

@ -95,11 +95,27 @@ class CaldavSynchronizer @Inject constructor(
setError(account, e.message)
} catch (e: IOException) {
setError(account, e.message)
} catch (e: HttpException) {
val message = when(e.code) {
402 -> if (account.isTasksOrg) {
context.getString(if (inventory.subscription == null) {
R.string.your_subscription_expired
} else {
R.string.insufficient_subscription
})
} else {
e.message
}
in 500..599 -> e.message
else -> {
firebase.reportException(e)
e.message
}
}
setError(account, message)
} catch (e: DavException) {
setError(account, e.message)
if (e !is HttpException || e.code < 500) {
firebase.reportException(e)
}
firebase.reportException(e)
}
}

@ -215,6 +215,7 @@ class Synchronization : InjectingPreferenceFragment() {
const val REQUEST_CALDAV_SETTINGS = 10013
const val REQUEST_GOOGLE_TASKS = 10014
private const val REQUEST_ADD_ACCOUNT = 10015
const val REQUEST_TASKS_ORG = 10016
private const val FRAG_TAG_ADD_ACCOUNT = "frag_tag_add_account"
}
}

@ -14,12 +14,15 @@ import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity
import dagger.hilt.android.AndroidEntryPoint
import org.tasks.BuildConfig
import org.tasks.R
import org.tasks.auth.SignInActivity
import org.tasks.caldav.CaldavAccountSettingsActivity
import org.tasks.dialogs.DialogBuilder
import org.tasks.etesync.EteSyncAccountSettingsActivity
import org.tasks.preferences.fragments.Synchronization.Companion.REQUEST_CALDAV_SETTINGS
import org.tasks.preferences.fragments.Synchronization.Companion.REQUEST_GOOGLE_TASKS
import org.tasks.preferences.fragments.Synchronization.Companion.REQUEST_TASKS_ORG
import org.tasks.themes.DrawableUtil
import javax.inject.Inject
@ -45,7 +48,7 @@ class AddAccountDialog : DialogFragment() {
view.findViewById<TextView>(R.id.text2).text = descriptions[position]
val icon = view.findViewById<ImageView>(R.id.image_view)
icon.setImageDrawable(DrawableUtil.getWrapped(context, icons[position]))
if (position == 1) {
if (position == 2) {
icon.drawable.setTint(context.getColor(R.color.icon_tint))
}
return view
@ -56,24 +59,37 @@ class AddAccountDialog : DialogFragment() {
.setTitle(R.string.choose_synchronization_service)
.setSingleChoiceItems(adapter, -1) { dialog, which ->
when (which) {
0 -> activity?.startActivityForResult(
0 -> if (BuildConfig.FLAVOR == "generic") {
dialogBuilder
.newDialog(R.string.github_sponsor_login)
.setPositiveButton(R.string.ok, null)
.show()
} else {
activity?.startActivityForResult(
Intent(activity, SignInActivity::class.java),
REQUEST_TASKS_ORG)
}
1 -> activity?.startActivityForResult(
Intent(activity, GtasksLoginActivity::class.java),
REQUEST_GOOGLE_TASKS)
1 -> activity?.startActivityForResult(
2 -> activity?.startActivityForResult(
Intent(activity, CaldavAccountSettingsActivity::class.java),
REQUEST_CALDAV_SETTINGS)
2 -> activity?.startActivityForResult(
3 -> activity?.startActivityForResult(
Intent(activity, EteSyncAccountSettingsActivity::class.java),
REQUEST_CALDAV_SETTINGS)
3 -> activity?.startActivity(
4 -> activity?.startActivity(
Intent(ACTION_VIEW, Uri.parse("https://tasks.org/davx5")))
}
dialog.dismiss()
}
.setNeutralButton(R.string.help) { _, _ ->
activity?.startActivity(Intent(
Intent.ACTION_VIEW,
Uri.parse(context?.getString(R.string.help_url_sync))))
activity?.startActivity(
Intent(
ACTION_VIEW,
Uri.parse(context?.getString(R.string.help_url_sync))
)
)
}
.setNegativeButton(R.string.cancel, null)
.show()

@ -0,0 +1,26 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="1146dp"
android:height="1146dp"
android:viewportWidth="1146"
android:viewportHeight="1146">
<group>
<clip-path
android:pathData="M0,0l1145.72,0l0,1145.72l-1145.72,0z"/>
<path
android:pathData="M572.65,571.88m-572.51,0a572.51,572.51 0,1 1,1145.02 0a572.51,572.51 45,1 1,-1145.02 0"
android:fillColor="#2196F3"/>
<group>
<clip-path
android:pathData="M572.65,571.88m-572.51,0a572.51,572.51 0,1 1,1145.02 0a572.51,572.51 45,1 1,-1145.02 0"/>
<path
android:fillColor="#FF000000"
android:pathData="M429.5,771.89L230.23,572.61L162.61,640.23L1146.31,1623.94L1719.76,1050.49L935.33,266.06L429.5,771.89Z"
android:fillType="nonZero"
android:fillAlpha="0.15"/>
</group>
</group>
<path
android:pathData="M429.5,771.88L230.22,572.61L162.61,640.23L429.5,907.12L1002.95,333.67L935.33,266.05L429.5,771.88Z"
android:fillColor="#ffffff"
android:fillType="nonZero"/>
</vector>

@ -186,6 +186,7 @@
</string-array>
<string-array name="synchronization_services">
<item>@string/tasks_org</item>
<item>@string/gtasks_GPr_header</item>
<item>@string/caldav</item>
<item>@string/etesync</item>
@ -193,6 +194,7 @@
</string-array>
<string-array name="synchronization_services_description">
<item>@string/tasks_org_sync_description</item>
<item>@string/google_tasks_selection_description</item>
<item>@string/caldav_selection_description</item>
<item>@string/etesync_selection_description</item>
@ -200,6 +202,7 @@
</string-array>
<array name="synchronization_services_icons">
<item>@drawable/ic_round_icon</item>
<item>@drawable/ic_google</item>
<item>@drawable/ic_webdav_logo</item>
<item>@drawable/ic_etesync</item>

@ -38,6 +38,7 @@
<string name="upgrade_balance">Your remaining balance will apply to your new subscription</string>
<string name="upgrade_cancel">Cancel at any time</string>
<string name="upgrade_benefits_retained">benefits are retained until the end of your billing period</string>
<string name="github_sponsor_login">Login for Github Sponsors coming soon!</string>
<string name="p_date_shortcut_morning">date_shortcut_morning</string>
<string name="p_date_shortcut_afternoon">date_shortcut_afternoon</string>

@ -547,6 +547,7 @@ File %1$s contained %2$s.\n\n
<string name="enter_tag_name">Enter tag name</string>
<string name="create_new_tag">Create \"%s\"</string>
<string name="choose_synchronization_service">Select a platform</string>
<string name="tasks_org_sync_description">Synchronize your data with Tasks.org</string>
<string name="google_tasks_selection_description">Basic service that synchronizes with your Google account</string>
<string name="caldav_selection_description">Synchronization based on open internet standards</string>
<string name="etesync_selection_description">Open source, end-to-end encrypted synchronization</string>
@ -654,6 +655,9 @@ File %1$s contained %2$s.\n\n
<string name="delete_comment">Delete this comment?</string>
<string name="custom_filter_has_subtask">Has subtasks</string>
<string name="custom_filter_is_subtask">Is subtask</string>
<string name="logged_in">Logged in %s</string>
<string name="your_subscription_expired">Your subscription has expired. Subscribe now to resume service.</string>
<string name="insufficient_subscription">Insufficient subscription level. Please upgrade your subscription to resume service.</string>
<string name="price_per_year">$%s/year</string>
<string name="price_per_year_abbreviated">$%s/yr</string>
<string name="price_per_month">$%s/month</string>

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Tasks</string>
<string name="tasks_caldav_url">https://caldav.tasks.org</string>
</resources>

@ -252,6 +252,21 @@
+| +--- com.google.auto.value:auto-value-annotations:1.6.2 -> 1.7.2
+| \--- com.google.code.gson:gson:2.8.5 -> 2.8.6
++--- com.android.billingclient:billing:1.2.2
++--- com.google.android.gms:play-services-auth:18.1.0
+| +--- androidx.fragment:fragment:1.0.0 -> 1.2.5 (*)
+| +--- androidx.loader:loader:1.0.0 (*)
+| +--- com.google.android.gms:play-services-auth-api-phone:17.0.0
+| | +--- com.google.android.gms:play-services-base:17.0.0 -> 17.3.0 (*)
+| | +--- com.google.android.gms:play-services-basement:17.0.0 -> 17.3.0 (*)
+| | \--- com.google.android.gms:play-services-tasks:17.0.0 -> 17.1.0 (*)
+| +--- com.google.android.gms:play-services-auth-base:17.0.0
+| | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
+| | +--- com.google.android.gms:play-services-base:17.0.0 -> 17.3.0 (*)
+| | +--- com.google.android.gms:play-services-basement:17.0.0 -> 17.3.0 (*)
+| | \--- com.google.android.gms:play-services-tasks:17.0.0 -> 17.1.0 (*)
+| +--- com.google.android.gms:play-services-base:17.1.0 -> 17.3.0 (*)
+| +--- com.google.android.gms:play-services-basement:17.1.1 -> 17.3.0 (*)
+| \--- com.google.android.gms:play-services-tasks:17.0.0 -> 17.1.0 (*)
++--- com.gitlab.bitfireAT:dav4jvm:2.1.1
+| +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.72 -> 1.4.10 (*)
+| \--- org.apache.commons:commons-lang3:3.9

Loading…
Cancel
Save