mirror of https://github.com/tasks/tasks
Add theme manager, widget themes
parent
81d9b3fb3b
commit
142a9b3229
@ -0,0 +1,15 @@
|
||||
package org.tasks.widget;
|
||||
|
||||
import org.tasks.injection.ActivityComponent;
|
||||
|
||||
public class WidgetConfigActivity extends BaseWidgetConfigActivity {
|
||||
@Override
|
||||
public void inject(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initiateThemePurchase() {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.tasks.widget;
|
||||
|
||||
import org.tasks.R;
|
||||
import org.tasks.injection.ActivityComponent;
|
||||
import org.tasks.preferences.Preferences;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class WidgetConfigActivity extends BaseWidgetConfigActivity {
|
||||
|
||||
@Inject Preferences preferences;
|
||||
|
||||
@Override
|
||||
public void inject(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initiateThemePurchase() {
|
||||
preferences.setBoolean(R.string.p_purchased_themes, true);
|
||||
showThemeSelection();
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package org.tasks.widget;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import org.tasks.R;
|
||||
import org.tasks.billing.PurchaseHelper;
|
||||
import org.tasks.billing.PurchaseHelperCallback;
|
||||
import org.tasks.injection.ActivityComponent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class WidgetConfigActivity extends BaseWidgetConfigActivity implements PurchaseHelperCallback {
|
||||
|
||||
private static final int REQUEST_PURCHASE = 10109;
|
||||
|
||||
@Inject PurchaseHelper purchaseHelper;
|
||||
|
||||
@Override
|
||||
public void initiateThemePurchase() {
|
||||
purchaseHelper.purchase(dialogBuilder, this, getString(R.string.sku_themes), getString(R.string.p_purchased_themes), REQUEST_PURCHASE, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void purchaseCompleted(boolean success, final String sku) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (getString(R.string.sku_themes).equals(sku)) {
|
||||
showThemeSelection();
|
||||
} else {
|
||||
Timber.d("Unhandled sku: %s", sku);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == REQUEST_PURCHASE) {
|
||||
purchaseHelper.handleActivityResult(this, requestCode, resultCode, data);
|
||||
} else {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package org.tasks.injection;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.tasks.preferences.ThemeApplicator;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public abstract class ThemedInjectingAppCompatActivity extends InjectingAppCompatActivity {
|
||||
|
||||
@Inject ThemeApplicator themeApplicator;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
themeApplicator.applyThemeAndStatusBarColor();
|
||||
}
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
package org.tasks.preferences;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ContextThemeWrapper;
|
||||
|
||||
import org.tasks.R;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop;
|
||||
|
||||
@Singleton
|
||||
public class ActivityPreferences extends Preferences {
|
||||
|
||||
private final Activity activity;
|
||||
|
||||
@Inject
|
||||
public ActivityPreferences(Activity activity, PermissionChecker permissionChecker) {
|
||||
super(activity, permissionChecker);
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public void applyThemeAndStatusBarColor() {
|
||||
applyTheme();
|
||||
applyStatusBarColor();
|
||||
}
|
||||
|
||||
public String getThemeName() {
|
||||
int themeIndex = getInt(R.string.p_theme, 0);
|
||||
String[] themeNames = activity.getResources().getStringArray(R.array.themes);
|
||||
return themeNames[themeIndex];
|
||||
}
|
||||
|
||||
public void applyTheme() {
|
||||
applyTheme(getTheme());
|
||||
}
|
||||
|
||||
public void applyDialogTheme() {
|
||||
applyTheme(getDialogTheme());
|
||||
}
|
||||
|
||||
private void applyTheme(int theme) {
|
||||
activity.setTheme(theme);
|
||||
activity.getWindow().setFormat(PixelFormat.RGBA_8888);
|
||||
}
|
||||
|
||||
private void applyStatusBarColor() {
|
||||
if (atLeastLollipop()) {
|
||||
activity.getWindow().setStatusBarColor(getPrimaryDarkColor());
|
||||
}
|
||||
}
|
||||
|
||||
public int getTheme() {
|
||||
return getTheme(getInt(R.string.p_theme, -1));
|
||||
}
|
||||
|
||||
public int getDialogTheme() {
|
||||
Context contextThemeWrapper = new ContextThemeWrapper(activity, getTheme());
|
||||
TypedValue typedValue = new TypedValue();
|
||||
contextThemeWrapper.getTheme().resolveAttribute(R.attr.alertDialogTheme, typedValue, true);
|
||||
return typedValue.data;
|
||||
}
|
||||
|
||||
public int getDateTimePickerAccent() {
|
||||
Context contextThemeWrapper = new ContextThemeWrapper(activity, getTheme());
|
||||
TypedValue typedValue = new TypedValue();
|
||||
contextThemeWrapper.getTheme().resolveAttribute(R.attr.asDateTimePickerAccent, typedValue, true);
|
||||
return typedValue.data;
|
||||
}
|
||||
|
||||
public int getPrimaryDarkColor() {
|
||||
return getColorAttribute(R.attr.colorPrimaryDark);
|
||||
}
|
||||
|
||||
private int getColorAttribute(int attribute) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
activity.getTheme().resolveAttribute(attribute, typedValue, true);
|
||||
return typedValue.data;
|
||||
}
|
||||
|
||||
public int getPrimaryColor(int themeIndex) {
|
||||
Context contextThemeWrapper = new ContextThemeWrapper(activity, getTheme(themeIndex));
|
||||
TypedValue typedValue = new TypedValue();
|
||||
contextThemeWrapper.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
|
||||
return typedValue.data;
|
||||
}
|
||||
|
||||
public int getTheme(int index) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
return R.style.Black;
|
||||
case 2:
|
||||
return R.style.Red;
|
||||
case 3:
|
||||
return R.style.Pink;
|
||||
case 4:
|
||||
return R.style.Purple;
|
||||
case 5:
|
||||
return R.style.DeepPurple;
|
||||
case 6:
|
||||
return R.style.Indigo;
|
||||
case 7:
|
||||
return R.style.Blue;
|
||||
case 8:
|
||||
return R.style.LightBlue;
|
||||
case 9:
|
||||
return R.style.Cyan;
|
||||
case 10:
|
||||
return R.style.Teal;
|
||||
case 11:
|
||||
return R.style.Green;
|
||||
case 12:
|
||||
return R.style.LightGreen;
|
||||
case 13:
|
||||
return R.style.Lime;
|
||||
case 14:
|
||||
return R.style.Yellow;
|
||||
case 15:
|
||||
return R.style.Amber;
|
||||
case 16:
|
||||
return R.style.Orange;
|
||||
case 17:
|
||||
return R.style.DeepOrange;
|
||||
case 18:
|
||||
return R.style.Brown;
|
||||
case 19:
|
||||
return R.style.Grey;
|
||||
case 0:
|
||||
default:
|
||||
return R.style.BlueGrey;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package org.tasks.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import org.tasks.R;
|
||||
|
||||
public class Theme {
|
||||
private final Context context;
|
||||
private final int themeRes;
|
||||
private final int themeIndex;
|
||||
private final String name;
|
||||
|
||||
public Theme(Context context, int themeIndex, int themeRes, String name) {
|
||||
this.themeIndex = themeIndex;
|
||||
this.name = name;
|
||||
this.context = new ContextThemeWrapper(context, themeRes);
|
||||
this.themeRes = themeRes;
|
||||
}
|
||||
|
||||
public LayoutInflater getThemedLayoutInflater() {
|
||||
return (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
public boolean isDark() {
|
||||
return themeIndex == 1;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getThemeIndex() {
|
||||
return themeIndex;
|
||||
}
|
||||
|
||||
public int getPrimaryColor() {
|
||||
return resolveAttribute(R.attr.colorPrimary);
|
||||
}
|
||||
|
||||
public int getContentBackground() {
|
||||
return resolveAttribute(R.attr.asContentBackground);
|
||||
}
|
||||
|
||||
public int getPrimaryDarkColor() {
|
||||
return resolveAttribute(R.attr.colorPrimaryDark);
|
||||
}
|
||||
|
||||
public int getTextColor() {
|
||||
return resolveAttribute(R.attr.asTextColor);
|
||||
}
|
||||
|
||||
public int getDateTimePickerAccent() {
|
||||
return resolveAttribute(R.attr.asDateTimePickerAccent);
|
||||
}
|
||||
|
||||
public int getAppThemeResId() {
|
||||
return themeRes;
|
||||
}
|
||||
|
||||
public int getDialogThemeResId() {
|
||||
return resolveAttribute(R.attr.alertDialogTheme);
|
||||
}
|
||||
|
||||
private int resolveAttribute(int attribute) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
context.getTheme().resolveAttribute(attribute, typedValue, true);
|
||||
return typedValue.data;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package org.tasks.preferences;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.PixelFormat;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop;
|
||||
|
||||
public class ThemeApplicator {
|
||||
private final Activity activity;
|
||||
private final ThemeManager themeManager;
|
||||
|
||||
@Inject
|
||||
public ThemeApplicator(Activity activity, ThemeManager themeManager) {
|
||||
this.activity = activity;
|
||||
this.themeManager = themeManager;
|
||||
}
|
||||
|
||||
public void applyThemeAndStatusBarColor() {
|
||||
applyTheme();
|
||||
applyStatusBarColor();
|
||||
}
|
||||
|
||||
public void applyTheme() {
|
||||
Theme appTheme = themeManager.getAppTheme();
|
||||
applyTheme(appTheme.getAppThemeResId());
|
||||
}
|
||||
|
||||
public void applyDialogTheme() {
|
||||
Theme appTheme = themeManager.getAppTheme();
|
||||
applyTheme(appTheme.getDialogThemeResId());
|
||||
}
|
||||
|
||||
private void applyTheme(int theme) {
|
||||
activity.setTheme(theme);
|
||||
activity.getWindow().setFormat(PixelFormat.RGBA_8888);
|
||||
}
|
||||
|
||||
private void applyStatusBarColor() {
|
||||
if (atLeastLollipop()) {
|
||||
Theme appTheme = themeManager.getAppTheme();
|
||||
activity.getWindow().setStatusBarColor(appTheme.getPrimaryDarkColor());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package org.tasks.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.tasks.R;
|
||||
import org.tasks.injection.ForApplication;
|
||||
import org.tasks.widget.WidgetConfigActivity;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class ThemeManager {
|
||||
|
||||
private final Context context;
|
||||
private final Preferences preferences;
|
||||
private final String[] themeNames;
|
||||
|
||||
@Inject
|
||||
public ThemeManager(@ForApplication Context context, Preferences preferences) {
|
||||
this.context = context;
|
||||
this.preferences = preferences;
|
||||
themeNames = context.getResources().getStringArray(R.array.themes);
|
||||
}
|
||||
|
||||
public Theme getAppTheme() {
|
||||
return getTheme(preferences.getInt(R.string.p_theme, 0));
|
||||
}
|
||||
|
||||
public Theme getTheme(int themeIndex) {
|
||||
return new Theme(context, themeIndex, getStyle(themeIndex), themeNames[themeIndex]);
|
||||
}
|
||||
|
||||
public Theme getWidgetTheme(int widgetId) {
|
||||
int defaultTheme = preferences.useDarkWidgetTheme(widgetId) ? 1 : 0;
|
||||
return getTheme(preferences.getInt(WidgetConfigActivity.PREF_THEME + widgetId, defaultTheme));
|
||||
}
|
||||
|
||||
public int getDialogThemeResId() {
|
||||
return getAppTheme().getDialogThemeResId();
|
||||
}
|
||||
|
||||
private int getStyle(int index) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
return R.style.Black;
|
||||
case 2:
|
||||
return R.style.Red;
|
||||
case 3:
|
||||
return R.style.Pink;
|
||||
case 4:
|
||||
return R.style.Purple;
|
||||
case 5:
|
||||
return R.style.DeepPurple;
|
||||
case 6:
|
||||
return R.style.Indigo;
|
||||
case 7:
|
||||
return R.style.Blue;
|
||||
case 8:
|
||||
return R.style.LightBlue;
|
||||
case 9:
|
||||
return R.style.Cyan;
|
||||
case 10:
|
||||
return R.style.Teal;
|
||||
case 11:
|
||||
return R.style.Green;
|
||||
case 12:
|
||||
return R.style.LightGreen;
|
||||
case 13:
|
||||
return R.style.Lime;
|
||||
case 14:
|
||||
return R.style.Yellow;
|
||||
case 15:
|
||||
return R.style.Amber;
|
||||
case 16:
|
||||
return R.style.Orange;
|
||||
case 17:
|
||||
return R.style.DeepOrange;
|
||||
case 18:
|
||||
return R.style.Brown;
|
||||
case 19:
|
||||
return R.style.Grey;
|
||||
case 0:
|
||||
default:
|
||||
return R.style.BlueGrey;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,91 +1,113 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/filter_selection"
|
||||
style="@style/WidgetConfigRow">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/selected_filter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:textColor="?attr/asTextColor"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toLeftOf="@id/selected_filter"
|
||||
android:layout_toStartOf="@id/selected_filter"
|
||||
android:text="@string/filter"
|
||||
android:textColor="?attr/asTextColor"
|
||||
android:textSize="18sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
style="@style/WidgetConfigRow">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/opacity_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:textColor="?attr/asTextColor"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toLeftOf="@id/opacity_value"
|
||||
android:layout_toStartOf="@id/opacity_value"
|
||||
android:text="@string/opacity"
|
||||
android:textColor="?attr/asTextColor"
|
||||
android:textSize="18sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/opacity_seekbar"
|
||||
style="@style/WidgetConfigRow"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/darkTheme"
|
||||
style="@style/WidgetConfigRow.CheckBox"
|
||||
android:checked="false"
|
||||
android:text="@string/EPr_use_dark_theme" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/hideDueDate"
|
||||
style="@style/WidgetConfigRow.CheckBox"
|
||||
android:checked="false"
|
||||
android:text="@string/widget_hide_due_date" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/hideCheckboxes"
|
||||
style="@style/WidgetConfigRow.CheckBox"
|
||||
android:checked="false"
|
||||
android:text="@string/widget_hide_checkboxes" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/hideHeader"
|
||||
style="@style/WidgetConfigRow.CheckBox"
|
||||
android:checked="false"
|
||||
android:text="@string/widget_hide_header" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/filter_selection"
|
||||
style="@style/WidgetConfigRow">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/selected_filter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:textColor="?attr/asTextColor"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toLeftOf="@id/selected_filter"
|
||||
android:layout_toStartOf="@id/selected_filter"
|
||||
android:text="@string/filter"
|
||||
android:textColor="?attr/asTextColor"
|
||||
android:textSize="18sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/theme_selection"
|
||||
style="@style/WidgetConfigRow">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/selected_theme"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:textColor="?attr/asTextColor"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toLeftOf="@id/selected_theme"
|
||||
android:layout_toStartOf="@id/selected_theme"
|
||||
android:text="@string/theme"
|
||||
android:textColor="?attr/asTextColor"
|
||||
android:textSize="18sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout style="@style/WidgetConfigRow">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/opacity_value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:textColor="?attr/asTextColor"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toLeftOf="@id/opacity_value"
|
||||
android:layout_toStartOf="@id/opacity_value"
|
||||
android:text="@string/opacity"
|
||||
android:textColor="?attr/asTextColor"
|
||||
android:textSize="18sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/opacity_seekbar"
|
||||
style="@style/WidgetConfigRow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/hideDueDate"
|
||||
style="@style/WidgetConfigRow.CheckBox"
|
||||
android:checked="false"
|
||||
android:text="@string/widget_hide_due_date" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/hideCheckboxes"
|
||||
style="@style/WidgetConfigRow.CheckBox"
|
||||
android:checked="false"
|
||||
android:text="@string/widget_hide_checkboxes" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/hideHeader"
|
||||
style="@style/WidgetConfigRow.CheckBox"
|
||||
android:checked="false"
|
||||
android:text="@string/widget_hide_header" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
Loading…
Reference in New Issue