New theme picker dialog with live preview

pull/935/head
Alex Baker 5 years ago
parent 60cd0821b1
commit ff33d5821c

@ -56,7 +56,7 @@ public class Tasks extends InjectingApplication {
preferences.setSyncOngoing(false);
themeCache.getThemeBase(preferences.getInt(R.string.p_theme, 0)).setDefaultNightMode();
themeCache.getThemeBase().setDefaultNightMode();
localBroadcastManager.registerRefreshReceiver(new RefreshBroadcastReceiver());

@ -66,8 +66,6 @@ public class ColorPickerActivity extends InjectingAppCompatActivity
return themeCache.getColors();
case LAUNCHER:
return themeCache.getColors().subList(0, themeCache.getColors().size() - 1);
case THEMES:
return themeCache.getThemes();
case WIDGET_BACKGROUND:
return themeCache.getWidgetThemes();
default:
@ -113,7 +111,6 @@ public class ColorPickerActivity extends InjectingAppCompatActivity
}
public enum ColorPalette {
THEMES,
COLORS,
ACCENTS,
LAUNCHER,

@ -0,0 +1,126 @@
package org.tasks.dialogs
import android.app.Activity.RESULT_CANCELED
import android.app.Activity.RESULT_OK
import android.app.Dialog
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import org.tasks.R
import org.tasks.billing.Inventory
import org.tasks.injection.DialogFragmentComponent
import org.tasks.injection.InjectingDialogFragment
import org.tasks.themes.ThemeAccent
import org.tasks.themes.ThemeBase
import org.tasks.themes.ThemeCache
import org.tasks.themes.ThemeCache.EXTRA_THEME_OVERRIDE
import javax.inject.Inject
class ThemePickerDialog : InjectingDialogFragment() {
companion object {
const val EXTRA_SELECTED = "extra_selected"
fun newThemePickerDialog(target: Fragment, rc: Int, selected: Int): ThemePickerDialog {
val args = Bundle()
args.putInt(EXTRA_SELECTED, selected)
val dialog = ThemePickerDialog()
dialog.setTargetFragment(target, rc)
dialog.arguments = args
return dialog
}
}
@Inject lateinit var inventory: Inventory
@Inject lateinit var dialogBuilder: DialogBuilder
@Inject lateinit var accent: ThemeAccent
@Inject lateinit var themeCache: ThemeCache
@Inject lateinit var themeBase: ThemeBase
var adapter: ArrayAdapter<String>? = null
var dialog: AlertDialog? = null
var selected = -1
override fun inject(component: DialogFragmentComponent) = component.inject(this)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val themes = resources.getStringArray(R.array.base_theme_names)
selected = savedInstanceState?.getInt(EXTRA_SELECTED) ?: arguments!!.getInt(EXTRA_SELECTED)
adapter = object : ArrayAdapter<String>(activity!!, R.layout.simple_list_item_single_choice, themes) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view = super.getView(position, convertView, parent)
val textColor = if (inventory.hasPro() || position < 2) {
R.color.text_primary
} else {
R.color.text_tertiary
}
val text: TextView = view.findViewById(R.id.text1)
text.setTextColor(ContextCompat.getColor(context, textColor))
return view
}
}
dialog = dialogBuilder.newDialog()
.setSingleChoiceItems(adapter, arguments!!.getInt(EXTRA_SELECTED)) { _, which ->
selected = which
if (available()) {
deliverResult()
} else {
updateButton()
activity?.intent?.putExtra(EXTRA_THEME_OVERRIDE, which)
Handler().post {
themeCache.getThemeBase(which).setDefaultNightMode()
activity?.recreate()
activity?.overridePendingTransition(R.anim.fragment_fade_enter, R.anim.fragment_fade_exit);
}
}
}
.setPositiveButton(android.R.string.ok) { _, _ ->
deliverResult()
}
.show()
updateButton()
return dialog as Dialog
}
override fun onCancel(dialog: DialogInterface) {
if (available()) {
deliverResult()
} else {
targetFragment?.onActivityResult(targetRequestCode, RESULT_CANCELED, null)
}
}
private fun deliverResult() {
dialog?.dismiss()
targetFragment?.onActivityResult(targetRequestCode, RESULT_OK, Intent().putExtra(EXTRA_SELECTED, selected))
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt(EXTRA_SELECTED, selected)
}
private fun updateButton() {
val stringRes = if (available()) {
android.R.string.ok
} else {
R.string.button_subscribe
}
dialog?.getButton(AlertDialog.BUTTON_POSITIVE)?.text = getString(stringRes)
}
private fun available() = inventory.hasPro() || selected < 2
}

@ -35,8 +35,8 @@ public class ActivityModule {
@Provides
@ActivityScope
public ThemeBase getThemeBase(ThemeCache themeCache, Preferences preferences) {
return themeCache.getThemeBase(preferences.getInt(R.string.p_theme, 0));
public ThemeBase getThemeBase(ThemeCache themeCache) {
return themeCache.getThemeBase(activity.getIntent());
}
@Provides

@ -14,6 +14,7 @@ import org.tasks.dialogs.ImportTasksDialog;
import org.tasks.dialogs.RecordAudioDialog;
import org.tasks.dialogs.SeekBarDialog;
import org.tasks.dialogs.SortDialog;
import org.tasks.dialogs.ThemePickerDialog;
import org.tasks.locale.LocalePickerDialog;
import org.tasks.reminders.NotificationDialog;
import org.tasks.reminders.SnoozeDialog;
@ -58,4 +59,6 @@ public interface DialogFragmentComponent {
void inject(ImportTasksDialog importTasksDialog);
void inject(LocalePickerDialog localePickerDialog);
void inject(ThemePickerDialog themePickerDialog);
}

@ -5,12 +5,14 @@ import androidx.appcompat.app.AppCompatActivity;
import javax.inject.Inject;
import org.tasks.locale.Locale;
import org.tasks.themes.Theme;
import org.tasks.themes.ThemeCache;
import org.tasks.themes.ThemeColor;
public abstract class ThemedInjectingAppCompatActivity extends AppCompatActivity
implements InjectingActivity {
@Inject Theme theme;
@Inject ThemeCache themeCache;
@Inject protected ThemeColor themeColor;
private ActivityComponent activityComponent;

@ -10,6 +10,7 @@ import android.os.Handler
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import androidx.preference.ListPreference
import androidx.preference.Preference
import com.google.common.base.Strings
@ -24,6 +25,9 @@ import org.tasks.activities.ColorPickerActivity.ColorPalette.*
import org.tasks.activities.FilterSelectionActivity
import org.tasks.activities.TimePickerActivity
import org.tasks.billing.Inventory
import org.tasks.billing.PurchaseActivity
import org.tasks.dialogs.ThemePickerDialog
import org.tasks.dialogs.ThemePickerDialog.Companion.newThemePickerDialog
import org.tasks.gtasks.PlayServices
import org.tasks.injection.FragmentComponent
import org.tasks.injection.InjectingPreferenceFragment
@ -34,8 +38,10 @@ import org.tasks.preferences.Preferences
import org.tasks.themes.ThemeAccent
import org.tasks.themes.ThemeBase
import org.tasks.themes.ThemeCache
import org.tasks.themes.ThemeCache.EXTRA_THEME_OVERRIDE
import org.tasks.themes.ThemeColor
import org.tasks.time.DateTime
import org.tasks.ui.NavigationDrawerFragment.REQUEST_PURCHASE
import org.tasks.ui.SingleCheckedArrayAdapter
import org.tasks.ui.TimePreference
import org.tasks.ui.Toaster
@ -54,6 +60,7 @@ private const val REQUEST_AFTERNOON = 10008
private const val REQUEST_EVENING = 10009
private const val REQUEST_NIGHT = 10010
private const val FRAG_TAG_LOCALE_PICKER = "frag_tag_locale_picker"
private const val FRAG_TAG_THEME_PICKER = "frag_tag_theme_picker"
class LookAndFeel : InjectingPreferenceFragment(), Preference.OnPreferenceChangeListener {
@ -72,7 +79,6 @@ class LookAndFeel : InjectingPreferenceFragment(), Preference.OnPreferenceChange
override fun getPreferenceXml() = R.xml.preferences_look_and_feel
override fun setupPreferences(savedInstanceState: Bundle?) {
setupColorPreference(R.string.p_theme, themeBase.name, THEMES, REQUEST_THEME_PICKER)
setupColorPreference(R.string.p_theme_color, themeColor.name, COLORS, REQUEST_COLOR_PICKER)
setupColorPreference(
R.string.p_theme_accent,
@ -88,6 +94,14 @@ class LookAndFeel : InjectingPreferenceFragment(), Preference.OnPreferenceChange
true
}
val themePref = findPreference(R.string.p_theme)
themePref.summary = themeBase.name
themePref.setOnPreferenceClickListener {
newThemePickerDialog(this, REQUEST_THEME_PICKER, themeBase.index)
.show(parentFragmentManager, FRAG_TAG_THEME_PICKER)
false
}
val defaultList = findPreference(R.string.p_default_list)
val filter: Filter = defaultFilterProvider.defaultFilter
defaultList.summary = filter.listingTitle
@ -226,16 +240,38 @@ class LookAndFeel : InjectingPreferenceFragment(), Preference.OnPreferenceChange
) else 0
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_THEME_PICKER) {
if (resultCode == RESULT_OK) {
val index = data!!.getIntExtra(ColorPickerActivity.EXTRA_COLOR, 0)
private fun setBaseTheme(index: Int) {
activity?.intent?.removeExtra(EXTRA_THEME_OVERRIDE)
preferences.setInt(R.string.p_theme, index)
if (themeBase.index != index) {
Handler().post {
themeCache.getThemeBase(index).setDefaultNightMode()
recreate()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_PURCHASE) {
val index = if (inventory.hasPro()) {
data?.getIntExtra(ThemePickerDialog.EXTRA_SELECTED, themeBase.index)
?: themeBase.index
} else {
preferences.getInt(R.string.p_theme, 0)
}
setBaseTheme(index)
} else if (requestCode == REQUEST_THEME_PICKER) {
val index = data?.getIntExtra(ThemePickerDialog.EXTRA_SELECTED, themeBase.index)
?: preferences.getInt(R.string.p_theme, 0)
if (resultCode == RESULT_OK) {
if (inventory.hasPro() || index < 2) {
setBaseTheme(index)
} else {
startActivityForResult(Intent(context, PurchaseActivity::class.java), REQUEST_PURCHASE)
}
} else {
setBaseTheme(index)
}
} else if (requestCode == REQUEST_COLOR_PICKER) {
if (resultCode == RESULT_OK) {
val index = data!!.getIntExtra(ColorPickerActivity.EXTRA_COLOR, 0)

@ -4,29 +4,39 @@ import static androidx.core.content.ContextCompat.getColor;
import static com.google.common.collect.ImmutableList.copyOf;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.tasks.R;
import org.tasks.billing.Inventory;
import org.tasks.injection.ApplicationScope;
import org.tasks.injection.ForApplication;
import org.tasks.preferences.Preferences;
@ApplicationScope
public class ThemeCache {
public static final String EXTRA_THEME_OVERRIDE = "extra_theme_override";
private final List<ThemeBase> themes = new ArrayList<>();
private final List<ThemeColor> colors = new ArrayList<>();
private final List<ThemeAccent> accents = new ArrayList<>();
private final List<WidgetTheme> widgetThemes = new ArrayList<>();
private final ThemeColor untaggedColor;
private final Preferences preferences;
private final Inventory inventory;
@Inject
public ThemeCache(@ForApplication Context context) {
public ThemeCache(Preferences preferences, Inventory inventory, @ForApplication Context context) {
this.preferences = preferences;
this.inventory = inventory;
Resources resources = context.getResources();
themes.add(
@ -95,6 +105,20 @@ public class ThemeCache {
return widgetThemes.get(index);
}
public ThemeBase getThemeBase() {
return getThemeBase(null);
}
public ThemeBase getThemeBase(@Nullable Intent intent) {
int index = preferences.getInt(R.string.p_theme, 0);
if (intent != null && intent.hasExtra(EXTRA_THEME_OVERRIDE)) {
index = intent.getIntExtra(EXTRA_THEME_OVERRIDE, 0);
} else if (index > 1 && !inventory.hasPro()) {
index = 0;
}
return getThemeBase(index);
}
public ThemeBase getThemeBase(int index) {
return themes.get(index);
}
@ -115,10 +139,6 @@ public class ThemeCache {
return copyOf(accents);
}
public List<ThemeBase> getThemes() {
return copyOf(themes);
}
public List<ThemeColor> getColors() {
return copyOf(colors);
}

@ -28,7 +28,7 @@ public class SingleCheckedArrayAdapter extends ArrayAdapter<String> {
public SingleCheckedArrayAdapter(
@NonNull Context context, @NonNull List<String> items, ThemeAccent accent) {
super(context, R.layout.simple_list_item_single_choice_themed, items);
super(context, R.layout.simple_list_item_single_checkmark, items);
this.context = context;
this.accent = accent;
this.alpha =

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeightSmall"
android:paddingStart="@dimen/keyline_first"
android:paddingEnd="@dimen/keyline_first"
android:paddingLeft="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_first"
android:checkMark="@null"
android:drawableLeft="?android:attr/listChoiceIndicatorSingle"
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
android:drawableRight="@null"
android:drawableEnd="@null"
android:checked="false"
android:drawablePadding="@dimen/keyline_second"
android:gravity="center_vertical"
android:textAppearance="?attr/textAppearanceListItemSmall"/>

@ -215,6 +215,14 @@
<item>@string/TEA_ctrl_hide_section_pref</item>
</string-array>
<string-array name="base_theme_names">
<item>@string/theme_light</item>
<item>@string/theme_black</item>
<item>@string/theme_dark</item>
<item>@string/theme_wallpaper</item>
<item>@string/theme_day_night</item>
</string-array>
<string-array name="EPr_default_reminders_mode">
<item>@string/ring_once</item>
<item>@string/ring_five_times</item>

Loading…
Cancel
Save