Allow user to change transparency of widgets

Closes #376
pull/538/head
Alinson S. Xavier 6 years ago
parent 5191290188
commit 3f002efb53

@ -4,9 +4,10 @@
* New bar chart showing number of repetition per week, month, quarter or year. * New bar chart showing number of repetition per week, month, quarter or year.
* Improved calculation of streaks for non-daily habits: performing habits on irregular weekdays will no longer break your streak. * Improved calculation of streaks for non-daily habits: performing habits on irregular weekdays will no longer break your streak.
* Automatically switch to dark theme, according to phone settings (Android 10). * Automatically switch to dark theme according to phone settings (Android 10).
* Yes/No buttons on notifications, instead of just "Check". * Yes/No buttons on notifications, instead of just "Check".
* More color choices. * More color choices.
* Customizable widget opacity.
* Significantly smaller backup files. * Significantly smaller backup files.
* Many internal code changes improving performance and stability. * Many internal code changes improving performance and stability.

@ -48,7 +48,7 @@ public class CheckmarkWidgetTest extends BaseViewTest
public void setUp() public void setUp()
{ {
super.setUp(); super.setUp();
setTheme(R.style.TransparentWidgetTheme); setTheme(R.style.WidgetTheme);
habit = fixtures.createShortHabit(); habit = fixtures.createShortHabit();
checkmarks = habit.getCheckmarks(); checkmarks = habit.getCheckmarks();

@ -42,7 +42,7 @@ public class FrequencyWidgetTest extends BaseViewTest
public void setUp() public void setUp()
{ {
super.setUp(); super.setUp();
setTheme(R.style.TransparentWidgetTheme); setTheme(R.style.WidgetTheme);
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
FrequencyWidget widget = new FrequencyWidget(targetContext, 0, habit); FrequencyWidget widget = new FrequencyWidget(targetContext, 0, habit);

@ -42,7 +42,7 @@ public class HistoryWidgetTest extends BaseViewTest
public void setUp() public void setUp()
{ {
super.setUp(); super.setUp();
setTheme(R.style.TransparentWidgetTheme); setTheme(R.style.WidgetTheme);
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
HistoryWidget widget = new HistoryWidget(targetContext, 0, habit); HistoryWidget widget = new HistoryWidget(targetContext, 0, habit);

@ -42,7 +42,7 @@ public class ScoreWidgetTest extends BaseViewTest
public void setUp() public void setUp()
{ {
super.setUp(); super.setUp();
setTheme(R.style.TransparentWidgetTheme); setTheme(R.style.WidgetTheme);
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
ScoreWidget widget = new ScoreWidget(targetContext, 0, habit); ScoreWidget widget = new ScoreWidget(targetContext, 0, habit);

@ -42,7 +42,7 @@ public class StreakWidgetTest extends BaseViewTest
public void setUp() public void setUp()
{ {
super.setUp(); super.setUp();
setTheme(R.style.TransparentWidgetTheme); setTheme(R.style.WidgetTheme);
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
StreakWidget widget = new StreakWidget(targetContext, 0, habit); StreakWidget widget = new StreakWidget(targetContext, 0, habit);

@ -43,7 +43,7 @@ public class CheckmarkWidgetViewTest extends BaseViewTest
public void setUp() public void setUp()
{ {
super.setUp(); super.setUp();
setTheme(R.style.TransparentWidgetTheme); setTheme(R.style.WidgetTheme);
Habit habit = fixtures.createShortHabit(); Habit habit = fixtures.createShortHabit();
view = new CheckmarkWidgetView(targetContext); view = new CheckmarkWidgetView(targetContext);

@ -26,12 +26,14 @@ import android.os.*;
import android.provider.*; import android.provider.*;
import android.support.annotation.*; import android.support.annotation.*;
import android.support.v7.preference.*; import android.support.v7.preference.*;
import android.util.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.core.preferences.*; import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.ui.*; import org.isoron.uhabits.core.ui.*;
import org.isoron.uhabits.notifications.*; import org.isoron.uhabits.notifications.*;
import org.isoron.uhabits.widgets.*;
import static android.media.RingtoneManager.*; import static android.media.RingtoneManager.*;
import static android.os.Build.VERSION.*; import static android.os.Build.VERSION.*;
@ -49,6 +51,9 @@ public class SettingsFragment extends PreferenceFragmentCompat
@Nullable @Nullable
private Preferences prefs; private Preferences prefs;
@Nullable
private WidgetUpdater widgetUpdater;
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) public void onActivityResult(int requestCode, int resultCode, Intent data)
{ {
@ -73,6 +78,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
{ {
HabitsApplication app = (HabitsApplication) appContext; HabitsApplication app = (HabitsApplication) appContext;
prefs = app.getComponent().getPreferences(); prefs = app.getComponent().getPreferences();
widgetUpdater = app.getComponent().getWidgetUpdater();
} }
setResultOnPreferenceClick("importData", RESULT_IMPORT_DATA); setResultOnPreferenceClick("importData", RESULT_IMPORT_DATA);
@ -152,6 +158,11 @@ public class SettingsFragment extends PreferenceFragmentCompat
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) String key)
{ {
if (key.equals("pref_widget_opacity") && widgetUpdater != null)
{
Log.d("SettingsFragment", "updating widgets");
widgetUpdater.updateWidgets();
}
BackupManager.dataChanged("org.isoron.uhabits"); BackupManager.dataChanged("org.isoron.uhabits");
updateSync(); updateSync();
} }

@ -23,6 +23,7 @@ import android.app.*;
import android.content.*; import android.content.*;
import android.graphics.*; import android.graphics.*;
import android.support.annotation.*; import android.support.annotation.*;
import android.util.*;
import android.view.*; import android.view.*;
import android.widget.*; import android.widget.*;
@ -201,4 +202,8 @@ public abstract class BaseWidget
view.measure(specWidth, specHeight); view.measure(specWidth, specHeight);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
} }
protected int getPreferedBackgroundAlpha() {
return prefs.getWidgetOpacity();
}
} }

@ -23,6 +23,7 @@ import android.appwidget.*;
import android.content.*; import android.content.*;
import android.os.*; import android.os.*;
import android.support.annotation.*; import android.support.annotation.*;
import android.util.*;
import android.widget.*; import android.widget.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
@ -77,9 +78,8 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
if (context == null) throw new RuntimeException("context is null"); if (context == null) throw new RuntimeException("context is null");
if (manager == null) throw new RuntimeException("manager is null"); if (manager == null) throw new RuntimeException("manager is null");
if (options == null) throw new RuntimeException("options is null"); if (options == null) throw new RuntimeException("options is null");
context.setTheme(R.style.OpaqueWidgetTheme);
updateDependencies(context); updateDependencies(context);
context.setTheme(R.style.WidgetTheme);
BaseWidget widget = getWidgetFromId(context, widgetId); BaseWidget widget = getWidgetFromId(context, widgetId);
WidgetDimensions dims = getDimensionsFromOptions(context, options); WidgetDimensions dims = getDimensionsFromOptions(context, options);
@ -124,12 +124,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
if (manager == null) throw new RuntimeException("manager is null"); if (manager == null) throw new RuntimeException("manager is null");
if (widgetIds == null) throw new RuntimeException("widgetIds is null"); if (widgetIds == null) throw new RuntimeException("widgetIds is null");
updateDependencies(context); updateDependencies(context);
context.setTheme(R.style.WidgetTheme);
if(preferences.isWidgetStackEnabled()) {
context.setTheme(R.style.OpaqueWidgetTheme);
} else {
context.setTheme(R.style.TransparentWidgetTheme);
}
new Thread(() -> new Thread(() ->
{ {
@ -183,7 +178,6 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
BaseWidget widget = getWidgetFromId(context, widgetId); BaseWidget widget = getWidgetFromId(context, widgetId);
Bundle options = manager.getAppWidgetOptions(widgetId); Bundle options = manager.getAppWidgetOptions(widgetId);
widget.setDimensions(getDimensionsFromOptions(context, options)); widget.setDimensions(getDimensionsFromOptions(context, options));
updateAppWidget(manager, widget); updateAppWidget(manager, widget);
} }
catch (RuntimeException e) catch (RuntimeException e)

@ -36,6 +36,7 @@ class CheckmarkWidget(
override fun refreshData(v: View) { override fun refreshData(v: View) {
(v as CheckmarkWidgetView).apply { (v as CheckmarkWidgetView).apply {
setBackgroundAlpha(preferedBackgroundAlpha)
setPercentage(habit.scores.todayValue.toFloat()) setPercentage(habit.scores.todayValue.toFloat())
setActiveColor(PaletteUtils.getColor(context, habit.color)) setActiveColor(PaletteUtils.getColor(context, habit.color))
setName(habit.name) setName(habit.name)

@ -38,6 +38,7 @@ class FrequencyWidget(
override fun refreshData(v: View) { override fun refreshData(v: View) {
val widgetView = v as GraphWidgetView val widgetView = v as GraphWidgetView
widgetView.setTitle(habit.name) widgetView.setTitle(habit.name)
widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
(widgetView.dataView as FrequencyChart).apply { (widgetView.dataView as FrequencyChart).apply {
setColor(PaletteUtils.getColor(context, habit.color)) setColor(PaletteUtils.getColor(context, habit.color))
setFrequency(habit.repetitions.weekdayFrequency) setFrequency(habit.repetitions.weekdayFrequency)

@ -39,6 +39,7 @@ class HistoryWidget(
override fun refreshData(view: View) { override fun refreshData(view: View) {
val widgetView = view as GraphWidgetView val widgetView = view as GraphWidgetView
widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
(widgetView.dataView as HistoryChart).apply { (widgetView.dataView as HistoryChart).apply {
setColor(PaletteUtils.getColor(context, habit.color)) setColor(PaletteUtils.getColor(context, habit.color))
setCheckmarks(habit.checkmarks.allValues) setCheckmarks(habit.checkmarks.allValues)

@ -44,6 +44,7 @@ class ScoreWidget(
} }
val widgetView = view as GraphWidgetView val widgetView = view as GraphWidgetView
widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
(widgetView.dataView as ScoreChart).apply { (widgetView.dataView as ScoreChart).apply {
setIsTransparencyEnabled(true) setIsTransparencyEnabled(true)
setBucketSize(size) setBucketSize(size)

@ -39,6 +39,7 @@ class StreakWidget(
override fun refreshData(view: View) { override fun refreshData(view: View) {
val widgetView = view as GraphWidgetView val widgetView = view as GraphWidgetView
widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
(widgetView.dataView as StreakChart).apply { (widgetView.dataView as StreakChart).apply {
setColor(PaletteUtils.getColor(context, habit.color)) setColor(PaletteUtils.getColor(context, habit.color))
setStreaks(habit.streaks.getBest(maxStreakCount)) setStreaks(habit.streaks.getBest(maxStreakCount))

@ -75,10 +75,7 @@ public class CheckmarkWidgetView extends HabitWidgetView
text = getResources().getString(R.string.fa_check); text = getResources().getString(R.string.fa_check);
bgColor = activeColor; bgColor = activeColor;
fgColor = res.getColor(R.attr.highContrastReverseTextColor); fgColor = res.getColor(R.attr.highContrastReverseTextColor);
setShadowAlpha(0x4f); setShadowAlpha(0x4f);
rebuildBackground();
backgroundPaint.setColor(bgColor); backgroundPaint.setColor(bgColor);
frame.setBackgroundDrawable(background); frame.setBackgroundDrawable(background);
break; break;
@ -87,10 +84,7 @@ public class CheckmarkWidgetView extends HabitWidgetView
text = getResources().getString(R.string.fa_check); text = getResources().getString(R.string.fa_check);
bgColor = res.getColor(R.attr.cardBgColor); bgColor = res.getColor(R.attr.cardBgColor);
fgColor = res.getColor(R.attr.mediumContrastTextColor); fgColor = res.getColor(R.attr.mediumContrastTextColor);
setShadowAlpha(0x00); setShadowAlpha(0x00);
rebuildBackground();
break; break;
case Checkmark.UNCHECKED: case Checkmark.UNCHECKED:
@ -98,10 +92,7 @@ public class CheckmarkWidgetView extends HabitWidgetView
text = getResources().getString(R.string.fa_times); text = getResources().getString(R.string.fa_times);
bgColor = res.getColor(R.attr.cardBgColor); bgColor = res.getColor(R.attr.cardBgColor);
fgColor = res.getColor(R.attr.mediumContrastTextColor); fgColor = res.getColor(R.attr.mediumContrastTextColor);
setShadowAlpha(0x00); setShadowAlpha(0x00);
rebuildBackground();
break; break;
} }

@ -49,6 +49,8 @@ public abstract class HabitWidgetView extends FrameLayout
private StyledResources res; private StyledResources res;
private int backgroundAlpha;
public HabitWidgetView(Context context) public HabitWidgetView(Context context)
{ {
super(context); super(context);
@ -64,19 +66,23 @@ public abstract class HabitWidgetView extends FrameLayout
public void setShadowAlpha(int shadowAlpha) public void setShadowAlpha(int shadowAlpha)
{ {
this.shadowAlpha = shadowAlpha; this.shadowAlpha = shadowAlpha;
rebuildBackground();
}
public void setBackgroundAlpha(int backgroundAlpha)
{
this.backgroundAlpha = backgroundAlpha;
rebuildBackground();
} }
protected abstract protected abstract
@NonNull @NonNull
Integer getInnerLayoutId(); Integer getInnerLayoutId();
protected void rebuildBackground() public void rebuildBackground()
{ {
Context context = getContext(); Context context = getContext();
int backgroundAlpha =
(int) (255 * res.getFloat(R.attr.widgetBackgroundAlpha));
int shadowRadius = (int) dpToPixels(context, 2); int shadowRadius = (int) dpToPixels(context, 2);
int shadowOffset = (int) dpToPixels(context, 1); int shadowOffset = (int) dpToPixels(context, 1);
int shadowColor = Color.argb(shadowAlpha, 0, 0, 0); int shadowColor = Color.argb(shadowAlpha, 0, 0, 0);

@ -128,4 +128,22 @@
<string name="snooze_interval_default" translatable="false">15</string> <string name="snooze_interval_default" translatable="false">15</string>
<string name="default_count" translatable="false">100</string> <string name="default_count" translatable="false">100</string>
<string-array name="widget_opacity_entries">
<item>100%</item>
<item>80%</item>
<item>60%</item>
<item>40%</item>
<item>20%</item>
<item>0%</item>
</string-array>
<string-array name="widget_opacity_values">
<item>255</item>
<item>204</item>
<item>153</item>
<item>102</item>
<item>51</item>
<item>0</item>
</string-array>
</resources> </resources>

@ -239,5 +239,7 @@
<string name="pref_view_privacy">View privacy policy</string> <string name="pref_view_privacy">View privacy policy</string>
<string name="view_all_contributors">View all contributors…</string> <string name="view_all_contributors">View all contributors…</string>
<string name="database">Database</string> <string name="database">Database</string>
<string name="widget_opacity_title">Widget opacity</string>
<string name="widget_opacity_description">Makes widgets more transparent or more opaque in your home screen.</string>
</resources> </resources>

@ -141,7 +141,7 @@
<item name="highContrastReverseTextColor">@color/black</item> <item name="highContrastReverseTextColor">@color/black</item>
</style> </style>
<style name="TransparentWidgetTheme" parent="AppBaseThemeDark"> <style name="WidgetTheme" parent="AppBaseThemeDark">
<item name="cardBgColor">@color/grey_850</item> <item name="cardBgColor">@color/grey_850</item>
<item name="highContrastTextColor">@color/white</item> <item name="highContrastTextColor">@color/white</item>
@ -155,12 +155,6 @@
<item name="palette">@array/transparentWidgetPalette</item> <item name="palette">@array/transparentWidgetPalette</item>
<item name="widgetShadowAlpha">0</item> <item name="widgetShadowAlpha">0</item>
<item name="widgetBackgroundAlpha">0.25</item>
</style>
<style name="OpaqueWidgetTheme" parent="TransparentWidgetTheme">
<item name="widgetBackgroundAlpha">1</item>
<item name="widgetShadowAlpha">0.25</item>
</style> </style>
<style name="day_of_week_label_condensed"/> <style name="day_of_week_label_condensed"/>

@ -43,6 +43,15 @@
android:summary="@string/pure_black_description" android:summary="@string/pure_black_description"
android:title="@string/use_pure_black"/> android:title="@string/use_pure_black"/>
<ListPreference
android:entries="@array/widget_opacity_entries"
android:entryValues="@array/widget_opacity_values"
android:key="pref_widget_opacity"
android:title="@string/widget_opacity_title"
android:summary="@string/widget_opacity_description"
android:defaultValue="102"
/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory

@ -328,6 +328,11 @@ public class Preferences
storage.putInt("last_version", version); storage.putInt("last_version", version);
} }
public int getWidgetOpacity()
{
return Integer.parseInt(storage.getString("pref_widget_opacity", "102"));
}
public interface Listener public interface Listener
{ {
default void onCheckmarkSequenceChanged() default void onCheckmarkSequenceChanged()

Loading…
Cancel
Save