Merge branch 'feature/dark-theme' into dev

This commit is contained in:
2016-04-15 18:29:39 -04:00
101 changed files with 1299 additions and 646 deletions

View File

@@ -19,6 +19,7 @@
package org.isoron.uhabits;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
@@ -29,6 +30,7 @@ import android.view.View;
import android.widget.TextView;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.UIHelper;
public class AboutActivity extends Activity implements View.OnClickListener
{
@@ -37,13 +39,16 @@ public class AboutActivity extends Activity implements View.OnClickListener
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
UIHelper.applyCurrentTheme(this);
setContentView(R.layout.about);
if (android.os.Build.VERSION.SDK_INT >= 21)
if (android.os.Build.VERSION.SDK_INT >= 21 && !UIHelper.isNightMode())
{
int color = getResources().getColor(R.color.blue_700);
int color = UIHelper.getStyledColor(this, R.attr.aboutScreenColor);
int darkerColor = ColorHelper.mixColors(color, Color.BLACK, 0.75f);
getActionBar().setBackgroundDrawable(new ColorDrawable(color));
ActionBar actionBar = getActionBar();
if(actionBar != null) actionBar.setBackgroundDrawable(new ColorDrawable(color));
getWindow().setStatusBarColor(darkerColor);
}

View File

@@ -26,6 +26,7 @@ import android.os.Bundle;
import android.widget.Toast;
import org.isoron.uhabits.commands.Command;
import org.isoron.uhabits.helpers.UIHelper;
import java.util.LinkedList;
@@ -44,6 +45,8 @@ abstract public class BaseActivity extends Activity implements Thread.UncaughtEx
{
super.onCreate(savedInstanceState);
UIHelper.applyCurrentTheme(this);
androidExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);

View File

@@ -30,16 +30,17 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.view.Menu;
import android.view.MenuItem;
import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.fragments.ListHabitsFragment;
import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.helpers.ReminderHelper;
import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.widgets.CheckmarkWidgetProvider;
@@ -70,6 +71,7 @@ public class MainActivity extends BaseActivity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.list_habits_activity);
prefs = PreferenceManager.getDefaultSharedPreferences(this);
@@ -122,6 +124,10 @@ public class MainActivity extends BaseActivity
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.list_habits_menu, menu);
MenuItem nightModeItem = menu.findItem(R.id.action_night_mode);
nightModeItem.setChecked(UIHelper.isNightMode());
return true;
}
@@ -130,6 +136,17 @@ public class MainActivity extends BaseActivity
{
switch (item.getItemId())
{
case R.id.action_night_mode:
{
if(UIHelper.isNightMode())
UIHelper.setCurrentTheme(UIHelper.THEME_LIGHT);
else
UIHelper.setCurrentTheme(UIHelper.THEME_DARK);
refreshTheme();
return true;
}
case R.id.action_settings:
{
Intent intent = new Intent(this, SettingsActivity.class);
@@ -158,6 +175,23 @@ public class MainActivity extends BaseActivity
}
}
private void refreshTheme()
{
new Handler().postDelayed(new Runnable()
{
@Override
public void run()
{
Intent intent = new Intent(MainActivity.this, MainActivity.class);
MainActivity.this.finish();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
startActivity(intent);
}
}, 500); // Let the menu disappear first
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{

View File

@@ -23,6 +23,7 @@ import android.app.Activity;
import android.os.Bundle;
import org.isoron.uhabits.fragments.SettingsFragment;
import org.isoron.uhabits.helpers.UIHelper;
public class SettingsActivity extends Activity
{
@@ -30,6 +31,9 @@ public class SettingsActivity extends Activity
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
UIHelper.applyCurrentTheme(this);
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment())
.commit();

View File

@@ -21,10 +21,13 @@ package org.isoron.uhabits;
import android.app.ActionBar;
import android.content.ContentUris;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.models.Habit;
public class ShowHabitActivity extends BaseActivity
@@ -43,8 +46,18 @@ public class ShowHabitActivity extends BaseActivity
if(actionBar != null && getHabit() != null)
{
actionBar.setTitle(getHabit().name);
if (android.os.Build.VERSION.SDK_INT >= 21)
actionBar.setBackgroundDrawable(new ColorDrawable(getHabit().color));
if (android.os.Build.VERSION.SDK_INT >= 21 &&
UIHelper.getStyledBoolean(this, R.attr.useHabitColorAsPrimary))
{
int androidColor = ColorHelper.getColor(this, getHabit().color);
ColorDrawable drawable = new ColorDrawable(androidColor);
actionBar.setBackgroundDrawable(drawable);
int color = ColorHelper.getColor(this, habit.color);
int darkerHabitColor = ColorHelper.mixColors(color, Color.BLACK, 0.75f);
getWindow().setStatusBarColor(darkerHabitColor);
}
}
setContentView(R.layout.show_habit_activity);

View File

@@ -40,14 +40,14 @@ import com.android.colorpicker.ColorPickerSwatch;
import com.android.datetimepicker.time.RadialPickerLayout;
import com.android.datetimepicker.time.TimePickerDialog;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.helpers.UIHelper.OnSavedListener;
import org.isoron.uhabits.R;
import org.isoron.uhabits.commands.Command;
import org.isoron.uhabits.commands.CreateHabitCommand;
import org.isoron.uhabits.commands.EditHabitCommand;
import org.isoron.uhabits.dialogs.WeekdayPickerDialog;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.helpers.UIHelper.OnSavedListener;
import org.isoron.uhabits.models.Habit;
import java.util.Arrays;
@@ -138,7 +138,7 @@ public class EditHabitFragment extends DialogFragment
modifiedHabit = new Habit();
modifiedHabit.freqNum = 1;
modifiedHabit.freqDen = 1;
modifiedHabit.color = prefs.getInt("pref_default_habit_color", modifiedHabit.color);
modifiedHabit.color = prefs.getInt("pref_default_habit_palette_color", modifiedHabit.color);
}
else if (mode == EDIT_MODE)
{
@@ -174,13 +174,13 @@ public class EditHabitFragment extends DialogFragment
return view;
}
private void changeColor(Integer color)
private void changeColor(int paletteColor)
{
modifiedHabit.color = color;
tvName.setTextColor(color);
modifiedHabit.color = paletteColor;
tvName.setTextColor(ColorHelper.getColor(getActivity(), paletteColor));
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("pref_default_habit_color", color);
editor.putInt("pref_default_habit_palette_color", paletteColor);
editor.apply();
}
@@ -237,15 +237,18 @@ public class EditHabitFragment extends DialogFragment
private void onColorButtonClick()
{
int originalAndroidColor = ColorHelper.getColor(getActivity(), modifiedHabit.color);
ColorPickerDialog picker = ColorPickerDialog.newInstance(
R.string.color_picker_default_title, ColorHelper.palette, modifiedHabit.color, 4,
ColorPickerDialog.SIZE_SMALL);
R.string.color_picker_default_title, ColorHelper.getPalette(getActivity()),
originalAndroidColor, 4, ColorPickerDialog.SIZE_SMALL);
picker.setOnColorSelectedListener(new ColorPickerSwatch.OnColorSelectedListener()
{
public void onColorSelected(int color)
public void onColorSelected(int androidColor)
{
changeColor(color);
int paletteColor = ColorHelper.colorToPaletteIndex(getActivity(), androidColor);
changeColor(paletteColor);
}
});
picker.show(getFragmentManager(), "picker");

View File

@@ -24,11 +24,9 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.helpers.ListHabitsHelper;
import org.isoron.uhabits.loaders.HabitListLoader;
import org.isoron.uhabits.models.Habit;
@@ -74,28 +72,15 @@ class HabitListAdapter extends BaseAdapter
public View getView(int position, View view, ViewGroup parent)
{
final Habit habit = loader.habitsList.get(position);
boolean selected = selectedPositions.contains(position);
if (view == null || (Long) view.getTag(R.id.timestamp_key) != DateHelper.getStartOfToday())
{
view = inflater.inflate(R.layout.list_habits_item, null);
helper.initializeLabelAndIcon(view);
helper.inflateCheckmarkButtons(view, onCheckmarkLongClickListener,
onCheckmarkClickListener, inflater);
view = helper.inflateHabitCard(inflater, onCheckmarkLongClickListener,
onCheckmarkClickListener);
}
TextView tvStar = ((TextView) view.findViewById(R.id.tvStar));
TextView tvName = (TextView) view.findViewById(R.id.label);
LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner);
LinearLayout llButtons = (LinearLayout) view.findViewById(R.id.llButtons);
llInner.setTag(R.string.habit_key, habit.getId());
helper.updateNameAndIcon(habit, tvStar, tvName);
helper.updateCheckmarkButtons(habit, llButtons);
boolean selected = selectedPositions.contains(position);
helper.updateHabitBackground(llInner, selected);
helper.updateHabitCard(view, habit, selected);
return view;
}

View File

@@ -29,8 +29,8 @@ import android.widget.ProgressBar;
import com.android.colorpicker.ColorPickerDialog;
import com.android.colorpicker.ColorPickerSwatch;
import org.isoron.uhabits.R;
import org.isoron.uhabits.BaseActivity;
import org.isoron.uhabits.R;
import org.isoron.uhabits.commands.ArchiveHabitsCommand;
import org.isoron.uhabits.commands.ChangeHabitColorCommand;
import org.isoron.uhabits.commands.DeleteHabitsCommand;
@@ -163,15 +163,20 @@ public class HabitSelectionCallback implements ActionMode.Callback
case R.id.action_color:
{
ColorPickerDialog picker = ColorPickerDialog.newInstance(R.string.color_picker_default_title,
ColorHelper.palette, firstHabit.color, 4, ColorPickerDialog.SIZE_SMALL);
int originalAndroidColor = ColorHelper.getColor(activity, firstHabit.color);
ColorPickerDialog picker = ColorPickerDialog.newInstance(
R.string.color_picker_default_title, ColorHelper.getPalette(activity),
originalAndroidColor, 4, ColorPickerDialog.SIZE_SMALL);
picker.setOnColorSelectedListener(new ColorPickerSwatch.OnColorSelectedListener()
{
public void onColorSelected(int color)
public void onColorSelected(int androidColor)
{
activity.executeCommand(
new ChangeHabitColorCommand(selectedHabits, color), null);
int paletteColor = ColorHelper.colorToPaletteIndex(activity,
androidColor);
activity.executeCommand(new ChangeHabitColorCommand(selectedHabits,
paletteColor), null);
mode.finish();
}
});

View File

@@ -21,7 +21,6 @@ package org.isoron.uhabits.fragments;
import android.app.Fragment;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
@@ -163,20 +162,13 @@ public class ShowHabitFragment extends Fragment
float percentage = todayValue / Score.MAX_VALUE;
RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing);
scoreRing.setColor(habit.color);
int androidColor = ColorHelper.getColor(getActivity(), habit.color);
scoreRing.setColor(androidColor);
scoreRing.setPercentage(percentage);
}
private void updateHeaders(View view)
{
if(habit == null | activity == null) return;
if (android.os.Build.VERSION.SDK_INT >= 21)
{
int darkerHabitColor = ColorHelper.mixColors(habit.color, Color.BLACK, 0.75f);
activity.getWindow().setStatusBarColor(darkerHabitColor);
}
updateColor(view, R.id.tvHistory);
updateColor(view, R.id.tvOverview);
updateColor(view, R.id.tvStrength);
@@ -186,10 +178,11 @@ public class ShowHabitFragment extends Fragment
private void updateColor(View view, int viewId)
{
if(habit == null) return;
if(habit == null || activity == null) return;
TextView textView = (TextView) view.findViewById(viewId);
textView.setTextColor(habit.color);
int androidColor = ColorHelper.getColor(activity, habit.color);
textView.setTextColor(androidColor);
}
@Override

View File

@@ -19,27 +19,59 @@
package org.isoron.uhabits.helpers;
import android.content.Context;
import android.graphics.Color;
import org.isoron.uhabits.R;
public class ColorHelper
{
public static final int[] palette =
public static int CSV_PALETTE[] =
{
Color.parseColor("#D32F2F"), // red
Color.parseColor("#E64A19"), // orange
Color.parseColor("#F9A825"), // yellow
Color.parseColor("#AFB42B"), // light green
Color.parseColor("#388E3C"), // dark green
Color.parseColor("#00897B"), // teal
Color.parseColor("#00ACC1"), // cyan
Color.parseColor("#039BE5"), // blue
Color.parseColor("#5E35B1"), // deep purple
Color.parseColor("#8E24AA"), // purple
Color.parseColor("#D81B60"), // pink
Color.parseColor("#303030"), // dark grey
Color.parseColor("#aaaaaa") // light grey
Color.parseColor("#D32F2F"), // red
Color.parseColor("#E64A19"), // orange
Color.parseColor("#F9A825"), // yellow
Color.parseColor("#AFB42B"), // light green
Color.parseColor("#388E3C"), // dark green
Color.parseColor("#00897B"), // teal
Color.parseColor("#00ACC1"), // cyan
Color.parseColor("#039BE5"), // blue
Color.parseColor("#5E35B1"), // deep purple
Color.parseColor("#8E24AA"), // purple
Color.parseColor("#D81B60"), // pink
Color.parseColor("#303030"), // dark grey
Color.parseColor("#aaaaaa") // light grey
};
public static int colorToPaletteIndex(Context context, int color)
{
int[] palette = getPalette(context);
for(int k = 0; k < palette.length; k++)
if(palette[k] == color) return k;
return -1;
}
public static int[] getPalette(Context context)
{
int resourceId = UIHelper.getStyleResource(context, R.attr.palette);
if(resourceId < 0) return CSV_PALETTE;
return context.getResources().getIntArray(resourceId);
}
public static int getColor(Context context, int paletteColor)
{
if(context == null) throw new IllegalArgumentException("Context is null");
int palette[] = getPalette(context);
if(paletteColor < 0 || paletteColor >= palette.length)
throw new IllegalArgumentException(String.format("Invalid color: %d", paletteColor));
return palette[paletteColor];
}
public static int mixColors(int color1, int color2, float amount)
{
final byte ALPHA_CHANNEL = 24;

View File

@@ -20,13 +20,12 @@
package org.isoron.uhabits.helpers;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.DisplayMetrics;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -39,8 +38,8 @@ import java.util.GregorianCalendar;
public class ListHabitsHelper
{
public static final int INACTIVE_COLOR = Color.rgb(200, 200, 200);
public static final int INACTIVE_CHECKMARK_COLOR = Color.rgb(230, 230, 230);
private final int lowContrastColor;
private final int mediumContrastColor;
private final Context context;
private final HabitListLoader loader;
@@ -51,6 +50,8 @@ public class ListHabitsHelper
this.context = context;
this.loader = loader;
lowContrastColor = UIHelper.getStyledColor(context, R.attr.lowContrastTextColor);
mediumContrastColor = UIHelper.getStyledColor(context, R.attr.mediumContrastTextColor);
fontawesome = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
}
@@ -61,16 +62,18 @@ public class ListHabitsHelper
public int getButtonCount()
{
DisplayMetrics dm = context.getResources().getDisplayMetrics();
int width = (int) (dm.widthPixels / dm.density);
return Math.max(0, (int) ((width - 160) / 42.0));
float screenWidth = UIHelper.getScreenWidth(context);
float labelWidth = context.getResources().getDimension(R.dimen.habitNameWidth);
float buttonWidth = context.getResources().getDimension(R.dimen.checkmarkWidth);
return Math.max(0, (int) ((screenWidth - labelWidth) / buttonWidth));
}
public int getHabitNameWidth()
{
DisplayMetrics dm = context.getResources().getDisplayMetrics();
int width = (int) (dm.widthPixels / dm.density);
return (int) ((width - 30 - getButtonCount() * 42) * dm.density);
float screenWidth = UIHelper.getScreenWidth(context);
float buttonWidth = context.getResources().getDimension(R.dimen.checkmarkWidth);
float padding = UIHelper.dpToPixels(context, 15);
return (int) (screenWidth - padding - getButtonCount() * buttonWidth);
}
public void updateCheckmarkButtons(Habit habit, LinearLayout llButtons)
@@ -94,8 +97,8 @@ public class ListHabitsHelper
public int getActiveColor(Habit habit)
{
int activeColor = habit.color;
if(habit.isArchived()) activeColor = INACTIVE_COLOR;
int activeColor = ColorHelper.getColor(context, habit.color);
if(habit.isArchived()) activeColor = mediumContrastColor;
return activeColor;
}
@@ -129,12 +132,12 @@ public class ListHabitsHelper
if (score < Score.HALF_STAR_CUTOFF)
{
tvStar.setText(context.getString(R.string.fa_star_o));
tvStar.setTextColor(INACTIVE_COLOR);
tvStar.setTextColor(lowContrastColor);
}
else if (score < Score.FULL_STAR_CUTOFF)
{
tvStar.setText(context.getString(R.string.fa_star_half_o));
tvStar.setTextColor(INACTIVE_COLOR);
tvStar.setTextColor(lowContrastColor);
}
else
{
@@ -156,27 +159,64 @@ public class ListHabitsHelper
case 1:
tvCheck.setText(R.string.fa_check);
tvCheck.setTextColor(INACTIVE_CHECKMARK_COLOR);
tvCheck.setTextColor(lowContrastColor);
tvCheck.setTag(R.string.toggle_key, 1);
break;
case 0:
tvCheck.setText(R.string.fa_times);
tvCheck.setTextColor(INACTIVE_CHECKMARK_COLOR);
tvCheck.setTextColor(lowContrastColor);
tvCheck.setTag(R.string.toggle_key, 0);
break;
}
}
public void updateHabitBackground(View view, boolean isSelected)
public View inflateHabitCard(LayoutInflater inflater,
View.OnLongClickListener onCheckmarkLongClickListener,
View.OnClickListener onCheckmarkClickListener)
{
if (isSelected)
view.setBackgroundResource(R.drawable.selected_box);
View view = inflater.inflate(R.layout.list_habits_item, null);
initializeLabelAndIcon(view);
inflateCheckmarkButtons(view, onCheckmarkLongClickListener, onCheckmarkClickListener,
inflater);
return view;
}
public void updateHabitCard(View view, Habit habit, boolean selected)
{
TextView tvStar = ((TextView) view.findViewById(R.id.tvStar));
TextView tvName = (TextView) view.findViewById(R.id.label);
LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner);
LinearLayout llButtons = (LinearLayout) view.findViewById(R.id.llButtons);
llInner.setTag(R.string.habit_key, habit.getId());
llInner.setOnTouchListener(new HotspotTouchListener());
updateNameAndIcon(habit, tvStar, tvName);
updateCheckmarkButtons(habit, llButtons);
updateHabitCardBackground(llInner, selected);
}
public void updateHabitCardBackground(View view, boolean isSelected)
{
if (android.os.Build.VERSION.SDK_INT >= 21)
{
if (isSelected)
view.setBackgroundResource(R.drawable.selected_box);
else
view.setBackgroundResource(R.drawable.ripple);
}
else
{
if (android.os.Build.VERSION.SDK_INT >= 21)
view.setBackgroundResource(R.drawable.ripple_white);
else view.setBackgroundResource(R.drawable.card_background);
Drawable background;
if (isSelected)
background = UIHelper.getStyledDrawable(context, R.attr.selectedBackground);
else
background = UIHelper.getStyledDrawable(context, R.attr.cardBackground);
view.setBackgroundDrawable(background);
}
}
@@ -206,7 +246,7 @@ public class ListHabitsHelper
for (int i = 0; i < getButtonCount(); i++)
{
View tvDay = inflater.inflate(R.layout.list_habits_header_check, null);
Button btCheck = (Button) tvDay.findViewById(R.id.tvCheck);
TextView btCheck = (TextView) tvDay.findViewById(R.id.tvCheck);
btCheck.setText(DateHelper.formatHeaderDate(day));
header.addView(tvDay);
@@ -222,9 +262,22 @@ public class ListHabitsHelper
public void toggleCheckmarkView(View v, Habit habit)
{
int androidColor = ColorHelper.getColor(context, habit.color);
if (v.getTag(R.string.toggle_key).equals(2))
updateCheckmark(habit.color, (TextView) v, 0);
updateCheckmark(androidColor, (TextView) v, 0);
else
updateCheckmark(habit.color, (TextView) v, 2);
updateCheckmark(androidColor, (TextView) v, 2);
}
private static class HotspotTouchListener implements View.OnTouchListener
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
if (android.os.Build.VERSION.SDK_INT >= 21)
v.getBackground().setHotspot(event.getX(), event.getY());
return false;
}
}
}

View File

@@ -19,10 +19,13 @@
package org.isoron.uhabits.helpers;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Debug;
import android.os.Looper;
@@ -35,14 +38,19 @@ import android.view.View;
import android.view.inputmethod.InputMethodManager;
import org.isoron.uhabits.BuildConfig;
import org.isoron.uhabits.HabitsApplication;
import org.isoron.uhabits.R;
import org.isoron.uhabits.commands.Command;
import java.util.Locale;
public abstract class UIHelper
{
public static final String ISORON_NAMESPACE = "http://isoron.org/android";
public static final int THEME_LIGHT = 0;
public static final int THEME_DARK = 1;
private static Typeface fontawesome;
public interface OnSavedListener
@@ -165,4 +173,92 @@ public abstract class UIHelper
return false;
}
public static float getScreenWidth(Context context)
{
return context.getResources().getDisplayMetrics().widthPixels;
}
public static int getStyledColor(Context context, int attrId)
{
int[] attrs = new int[]{ attrId };
TypedArray ta = context.obtainStyledAttributes(attrs);
int color = ta.getColor(0, 0);
ta.recycle();
return color;
}
public static Drawable getStyledDrawable(Context context, int attrId)
{
int[] attrs = new int[]{ attrId };
TypedArray ta = context.obtainStyledAttributes(attrs);
Drawable drawable = ta.getDrawable(0);
ta.recycle();
return drawable;
}
public static boolean getStyledBoolean(Context context, int attrId)
{
int[] attrs = new int[]{ attrId };
TypedArray ta = context.obtainStyledAttributes(attrs);
boolean bool = ta.getBoolean(0, false);
ta.recycle();
return bool;
}
static int getStyleResource(Context context, int attrId)
{
int[] attr = new int[] { attrId };
TypedArray array = context.obtainStyledAttributes(attr);
int resourceId = array.getResourceId(0, -1);
array.recycle();
return resourceId;
}
public static void applyCurrentTheme(Activity activity)
{
switch(getCurrentTheme())
{
case THEME_DARK:
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
boolean pureBlackEnabled = prefs.getBoolean("pref_pure_black", false);
if(pureBlackEnabled)
activity.setTheme(R.style.AppBaseThemeDark_PureBlack);
else
activity.setTheme(R.style.AppBaseThemeDark);
break;
}
case THEME_LIGHT:
default:
activity.setTheme(R.style.AppBaseTheme);
break;
}
}
private static int getCurrentTheme()
{
Context appContext = HabitsApplication.getContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
return prefs.getInt("pref_theme", THEME_LIGHT);
}
public static void setCurrentTheme(int theme)
{
Context appContext = HabitsApplication.getContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
prefs.edit().putInt("pref_theme", theme).apply();
}
public static boolean isNightMode()
{
return getCurrentTheme() == THEME_DARK;
}
}

View File

@@ -71,7 +71,11 @@ public class Habit extends Model
public Integer freqDen;
/**
* Color of the habit. The format is the same as android.graphics.Color.
* Color of the habit.
*
* This number is not an android.graphics.Color, but an index to the activity color palette,
* which changes according to the theme. To convert this color into an android.graphics.Color,
* use ColorHelper.getColor(context, habit.color).
*/
@Column(name = "color")
public Integer color;
@@ -166,7 +170,7 @@ public class Habit extends Model
*/
public Habit()
{
this.color = ColorHelper.palette[5];
this.color = 5;
this.position = Habit.countWithArchived();
this.highlight = 0;
this.archived = 0;
@@ -492,8 +496,15 @@ public class Habit extends Model
for(Habit habit : habits)
{
String[] cols = { habit.name, habit.description, Integer.toString(habit.freqNum),
Integer.toString(habit.freqDen), ColorHelper.toHTML(habit.color) };
String[] cols =
{
habit.name,
habit.description,
Integer.toString(habit.freqNum),
Integer.toString(habit.freqDen),
ColorHelper.toHTML(ColorHelper.CSV_PALETTE[habit.color])
};
csv.writeNext(cols, false);
}

View File

@@ -94,7 +94,7 @@ public class CheckmarkView extends View implements HabitDataView
fa_check = context.getString(R.string.fa_check);
fa_times = context.getString(R.string.fa_times);
primaryColor = ColorHelper.palette[10];
primaryColor = ColorHelper.getColor(getContext(), 10);
timesColor = Color.argb(128, 255, 255, 255);
darkGrey = Color.argb(64, 0, 0, 0);
@@ -184,8 +184,9 @@ public class CheckmarkView extends View implements HabitDataView
public void refreshData()
{
this.check_status = habit.checkmarks.getTodayValue();
this.primaryColor = Color.argb(230, Color.red(habit.color), Color.green(habit.color),
Color.blue(habit.color));
int color = ColorHelper.getColor(getContext(), habit.color);
this.primaryColor = Color.argb(230, Color.red(color), Color.green(color),
Color.blue(color));
this.label = habit.name;
updateLabel();

View File

@@ -26,8 +26,10 @@ import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.models.Habit;
import java.text.SimpleDateFormat;
@@ -56,7 +58,7 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
private int nColumns;
private int textColor;
private int dimmedTextColor;
private int gridColor;
private int[] colors;
private int primaryColor;
private boolean isBackgroundTransparent;
@@ -72,7 +74,7 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
public HabitFrequencyView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.primaryColor = ColorHelper.palette[7];
this.primaryColor = ColorHelper.getColor(getContext(), 7);
this.frequency = new HashMap<>();
init();
}
@@ -98,7 +100,9 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
private void createColors()
{
if(habit != null)
this.primaryColor = habit.color;
{
this.primaryColor = ColorHelper.getColor(getContext(), habit.color);
}
if (isBackgroundTransparent)
{
@@ -106,17 +110,17 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
primaryColor = ColorHelper.setValue(primaryColor, 1.0f);
textColor = Color.argb(192, 255, 255, 255);
dimmedTextColor = Color.argb(128, 255, 255, 255);
gridColor = Color.argb(128, 255, 255, 255);
}
else
{
textColor = Color.argb(64, 0, 0, 0);
dimmedTextColor = Color.argb(16, 0, 0, 0);
textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
gridColor = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor);
}
colors = new int[4];
colors[0] = Color.rgb(230, 230, 230);
colors[0] = gridColor;
colors[3] = primaryColor;
colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f);
colors[2] = ColorHelper.mixColors(colors[0], colors[3], 0.33f);
@@ -286,7 +290,7 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
pText.setTextAlign(Paint.Align.LEFT);
pText.setColor(textColor);
pGrid.setColor(dimmedTextColor);
pGrid.setColor(gridColor);
for (String day : DateHelper.getLocaleDayNames(Calendar.SHORT)) {
canvas.drawText(day, rGrid.right - columnWidth,

View File

@@ -70,6 +70,7 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
private boolean isBackgroundTransparent;
private int textColor;
private int reverseTextColor;
private boolean isEditable;
public HabitHistoryView(Context context)
@@ -92,12 +93,12 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
private void init()
{
createPaints();
createColors();
createPaints();
isEditable = false;
checkmarks = new int[0];
primaryColor = ColorHelper.palette[7];
primaryColor = ColorHelper.getColor(getContext(), 7);
dfMonth = DateHelper.getDateFormat("MMM");
dfYear = DateHelper.getDateFormat("yyyy");
@@ -164,7 +165,7 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
private void createColors()
{
if(habit != null)
this.primaryColor = habit.color;
this.primaryColor = ColorHelper.getColor(getContext(), habit.color);
if(isBackgroundTransparent)
primaryColor = ColorHelper.setMinValue(primaryColor, 0.75f);
@@ -179,15 +180,17 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
colors[0] = Color.argb(16, 255, 255, 255);
colors[1] = Color.argb(128, red, green, blue);
colors[2] = primaryColor;
textColor = Color.rgb(255, 255, 255);
textColor = Color.WHITE;
reverseTextColor = Color.WHITE;
}
else
{
colors = new int[3];
colors[0] = Color.argb(25, 0, 0, 0);
colors[0] = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor);
colors[1] = Color.argb(127, red, green, blue);
colors[2] = primaryColor;
textColor = Color.argb(64, 0, 0, 0);
textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
reverseTextColor = UIHelper.getStyledColor(getContext(), R.attr.highContrastReverseTextColor);
}
}
@@ -198,10 +201,8 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
pTextHeader.setAntiAlias(true);
pSquareBg = new Paint();
pSquareBg.setColor(primaryColor);
pSquareFg = new Paint();
pSquareFg.setColor(Color.WHITE);
pSquareFg.setAntiAlias(true);
pSquareFg.setTextAlign(Align.CENTER);
}
@@ -292,6 +293,7 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
if (checkmarkOffset >= checkmarks.length) pSquareBg.setColor(colors[0]);
else pSquareBg.setColor(colors[checkmarks[checkmarkOffset]]);
pSquareFg.setColor(reverseTextColor);
canvas.drawRect(location, pSquareBg);
String text = Integer.toString(date.get(Calendar.DAY_OF_MONTH));
canvas.drawText(text, location.centerX(), location.centerY() + squareTextOffset, pSquareFg);

View File

@@ -32,6 +32,7 @@ import android.util.AttributeSet;
import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.Score;
@@ -65,7 +66,7 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
private int nColumns;
private int textColor;
private int dimmedTextColor;
private int gridColor;
@Nullable
private int[] scores;
@@ -74,6 +75,7 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
private boolean isBackgroundTransparent;
private int bucketSize = 7;
private int footerHeight;
private int backgroundColor;
public HabitScoreView(Context context)
{
@@ -84,7 +86,7 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
public HabitScoreView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.primaryColor = ColorHelper.palette[7];
this.primaryColor = ColorHelper.getColor(getContext(), 7);
init();
}
@@ -110,7 +112,7 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
private void createColors()
{
if(habit != null)
this.primaryColor = habit.color;
this.primaryColor = ColorHelper.getColor(getContext(), habit.color);
if (isBackgroundTransparent)
{
@@ -118,12 +120,13 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
primaryColor = ColorHelper.setValue(primaryColor, 1.0f);
textColor = Color.argb(192, 255, 255, 255);
dimmedTextColor = Color.argb(128, 255, 255, 255);
gridColor = Color.argb(128, 255, 255, 255);
}
else
{
textColor = Color.argb(64, 0, 0, 0);
dimmedTextColor = Color.argb(16, 0, 0, 0);
textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
gridColor = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor);
backgroundColor = UIHelper.getStyledColor(getContext(), R.attr.cardBackgroundColor);
}
}
@@ -172,7 +175,7 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
pGraph.setTextSize(baseSize * 0.5f);
pGraph.setStrokeWidth(baseSize * 0.1f);
pGrid.setStrokeWidth(baseSize * 0.05f);
pGrid.setStrokeWidth(baseSize * 0.025f);
}
public void refreshData()
@@ -322,7 +325,7 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
pText.setTextAlign(Paint.Align.LEFT);
pText.setColor(textColor);
pGrid.setColor(dimmedTextColor);
pGrid.setColor(gridColor);
for (int i = 0; i < nRows; i++)
{
@@ -345,7 +348,7 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
private void drawMarker(Canvas canvas, RectF rect)
{
rect.inset(baseSize * 0.15f, baseSize * 0.15f);
setModeOrColor(pGraph, XFERMODE_CLEAR, Color.WHITE);
setModeOrColor(pGraph, XFERMODE_CLEAR, backgroundColor);
canvas.drawOval(rect, pGraph);
rect.inset(baseSize * 0.1f, baseSize * 0.1f);
@@ -353,7 +356,7 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
canvas.drawOval(rect, pGraph);
rect.inset(baseSize * 0.1f, baseSize * 0.1f);
setModeOrColor(pGraph, XFERMODE_CLEAR, Color.WHITE);
setModeOrColor(pGraph, XFERMODE_CLEAR, backgroundColor);
canvas.drawOval(rect, pGraph);
if(isBackgroundTransparent)

View File

@@ -29,6 +29,7 @@ import android.view.View;
import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.Streak;
@@ -53,7 +54,6 @@ public class HabitStreakView extends View implements HabitDataView
private List<Streak> streaks;
private boolean isBackgroundTransparent;
private int textColor;
private DateFormat dateFormat;
private int width;
private float em;
@@ -61,6 +61,8 @@ public class HabitStreakView extends View implements HabitDataView
private float textMargin;
private boolean shouldShowLabels;
private int maxStreakCount;
private int textColor;
private int reverseTextColor;
public HabitStreakView(Context context)
{
@@ -71,7 +73,7 @@ public class HabitStreakView extends View implements HabitDataView
public HabitStreakView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.primaryColor = ColorHelper.palette[7];
this.primaryColor = ColorHelper.getColor(getContext(), 7);
init();
}
@@ -122,7 +124,7 @@ public class HabitStreakView extends View implements HabitDataView
private void createColors()
{
if(habit != null)
this.primaryColor = habit.color;
this.primaryColor = ColorHelper.getColor(getContext(), habit.color);
if(isBackgroundTransparent)
{
@@ -141,7 +143,8 @@ public class HabitStreakView extends View implements HabitDataView
colors[2] = Color.argb(213, red, green, blue);
colors[1] = Color.argb(170, red, green, blue);
colors[0] = Color.argb(128, red, green, blue);
textColor = Color.rgb(255, 255, 255);
textColor = Color.WHITE;
reverseTextColor = Color.WHITE;
}
else
{
@@ -149,8 +152,9 @@ public class HabitStreakView extends View implements HabitDataView
colors[3] = primaryColor;
colors[2] = Color.argb(192, red, green, blue);
colors[1] = Color.argb(96, red, green, blue);
colors[0] = Color.argb(32, 0, 0, 0);
textColor = Color.argb(64, 0, 0, 0);
colors[0] = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor);
textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
reverseTextColor = UIHelper.getStyledColor(getContext(), R.attr.highContrastReverseTextColor);
}
}
@@ -216,7 +220,7 @@ public class HabitStreakView extends View implements HabitDataView
if(shouldShowLabels) availableWidth -= 2 * textMargin;
float barWidth = percentage * availableWidth;
float minBarWidth = paint.measureText(streak.length.toString());
float minBarWidth = paint.measureText(streak.length.toString()) + em;
barWidth = Math.max(barWidth, minBarWidth);
float gap = (width - barWidth) / 2;
@@ -229,7 +233,7 @@ public class HabitStreakView extends View implements HabitDataView
float yOffset = rect.centerY() + 0.3f * em;
paint.setColor(Color.WHITE);
paint.setColor(reverseTextColor);
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(streak.length.toString(), rect.centerX(), yOffset, paint);

View File

@@ -71,7 +71,7 @@ public class NumberView extends View
this.textSize = UIHelper.getFloatAttribute(context, attrs, "textSize",
getResources().getDimension(R.dimen.regularTextSize));
this.color = ColorHelper.palette[7];
this.color = ColorHelper.getColor(getContext(), 7);
init();
}

View File

@@ -23,6 +23,7 @@ import android.content.Context;
import android.util.AttributeSet;
import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.models.Habit;
@@ -79,6 +80,6 @@ public class RepetitionCountView extends NumberView implements HabitDataView
public void setHabit(Habit habit)
{
this.habit = habit;
setColor(habit.color);
setColor(ColorHelper.getColor(getContext(), habit.color));
}
}

View File

@@ -22,7 +22,6 @@ package org.isoron.uhabits.views;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.Layout;
@@ -50,7 +49,8 @@ public class RingView extends View
private float maxDiameter;
private float textSize;
private int fadedTextColor;
private int textColor;
private int backgroundColor;
public RingView(Context context)
{
@@ -97,7 +97,8 @@ public class RingView extends View
pRing.setColor(color);
pRing.setTextAlign(Paint.Align.CENTER);
fadedTextColor = getResources().getColor(R.color.fadedTextColor);
backgroundColor = UIHelper.getStyledColor(getContext(), R.attr.cardBackgroundColor);
textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
textSize = getResources().getDimension(R.dimen.smallTextSize);
rect = new RectF();
@@ -136,14 +137,15 @@ public class RingView extends View
rect.offset((width - diameter) / 2, 0);
canvas.drawArc(rect, -90, 360 * percentage, true, pRing);
pRing.setColor(Color.argb(255, 230, 230, 230));
int grey = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor);
pRing.setColor(grey);
canvas.drawArc(rect, 360 * percentage - 90 + 2, 360 * (1 - percentage) - 4, true, pRing);
pRing.setColor(Color.WHITE);
pRing.setColor(backgroundColor);
rect.inset(thickness, thickness);
canvas.drawArc(rect, -90, 360, true, pRing);
pRing.setColor(fadedTextColor);
pRing.setColor(textColor);
pRing.setTextSize(textSize);
float lineHeight = pRing.getFontSpacing();
canvas.drawText(String.format("%.0f%%", percentage * 100), rect.centerX(),