diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index e51965ebe..c673d7faa 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -180,6 +180,7 @@ dependencies {
implementation("androidx.annotation:annotation:1.1.0")
implementation("androidx.constraintlayout:constraintlayout:2.0.0-beta4")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
+ implementation("androidx.preference:preference:1.1.0")
implementation("com.jakewharton.timber:timber:4.7.1")
implementation("com.jakewharton.threetenabp:threetenabp:1.2.1")
implementation("com.google.guava:guava:27.1-android")
diff --git a/app/licenses.yml b/app/licenses.yml
index f6e43887f..6c1f7d94a 100644
--- a/app/licenses.yml
+++ b/app/licenses.yml
@@ -829,3 +829,9 @@
license: Bouncy Castle Licence
licenseUrl: http://www.bouncycastle.org/licence.html
url: http://rtyley.github.io/spongycastle/
+- artifact: androidx.preference:preference:+
+ name: AndroidX Preference
+ copyrightHolder: Android Open Source Project
+ license: The Apache Software License, Version 2.0
+ licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
+ url: https://developer.android.com/jetpack/androidx
diff --git a/app/src/debug/res/values/keys.xml b/app/src/debug/res/values/keys.xml
index 36bf6f2dc..99967f7f4 100644
--- a/app/src/debug/res/values/keys.xml
+++ b/app/src/debug/res/values/keys.xml
@@ -1,6 +1,7 @@
Tasks Debug
+ org.tasks.debug
AEdPqrEAAAAImTf5DbfspggWrU9h06685ONycpUVwJj1JwawQQ
Strict mode - Thread
Strict mode - VM
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index dfc7007f7..f59113fc9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -574,6 +574,10 @@
android:name=".etesync.EncryptionSettingsActivity"
android:theme="@style/Tasks" />
+
+
+ val nextIntent = Intent(context, MainActivity::class.java)
+ nextIntent.putExtra(MainActivity.OPEN_FILTER, null as Filter?)
+ ProcessPhoenix.triggerRebirth(context, nextIntent)
+ }
+ .setNegativeButton(R.string.restart_later, null)
+ .show()
+ }
+
+ protected fun requires(@StringRes prefGroup: Int, check: Boolean, vararg resIds: Int) {
+ if (!check) {
+ remove(findPreference(prefGroup) as PreferenceGroup, resIds)
+ }
+ }
+
+ protected fun remove(vararg resIds: Int) {
+ remove(preferenceScreen, resIds)
+ }
+
+ private fun remove(preferenceGroup: PreferenceGroup, resIds: IntArray) {
+ for (resId in resIds) {
+ preferenceGroup.removePreference(findPreference(resId))
+ }
+ }
+
+ protected fun recreate() {
+ activity!!.recreate()
+ }
+
+ protected fun findPreference(@StringRes prefId: Int): Preference {
+ return findPreference(getString(prefId))!!
+ }
+
+ protected abstract fun inject(component: FragmentComponent)
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/tasks/preferences/BasicPreferences.java b/app/src/main/java/org/tasks/preferences/BasicPreferences.java
index e4045c92e..8daad0717 100644
--- a/app/src/main/java/org/tasks/preferences/BasicPreferences.java
+++ b/app/src/main/java/org/tasks/preferences/BasicPreferences.java
@@ -43,9 +43,7 @@ import org.tasks.activities.FilterSelectionActivity;
import org.tasks.analytics.Tracker;
import org.tasks.analytics.Tracking;
import org.tasks.analytics.Tracking.Events;
-import org.tasks.billing.BillingClient;
import org.tasks.billing.Inventory;
-import org.tasks.billing.PurchaseActivity;
import org.tasks.caldav.CaldavAccountSettingsActivity;
import org.tasks.data.CaldavAccount;
import org.tasks.data.CaldavDao;
@@ -107,7 +105,6 @@ public class BasicPreferences extends InjectingPreferenceActivity
@Inject Toaster toaster;
@Inject ActivityPermissionRequestor permissionRequestor;
@Inject GoogleAccountManager googleAccountManager;
- @Inject BillingClient billingClient;
@Inject DefaultFilterProvider defaultFilterProvider;
@Inject LocalBroadcastManager localBroadcastManager;
@Inject WorkManager workManager;
@@ -248,12 +245,6 @@ public class BasicPreferences extends InjectingPreferenceActivity
}
return true;
});
- findPreference(getString(R.string.p_collect_statistics))
- .setOnPreferenceChangeListener(
- (preference, newValue) -> {
- showRestartDialog();
- return true;
- });
findPreference(R.string.backup_BAc_import)
.setOnPreferenceClickListener(
@@ -292,45 +283,6 @@ public class BasicPreferences extends InjectingPreferenceActivity
}
});
- findPreference(R.string.contact_developer)
- .setOnPreferenceClickListener(
- preference -> {
- emailSupport();
- return false;
- });
-
- findPreference(R.string.third_party_licenses)
- .setOnPreferenceClickListener(
- preference -> {
- startActivity(new Intent(this, AttributionActivity.class));
- return false;
- });
-
- findPreference(R.string.rate_tasks)
- .setOnPreferenceClickListener(
- preference -> {
- startActivity(
- new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.market_url))));
- return false;
- });
-
- Preference upgradeToPro = findPreference(R.string.upgrade_to_pro);
- upgradeToPro.setOnPreferenceClickListener(
- p -> {
- startActivity(new Intent(this, PurchaseActivity.class));
- return false;
- });
- if (inventory.hasPro()) {
- upgradeToPro.setTitle(R.string.manage_subscription);
- upgradeToPro.setSummary(R.string.manage_subscription_summary);
- }
-
- findPreference(R.string.refresh_purchases).setOnPreferenceClickListener(
- preference -> {
- billingClient.queryPurchases();
- return false;
- });
-
findPreference(getString(R.string.p_background_sync_unmetered_only))
.setOnPreferenceChangeListener(
(preference, o) -> {
@@ -362,9 +314,6 @@ public class BasicPreferences extends InjectingPreferenceActivity
return false;
});
- findPreference(R.string.changelog)
- .setSummary(getString(R.string.version_string, BuildConfig.VERSION_NAME));
-
requires(
R.string.settings_localization,
atLeastJellybeanMR1(),
@@ -375,17 +324,6 @@ public class BasicPreferences extends InjectingPreferenceActivity
requires(BuildConfig.DEBUG, R.string.debug);
- //noinspection ConstantConditions
- if (BuildConfig.FLAVOR.equals("generic")) {
- requires(
- R.string.about,
- false,
- R.string.rate_tasks,
- R.string.upgrade_to_pro,
- R.string.refresh_purchases);
- requires(R.string.privacy, false, R.string.p_collect_statistics);
- }
-
//noinspection ConstantConditions
if (!BuildConfig.FLAVOR.equals("googleplay")) {
removeGroup(R.string.TEA_control_location);
diff --git a/app/src/main/java/org/tasks/preferences/HelpAndFeedback.kt b/app/src/main/java/org/tasks/preferences/HelpAndFeedback.kt
new file mode 100644
index 000000000..e18e54a8a
--- /dev/null
+++ b/app/src/main/java/org/tasks/preferences/HelpAndFeedback.kt
@@ -0,0 +1,81 @@
+package org.tasks.preferences
+
+import android.os.Bundle
+import androidx.appcompat.widget.Toolbar
+import androidx.core.content.ContextCompat
+import androidx.preference.Preference
+import androidx.preference.PreferenceFragmentCompat
+import org.tasks.R
+import org.tasks.databinding.ActivityPreferencesBinding
+import org.tasks.injection.ActivityComponent
+import org.tasks.injection.ThemedInjectingAppCompatActivity
+import org.tasks.preferences.fragments.HelpAndFeedback
+import org.tasks.ui.MenuColorizer
+
+private const val EXTRA_TITLE = "extra_title"
+
+class HelpAndFeedback : ThemedInjectingAppCompatActivity(),
+ PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
+
+ lateinit var toolbar: Toolbar
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val binding = ActivityPreferencesBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ toolbar = binding.toolbar.toolbar
+ if (savedInstanceState == null) {
+ supportFragmentManager
+ .beginTransaction()
+ .replace(R.id.settings, HelpAndFeedback())
+ .commit()
+ toolbar.title = getString(R.string.help_and_feedback)
+ } else {
+ toolbar.title = savedInstanceState.getCharSequence(EXTRA_TITLE)
+ }
+ supportFragmentManager.addOnBackStackChangedListener {
+ if (supportFragmentManager.backStackEntryCount == 0) {
+ toolbar.title = getString(R.string.help_and_feedback)
+ }
+ }
+ toolbar.navigationIcon = ContextCompat.getDrawable(this, R.drawable.ic_outline_arrow_back_24px);
+ toolbar.setNavigationOnClickListener { onBackPressed() }
+ MenuColorizer.colorToolbar(this, toolbar)
+ }
+
+ override fun inject(component: ActivityComponent) {
+ component.inject(this)
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putCharSequence(EXTRA_TITLE, toolbar.title)
+ }
+
+ override fun onSupportNavigateUp(): Boolean {
+ if (supportFragmentManager.popBackStackImmediate()) {
+ return true
+ }
+ return super.onSupportNavigateUp()
+ }
+
+ override fun onPreferenceStartFragment(
+ caller: PreferenceFragmentCompat,
+ pref: Preference
+ ): Boolean {
+ val args = pref.extras
+ val fragment = supportFragmentManager.fragmentFactory.instantiate(
+ classLoader,
+ pref.fragment
+ ).apply {
+ arguments = args
+ setTargetFragment(caller, 0)
+ }
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.settings, fragment)
+ .addToBackStack(null)
+ .commit()
+ toolbar.title = pref.title
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/tasks/preferences/fragments/HelpAndFeedback.kt b/app/src/main/java/org/tasks/preferences/fragments/HelpAndFeedback.kt
new file mode 100644
index 000000000..68909d113
--- /dev/null
+++ b/app/src/main/java/org/tasks/preferences/fragments/HelpAndFeedback.kt
@@ -0,0 +1,64 @@
+package org.tasks.preferences.fragments
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import org.tasks.BuildConfig
+import org.tasks.R
+import org.tasks.billing.BillingClient
+import org.tasks.billing.Inventory
+import org.tasks.injection.FragmentComponent
+import org.tasks.injection.InjectingPreferenceFragment
+import javax.inject.Inject
+
+class HelpAndFeedback : InjectingPreferenceFragment() {
+
+ @Inject lateinit var billingClient: BillingClient
+ @Inject lateinit var inventory: Inventory
+
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ setPreferencesFromResource(R.xml.help_and_feedback, rootKey)
+
+ findPreference(R.string.changelog).summary = getString(R.string.version_string, BuildConfig.VERSION_NAME)
+
+ findPreference(R.string.contact_developer)
+ .setOnPreferenceClickListener {
+ val uri = Uri.fromParts("mailto", "Alex <" + getString(R.string.support_email) + ">", null)
+ val intent = Intent(Intent.ACTION_SENDTO, uri)
+ .putExtra(Intent.EXTRA_SUBJECT, "Tasks Feedback")
+ .putExtra(Intent.EXTRA_TEXT, device.debugInfo)
+ startActivity(intent)
+ false
+ }
+
+ findPreference(R.string.refresh_purchases)
+ .setOnPreferenceClickListener {
+ billingClient.queryPurchases()
+ false
+ }
+
+ findPreference(R.string.p_collect_statistics)
+ .setOnPreferenceClickListener {
+ showRestartDialog()
+ true
+ }
+
+ if (inventory.hasPro()) {
+ val findPreference = findPreference(R.string.upgrade_to_pro)
+ findPreference.title = getString(R.string.manage_subscription)
+ findPreference.summary = getString(R.string.manage_subscription_summary)
+ }
+
+ @Suppress("ConstantConditionIf")
+ if (BuildConfig.FLAVOR == "generic") {
+ remove(R.string.p_collect_statistics,
+ R.string.rate_tasks,
+ R.string.upgrade_to_pro,
+ R.string.refresh_purchases)
+ }
+ }
+
+ override fun inject(component: FragmentComponent) {
+ component.inject(this);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/tasks/themes/CustomIcons.kt b/app/src/main/java/org/tasks/themes/CustomIcons.kt
index 135132d5f..51ed7d482 100644
--- a/app/src/main/java/org/tasks/themes/CustomIcons.kt
+++ b/app/src/main/java/org/tasks/themes/CustomIcons.kt
@@ -152,7 +152,11 @@ object CustomIcons {
1115 to R.drawable.ic_outline_scanner_24px,
1116 to R.drawable.ic_outline_router_24px,
1117 to R.drawable.ic_outline_watch_24px,
- 1118 to R.drawable.ic_outline_videogame_asset_24px
+ 1118 to R.drawable.ic_outline_videogame_asset_24px,
+ 1119 to R.drawable.ic_cached_24px,
+ 1120 to R.drawable.ic_octocat,
+ 1121 to R.drawable.ic_outline_perm_identity_24px,
+ 1122 to R.drawable.ic_track_changes_24px
)
@kotlin.jvm.JvmStatic
diff --git a/app/src/main/res/drawable/ic_cached_24px.xml b/app/src/main/res/drawable/ic_cached_24px.xml
new file mode 100644
index 000000000..1f361b4c4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cached_24px.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_octocat.xml b/app/src/main/res/drawable/ic_octocat.xml
new file mode 100644
index 000000000..863680d33
--- /dev/null
+++ b/app/src/main/res/drawable/ic_octocat.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_outline_perm_identity_24px.xml b/app/src/main/res/drawable/ic_outline_perm_identity_24px.xml
new file mode 100644
index 000000000..972af9cf1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_outline_perm_identity_24px.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_track_changes_24px.xml b/app/src/main/res/drawable/ic_track_changes_24px.xml
new file mode 100644
index 000000000..8092efc53
--- /dev/null
+++ b/app/src/main/res/drawable/ic_track_changes_24px.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_preferences.xml b/app/src/main/res/layout/activity_preferences.xml
new file mode 100644
index 000000000..a022a0822
--- /dev/null
+++ b/app/src/main/res/layout/activity_preferences.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3de05e03a..0d3cfcca3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -496,6 +496,7 @@ File %1$s contained %2$s.\n\n
Create task
List notification
Help
+ Help & feedback
Home set not found
Connection failed
Only on unmetered connections
@@ -578,4 +579,5 @@ File %1$s contained %2$s.\n\n
Requires an account with a CalDAV service provider or a self-hosted server. Find a service provider by visiting tasks.org/caldav
Requires an account with EteSync.com or a self-hosted server
Choose an encryption password. Do not forget your password, it cannot be recovered!
+ Documentation
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 8e6faf96f..962366668 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,6 +1,8 @@
-
+
diff --git a/app/src/main/res/values/theme.xml b/app/src/main/res/values/theme.xml
index 2372d2998..92fe02c9d 100644
--- a/app/src/main/res/values/theme.xml
+++ b/app/src/main/res/values/theme.xml
@@ -30,6 +30,7 @@
- ?attr/colorPrimary
- ?attr/colorOnPrimary
- 2
+ - @style/PreferenceTheme
diff --git a/app/src/main/res/xml/help_and_feedback.xml b/app/src/main/res/xml/help_and_feedback.xml
new file mode 100644
index 000000000..254a3a124
--- /dev/null
+++ b/app/src/main/res/xml/help_and_feedback.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index b78c6a375..26a81e69a 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -240,66 +240,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/release/res/values/keys.xml b/app/src/release/res/values/keys.xml
index 357b7fd04..504ddb57c 100644
--- a/app/src/release/res/values/keys.xml
+++ b/app/src/release/res/values/keys.xml
@@ -1,5 +1,6 @@
Tasks
+ org.tasks
AEdPqrEAAAAI49v5bBusi_bq1bgLBB1LIsepNV0eBrFkQrBZkw
\ No newline at end of file