mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Compatibility with older devices; more statistics
This commit is contained in:
@@ -6,7 +6,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "org.isoron.uhabits"
|
applicationId "org.isoron.uhabits"
|
||||||
minSdkVersion 21
|
minSdkVersion 15
|
||||||
targetSdkVersion 22
|
targetSdkVersion 22
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest
|
||||||
package="org.isoron.uhabits"
|
package="org.isoron.uhabits"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:versionCode="1"
|
android:versionCode="1"
|
||||||
android:versionName="1.0">
|
android:versionName="1.0">
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="21"
|
android:minSdkVersion="14"
|
||||||
android:targetSdkVersion="22" />
|
android:targetSdkVersion="21"/>
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
|
|
||||||
@@ -16,9 +17,11 @@
|
|||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="AA_DB_NAME"
|
android:name="AA_DB_NAME"
|
||||||
android:value="uhabits.db"/>
|
android:value="uhabits.db"/>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="AA_DB_VERSION"
|
android:name="AA_DB_VERSION"
|
||||||
android:value="6"/>
|
android:value="6"/>
|
||||||
@@ -29,7 +32,6 @@
|
|||||||
android:launchMode="singleInstance">
|
android:launchMode="singleInstance">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ public class DatePickerDialog extends DialogFragment implements
|
|||||||
private TextView mYearView;
|
private TextView mYearView;
|
||||||
private DayPickerView mDayPickerView;
|
private DayPickerView mDayPickerView;
|
||||||
private YearPickerView mYearPickerView;
|
private YearPickerView mYearPickerView;
|
||||||
private Button mDoneButton;
|
|
||||||
private Button mClearButton;
|
|
||||||
|
|
||||||
private int mCurrentView = UNINITIALIZED;
|
private int mCurrentView = UNINITIALIZED;
|
||||||
|
|
||||||
@@ -245,12 +243,15 @@ public class DatePickerDialog extends DialogFragment implements
|
|||||||
animation2.setDuration(ANIMATION_DURATION);
|
animation2.setDuration(ANIMATION_DURATION);
|
||||||
mAnimator.setOutAnimation(animation2);
|
mAnimator.setOutAnimation(animation2);
|
||||||
|
|
||||||
mDoneButton = (Button) view.findViewById(R.id.done);
|
Button mDoneButton = (Button) view.findViewById(R.id.done);
|
||||||
mDoneButton.setOnClickListener(new OnClickListener() {
|
mDoneButton.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v)
|
||||||
|
{
|
||||||
tryVibrate();
|
tryVibrate();
|
||||||
if (mCallBack != null) {
|
if (mCallBack != null)
|
||||||
|
{
|
||||||
mCallBack.onDateSet(DatePickerDialog.this, mCalendar.get(Calendar.YEAR),
|
mCallBack.onDateSet(DatePickerDialog.this, mCalendar.get(Calendar.YEAR),
|
||||||
mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH));
|
mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH));
|
||||||
}
|
}
|
||||||
@@ -258,12 +259,15 @@ public class DatePickerDialog extends DialogFragment implements
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mClearButton = (Button) view.findViewById(R.id.clear);
|
Button mClearButton = (Button) view.findViewById(R.id.clear);
|
||||||
mClearButton.setOnClickListener(new OnClickListener() {
|
mClearButton.setOnClickListener(new OnClickListener()
|
||||||
|
{
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v)
|
||||||
|
{
|
||||||
tryVibrate();
|
tryVibrate();
|
||||||
if (mCallBack != null) {
|
if (mCallBack != null)
|
||||||
|
{
|
||||||
mCallBack.onDateCleared(DatePickerDialog.this);
|
mCallBack.onDateCleared(DatePickerDialog.this);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ public class DateHelper
|
|||||||
public static int differenceInDays(Date from, Date to)
|
public static int differenceInDays(Date from, Date to)
|
||||||
{
|
{
|
||||||
long milliseconds = getStartOfDay(to.getTime()) - getStartOfDay(from.getTime());
|
long milliseconds = getStartOfDay(to.getTime()) - getStartOfDay(from.getTime());
|
||||||
int days = (int) (milliseconds / millisecondsInOneDay);
|
return (int) (milliseconds / millisecondsInOneDay);
|
||||||
return days;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String differenceInWords(Date from, Date to)
|
public static String differenceInWords(Date from, Date to)
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ public class MainActivity extends Activity
|
|||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= 21)
|
||||||
getActionBar().setElevation(5);
|
getActionBar().setElevation(5);
|
||||||
|
|
||||||
setContentView(R.layout.list_habits_activity);
|
setContentView(R.layout.list_habits_activity);
|
||||||
|
|||||||
@@ -16,22 +16,24 @@ public class ShowHabitActivity extends Activity
|
|||||||
{
|
{
|
||||||
|
|
||||||
public Habit habit;
|
public Habit habit;
|
||||||
private ShowHabitFragment showHabitFragment;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
getActionBar().setElevation(5);
|
|
||||||
Uri data = getIntent().getData();
|
Uri data = getIntent().getData();
|
||||||
habit = Habit.get(ContentUris.parseId(data));
|
habit = Habit.get(ContentUris.parseId(data));
|
||||||
getActionBar().setTitle(habit.name);
|
getActionBar().setTitle(habit.name);
|
||||||
|
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= 21)
|
||||||
|
{
|
||||||
|
getActionBar().setElevation(5);
|
||||||
getActionBar().setBackgroundDrawable(new ColorDrawable(habit.color));
|
getActionBar().setBackgroundDrawable(new ColorDrawable(habit.color));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
setContentView(R.layout.show_habit_activity);
|
setContentView(R.layout.show_habit_activity);
|
||||||
showHabitFragment = (ShowHabitFragment) getFragmentManager().findFragmentById(
|
|
||||||
R.id.fragment2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -338,7 +338,6 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnI
|
|||||||
Intent intent = new Intent(getActivity(), ShowHabitActivity.class);
|
Intent intent = new Intent(getActivity(), ShowHabitActivity.class);
|
||||||
intent.setData(Uri.parse("content://org.isoron.uhabits/habit/"
|
intent.setData(Uri.parse("content://org.isoron.uhabits/habit/"
|
||||||
+ habit.getId()));
|
+ habit.getId()));
|
||||||
getActivity().getWindow().setExitTransition(new Explode());
|
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import org.isoron.uhabits.R;
|
|||||||
import org.isoron.uhabits.ShowHabitActivity;
|
import org.isoron.uhabits.ShowHabitActivity;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
import org.isoron.uhabits.views.HabitHistoryView;
|
import org.isoron.uhabits.views.HabitHistoryView;
|
||||||
|
import org.isoron.uhabits.views.HabitStreakView;
|
||||||
|
import org.isoron.uhabits.views.RingView;
|
||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@@ -27,7 +29,6 @@ import android.widget.TextView;
|
|||||||
public class ShowHabitFragment extends Fragment
|
public class ShowHabitFragment extends Fragment
|
||||||
{
|
{
|
||||||
protected ShowHabitActivity activity;
|
protected ShowHabitActivity activity;
|
||||||
private Habit habit;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart()
|
public void onStart()
|
||||||
@@ -43,24 +44,34 @@ public class ShowHabitFragment extends Fragment
|
|||||||
|
|
||||||
View view = inflater.inflate(R.layout.show_habit, container, false);
|
View view = inflater.inflate(R.layout.show_habit, container, false);
|
||||||
activity = (ShowHabitActivity) getActivity();
|
activity = (ShowHabitActivity) getActivity();
|
||||||
habit = activity.habit;
|
Habit habit = activity.habit;
|
||||||
|
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= 21)
|
||||||
|
{
|
||||||
int darkerHabitColor = ColorHelper.mixColors(habit.color, Color.BLACK, 0.75f);
|
int darkerHabitColor = ColorHelper.mixColors(habit.color, Color.BLACK, 0.75f);
|
||||||
activity.getWindow().setStatusBarColor(darkerHabitColor);
|
activity.getWindow().setStatusBarColor(darkerHabitColor);
|
||||||
|
}
|
||||||
|
|
||||||
TextView tvHistory = (TextView) view.findViewById(R.id.tvHistory);
|
TextView tvHistory = (TextView) view.findViewById(R.id.tvHistory);
|
||||||
TextView tvOverview = (TextView) view.findViewById(R.id.tvOverview);
|
TextView tvOverview = (TextView) view.findViewById(R.id.tvOverview);
|
||||||
|
TextView tvStreaks= (TextView) view.findViewById(R.id.tvStreaks);
|
||||||
tvHistory.setTextColor(habit.color);
|
tvHistory.setTextColor(habit.color);
|
||||||
tvOverview.setTextColor(habit.color);
|
tvOverview.setTextColor(habit.color);
|
||||||
|
tvStreaks.setTextColor(habit.color);
|
||||||
|
|
||||||
TextView tvStrength = (TextView) view.findViewById(R.id.tvStrength);
|
LinearLayout llOverview = (LinearLayout) view.findViewById(R.id.llOverview);
|
||||||
tvStrength.setText(String.format("%.2f%%", ((float) habit.getScore() / Habit.MAX_SCORE) * 100));
|
llOverview.addView(new RingView(activity, 200, habit.color, ((float) habit.getScore() / Habit.MAX_SCORE), "Habit strength"));
|
||||||
|
|
||||||
LinearLayout llHistory = (LinearLayout) view.findViewById(R.id.llHistory);
|
LinearLayout llHistory = (LinearLayout) view.findViewById(R.id.llHistory);
|
||||||
|
HabitHistoryView hhv = new HabitHistoryView(activity, habit,
|
||||||
HabitHistoryView hhv = new HabitHistoryView(activity, habit, 40);
|
(int) activity.getResources().getDimension(R.dimen.square_size));
|
||||||
llHistory.addView(hhv);
|
llHistory.addView(hhv);
|
||||||
|
|
||||||
|
LinearLayout llStreaks = (LinearLayout) view.findViewById(R.id.llStreaks);
|
||||||
|
HabitStreakView hsv = new HabitStreakView(activity, habit,
|
||||||
|
(int) activity.getResources().getDimension(R.dimen.square_size));
|
||||||
|
llStreaks.addView(hsv);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
package org.isoron.uhabits.models;
|
package org.isoron.uhabits.models;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.isoron.helpers.ColorHelper;
|
|
||||||
import org.isoron.helpers.Command;
|
|
||||||
import org.isoron.helpers.DateHelper;
|
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.activeandroid.Cache;
|
||||||
import com.activeandroid.Model;
|
import com.activeandroid.Model;
|
||||||
import com.activeandroid.annotation.Column;
|
import com.activeandroid.annotation.Column;
|
||||||
import com.activeandroid.annotation.Table;
|
import com.activeandroid.annotation.Table;
|
||||||
@@ -18,14 +15,17 @@ import com.activeandroid.query.Select;
|
|||||||
import com.activeandroid.query.Update;
|
import com.activeandroid.query.Update;
|
||||||
import com.activeandroid.util.SQLiteUtils;
|
import com.activeandroid.util.SQLiteUtils;
|
||||||
|
|
||||||
|
import org.isoron.helpers.ColorHelper;
|
||||||
|
import org.isoron.helpers.Command;
|
||||||
|
import org.isoron.helpers.DateHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Table(name = "Habits")
|
@Table(name = "Habits")
|
||||||
public class Habit extends Model
|
public class Habit extends Model
|
||||||
{
|
{
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
||||||
* Fields *
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
public static final int HALF_STAR_CUTOFF = 5999000;
|
public static final int HALF_STAR_CUTOFF = 5999000;
|
||||||
public static final int FULL_STAR_CUTOFF = 12973000;
|
public static final int FULL_STAR_CUTOFF = 12973000;
|
||||||
public static final int MAX_SCORE = 19259500;
|
public static final int MAX_SCORE = 19259500;
|
||||||
@@ -57,9 +57,327 @@ public class Habit extends Model
|
|||||||
@Column(name = "highlight")
|
@Column(name = "highlight")
|
||||||
public Integer highlight;
|
public Integer highlight;
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
public Habit(Habit model)
|
||||||
* Commands *
|
{
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
copyAttributes(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Habit()
|
||||||
|
{
|
||||||
|
this.color = ColorHelper.palette[11];
|
||||||
|
this.position = Habit.getCount();
|
||||||
|
this.highlight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Habit get(Long id)
|
||||||
|
{
|
||||||
|
return Habit.load(Habit.class, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
public static void updateId(long oldId, long newId)
|
||||||
|
{
|
||||||
|
SQLiteUtils.execSql(String.format(
|
||||||
|
"update Habits set Id = %d where Id = %d", newId, oldId));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static From select()
|
||||||
|
{
|
||||||
|
return new Select().from(Habit.class).orderBy("position");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getCount()
|
||||||
|
{
|
||||||
|
return select().count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Habit getByPosition(int position)
|
||||||
|
{
|
||||||
|
return select().offset(position).executeSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static java.util.List<Habit> getHabits()
|
||||||
|
{
|
||||||
|
return select().execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static java.util.List<Habit> getHighlightedHabits()
|
||||||
|
{
|
||||||
|
return select().where("highlight = 1").orderBy("reminder_hour desc, reminder_min desc")
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static java.util.List<Habit> getHabitsWithReminder()
|
||||||
|
{
|
||||||
|
return select().where("reminder_hour is not null").execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void reorder(int from, int to)
|
||||||
|
{
|
||||||
|
if (from == to)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Habit h = Habit.getByPosition(from);
|
||||||
|
if (to < from)
|
||||||
|
new Update(Habit.class).set("position = position + 1")
|
||||||
|
.where("position >= ? and position < ?", to, from)
|
||||||
|
.execute();
|
||||||
|
else
|
||||||
|
new Update(Habit.class).set("position = position - 1")
|
||||||
|
.where("position > ? and position <= ?", from, to)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
h.position = to;
|
||||||
|
h.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void rebuildOrder()
|
||||||
|
{
|
||||||
|
List<Habit> habits = select().execute();
|
||||||
|
int i = 0;
|
||||||
|
for (Habit h : habits)
|
||||||
|
{
|
||||||
|
h.position = i++;
|
||||||
|
h.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void roundTimestamps()
|
||||||
|
{
|
||||||
|
List<Repetition> reps = new Select().from(Repetition.class).execute();
|
||||||
|
for (Repetition r : reps)
|
||||||
|
{
|
||||||
|
r.timestamp = DateHelper.getStartOfDay(r.timestamp);
|
||||||
|
r.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getStarCount()
|
||||||
|
{
|
||||||
|
String args[] = {};
|
||||||
|
return SQLiteUtils.intQuery(
|
||||||
|
"select count(*) from (select score, max(timestamp) from " +
|
||||||
|
"score group by habit) as scores where scores.score >= "
|
||||||
|
+ Integer.toString(12973000), args);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyAttributes(Habit model)
|
||||||
|
{
|
||||||
|
this.name = model.name;
|
||||||
|
this.description = model.description;
|
||||||
|
this.freq_num = model.freq_num;
|
||||||
|
this.freq_den = model.freq_den;
|
||||||
|
this.color = model.color;
|
||||||
|
this.position = model.position;
|
||||||
|
this.reminder_hour = model.reminder_hour;
|
||||||
|
this.reminder_min = model.reminder_min;
|
||||||
|
this.highlight = model.highlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void save(Long id)
|
||||||
|
{
|
||||||
|
save();
|
||||||
|
Habit.updateId(getId(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected From selectReps()
|
||||||
|
{
|
||||||
|
return new Select().from(Repetition.class).where("habit = ?", getId())
|
||||||
|
.orderBy("timestamp");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected From selectRepsFromTo(long timeFrom, long timeTo)
|
||||||
|
{
|
||||||
|
return selectReps().and("timestamp >= ?", timeFrom).and(
|
||||||
|
"timestamp <= ?", timeTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasRep(long timestamp)
|
||||||
|
{
|
||||||
|
int count = selectReps().where("timestamp = ?", timestamp).count();
|
||||||
|
return (count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasRepToday()
|
||||||
|
{
|
||||||
|
return hasRep(DateHelper.getStartOfToday());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteReps(long timestamp)
|
||||||
|
{
|
||||||
|
new Delete().from(Repetition.class).where("habit = ?", getId())
|
||||||
|
.and("timestamp = ?", timestamp).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getReps(long timeFrom, long timeTo)
|
||||||
|
{
|
||||||
|
long timeFromExtended = timeFrom - (long) (freq_den) * DateHelper.millisecondsInOneDay;
|
||||||
|
List<Repetition> reps = selectRepsFromTo(timeFromExtended, timeTo).execute();
|
||||||
|
|
||||||
|
int nDaysExtended = (int) ((timeTo - timeFromExtended) / DateHelper.millisecondsInOneDay);
|
||||||
|
int checkExtended[] = new int[nDaysExtended + 1];
|
||||||
|
|
||||||
|
int nDays = (int) ((timeTo - timeFrom) / DateHelper.millisecondsInOneDay);
|
||||||
|
|
||||||
|
// mark explicit checks
|
||||||
|
for (Repetition rep : reps)
|
||||||
|
{
|
||||||
|
int offset = (int) ((rep.timestamp - timeFrom) / DateHelper.millisecondsInOneDay);
|
||||||
|
checkExtended[nDays - offset] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// marks implicit checks
|
||||||
|
for (int i = 0; i < nDays; i++)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < freq_den; j++)
|
||||||
|
if (checkExtended[i + j] == 2) counter++;
|
||||||
|
|
||||||
|
if (counter >= freq_num)
|
||||||
|
checkExtended[i] = Math.max(checkExtended[i], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int check[] = new int[nDays + 1];
|
||||||
|
for (int i = 0; i < nDays + 1; i++)
|
||||||
|
check[i] = checkExtended[i];
|
||||||
|
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasImplicitRepToday()
|
||||||
|
{
|
||||||
|
long today = DateHelper.getStartOfToday();
|
||||||
|
int reps[] = getReps(today - DateHelper.millisecondsInOneDay, today);
|
||||||
|
return (reps[0] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Repetition getOldestRep()
|
||||||
|
{
|
||||||
|
return (Repetition) selectReps().limit(1).executeSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleRepetition(long timestamp)
|
||||||
|
{
|
||||||
|
if (hasRep(timestamp))
|
||||||
|
{
|
||||||
|
deleteReps(timestamp);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Repetition rep = new Repetition();
|
||||||
|
rep.habit = this;
|
||||||
|
rep.timestamp = timestamp;
|
||||||
|
rep.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteScoresNewerThan(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleRepetitionToday()
|
||||||
|
{
|
||||||
|
toggleRepetition(DateHelper.getStartOfToday());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Score getNewestScore()
|
||||||
|
{
|
||||||
|
return new Select().from(Score.class).where("habit = ?", getId())
|
||||||
|
.orderBy("timestamp desc").limit(1).executeSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteScoresNewerThan(long timestamp)
|
||||||
|
{
|
||||||
|
new Delete().from(Score.class).where("habit = ?", getId())
|
||||||
|
.and("timestamp >= ?", timestamp).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getScore()
|
||||||
|
{
|
||||||
|
int beginningScore;
|
||||||
|
long beginningTime;
|
||||||
|
|
||||||
|
long today = DateHelper.getStartOfDay(DateHelper.getLocalTime());
|
||||||
|
long day = DateHelper.millisecondsInOneDay;
|
||||||
|
|
||||||
|
double freq = ((double) freq_num) / freq_den;
|
||||||
|
double multiplier = Math.pow(0.5, 1.0 / (14.0 / freq - 1));
|
||||||
|
|
||||||
|
Score newestScore = getNewestScore();
|
||||||
|
if (newestScore == null)
|
||||||
|
{
|
||||||
|
Repetition oldestRep = getOldestRep();
|
||||||
|
if (oldestRep == null)
|
||||||
|
return 0;
|
||||||
|
beginningTime = oldestRep.timestamp;
|
||||||
|
beginningScore = 0;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
beginningTime = newestScore.timestamp + day;
|
||||||
|
beginningScore = newestScore.score;
|
||||||
|
}
|
||||||
|
|
||||||
|
long nDays = (today - beginningTime) / day;
|
||||||
|
if (nDays < 0)
|
||||||
|
return newestScore.score;
|
||||||
|
|
||||||
|
int reps[] = getReps(beginningTime, today);
|
||||||
|
|
||||||
|
int lastScore = beginningScore;
|
||||||
|
for (int i = 0; i < reps.length; i++)
|
||||||
|
{
|
||||||
|
Score s = new Score();
|
||||||
|
s.habit = this;
|
||||||
|
s.timestamp = beginningTime + day * i;
|
||||||
|
s.score = (int) (lastScore * multiplier);
|
||||||
|
if (reps[reps.length - i - 1] == 2)
|
||||||
|
{
|
||||||
|
s.score += 1000000;
|
||||||
|
s.score = Math.min(s.score, 19259500);
|
||||||
|
}
|
||||||
|
s.save();
|
||||||
|
|
||||||
|
lastScore = s.score;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long[] getStreaks()
|
||||||
|
{
|
||||||
|
String query = "create temporary table T as select distinct r1.habit as habit, r1.timestamp as time,\n" +
|
||||||
|
" (select count(*) from repetitions r2 where r1.habit = r2.habit and\n" +
|
||||||
|
" (r1.timestamp = r2.timestamp - 24*60*60*1000 or\n" +
|
||||||
|
" r1.timestamp = r2.timestamp + 24*60*60*1000)) as neighbors\n" +
|
||||||
|
"from repetitions r1 where r1.habit = ?";
|
||||||
|
|
||||||
|
String query2 =
|
||||||
|
"select time from T, (select 0 union select 1) where neighbors = 0 union all\n" +
|
||||||
|
"select time from T where neighbors = 1 order by time;";
|
||||||
|
|
||||||
|
String args[] = {getId().toString()};
|
||||||
|
|
||||||
|
SQLiteDatabase db = Cache.openDatabase();
|
||||||
|
db.beginTransaction();
|
||||||
|
db.execSQL(query, args);
|
||||||
|
Cursor cursor = db.rawQuery(query2, null);
|
||||||
|
|
||||||
|
long streaks[] = new long[cursor.getCount()];
|
||||||
|
int current = 0;
|
||||||
|
|
||||||
|
Log.d("Streaks", String.format("%d rows", cursor.getCount()));
|
||||||
|
|
||||||
|
if (cursor.moveToFirst())
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
streaks[current++] = cursor.getLong(0);
|
||||||
|
} while (cursor.moveToNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
db.endTransaction();
|
||||||
|
return streaks;
|
||||||
|
}
|
||||||
|
|
||||||
public static class CreateCommand extends Command
|
public static class CreateCommand extends Command
|
||||||
{
|
{
|
||||||
@@ -79,8 +397,7 @@ public class Habit extends Model
|
|||||||
{
|
{
|
||||||
savedHabit.save();
|
savedHabit.save();
|
||||||
savedId = savedHabit.getId();
|
savedId = savedHabit.getId();
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
{
|
||||||
savedHabit.save(savedId);
|
savedHabit.save(savedId);
|
||||||
}
|
}
|
||||||
@@ -173,312 +490,4 @@ public class Habit extends Model
|
|||||||
execute();
|
execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
||||||
* Accessors *
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
public Habit(Habit model)
|
|
||||||
{
|
|
||||||
copyAttributes(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void copyAttributes(Habit model)
|
|
||||||
{
|
|
||||||
this.name = model.name;
|
|
||||||
this.description = model.description;
|
|
||||||
this.freq_num = model.freq_num;
|
|
||||||
this.freq_den = model.freq_den;
|
|
||||||
this.color = model.color;
|
|
||||||
this.position = model.position;
|
|
||||||
this.reminder_hour = model.reminder_hour;
|
|
||||||
this.reminder_min = model.reminder_min;
|
|
||||||
this.highlight = model.highlight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Habit()
|
|
||||||
{
|
|
||||||
this.color = ColorHelper.palette[11];
|
|
||||||
this.position = Habit.getCount();
|
|
||||||
this.highlight = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Habit get(Long id)
|
|
||||||
{
|
|
||||||
return Habit.load(Habit.class, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save(Long id)
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
Habit.updateId(getId(), id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
|
||||||
public static void updateId(long oldId, long newId)
|
|
||||||
{
|
|
||||||
SQLiteUtils.execSql(String.format(
|
|
||||||
"update Habits set Id = %d where Id = %d", newId, oldId));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static From select()
|
|
||||||
{
|
|
||||||
return new Select().from(Habit.class).orderBy("position");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getCount()
|
|
||||||
{
|
|
||||||
return select().count();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Habit getByPosition(int position)
|
|
||||||
{
|
|
||||||
return select().offset(position).executeSingle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static java.util.List<Habit> getHabits()
|
|
||||||
{
|
|
||||||
return select().execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static java.util.List<Habit> getHighlightedHabits()
|
|
||||||
{
|
|
||||||
return select().where("highlight = 1").orderBy("reminder_hour desc, reminder_min desc")
|
|
||||||
.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static java.util.List<Habit> getHabitsWithReminder()
|
|
||||||
{
|
|
||||||
return select().where("reminder_hour is not null").execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
||||||
* Repetitions *
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
protected From selectReps()
|
|
||||||
{
|
|
||||||
return new Select().from(Repetition.class).where("habit = ?", getId())
|
|
||||||
.orderBy("timestamp");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected From selectRepsFromTo(long timeFrom, long timeTo)
|
|
||||||
{
|
|
||||||
return selectReps().and("timestamp >= ?", timeFrom).and(
|
|
||||||
"timestamp <= ?", timeTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasRep(long timestamp)
|
|
||||||
{
|
|
||||||
int count = selectReps().where("timestamp = ?", timestamp).count();
|
|
||||||
return (count > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasRepToday()
|
|
||||||
{
|
|
||||||
return hasRep(DateHelper.getStartOfToday());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteReps(long timestamp)
|
|
||||||
{
|
|
||||||
new Delete().from(Repetition.class).where("habit = ?", getId())
|
|
||||||
.and("timestamp = ?", timestamp).execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getReps(long timeFrom, long timeTo)
|
|
||||||
{
|
|
||||||
long timeFromExtended = timeFrom - (long)(freq_den) * DateHelper.millisecondsInOneDay;
|
|
||||||
List<Repetition> reps = selectRepsFromTo(timeFromExtended, timeTo).execute();
|
|
||||||
|
|
||||||
int nDaysExtended = (int) ((timeTo - timeFromExtended) / DateHelper.millisecondsInOneDay);
|
|
||||||
int checkExtended[] = new int[nDaysExtended + 1];
|
|
||||||
|
|
||||||
int nDays = (int) ((timeTo - timeFrom) / DateHelper.millisecondsInOneDay);
|
|
||||||
|
|
||||||
// mark explicit checks
|
|
||||||
for (Repetition rep : reps)
|
|
||||||
{
|
|
||||||
int offset = (int) ((rep.timestamp - timeFrom) / DateHelper.millisecondsInOneDay);
|
|
||||||
checkExtended[nDays - offset] = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// marks implicit checks
|
|
||||||
for(int i=0; i<nDays; i++)
|
|
||||||
{
|
|
||||||
int counter = 0;
|
|
||||||
|
|
||||||
for(int j=0; j<freq_den; j++)
|
|
||||||
if(checkExtended[i+j] == 2) counter++;
|
|
||||||
|
|
||||||
if(counter >= freq_num)
|
|
||||||
checkExtended[i] = Math.max(checkExtended[i], 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int check[] = new int[nDays + 1];
|
|
||||||
for(int i=0; i<nDays+1; i++)
|
|
||||||
check[i] = checkExtended[i];
|
|
||||||
|
|
||||||
return check;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasImplicitRepToday()
|
|
||||||
{
|
|
||||||
long today = DateHelper.getStartOfToday();
|
|
||||||
int reps[] = getReps(today - DateHelper.millisecondsInOneDay, today);
|
|
||||||
return (reps[0] > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Repetition getOldestRep()
|
|
||||||
{
|
|
||||||
return (Repetition) selectReps().limit(1).executeSingle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleRepetition(long timestamp)
|
|
||||||
{
|
|
||||||
if(hasRep(timestamp))
|
|
||||||
{
|
|
||||||
deleteReps(timestamp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Repetition rep = new Repetition();
|
|
||||||
rep.habit = this;
|
|
||||||
rep.timestamp = timestamp;
|
|
||||||
rep.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteScoresNewerThan(timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleRepetitionToday()
|
|
||||||
{
|
|
||||||
toggleRepetition(DateHelper.getStartOfToday());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
||||||
* Scoring *
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
public Score getNewestScore()
|
|
||||||
{
|
|
||||||
return new Select().from(Score.class).where("habit = ?", getId())
|
|
||||||
.orderBy("timestamp desc").limit(1).executeSingle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteScoresNewerThan(long timestamp)
|
|
||||||
{
|
|
||||||
new Delete().from(Score.class).where("habit = ?", getId())
|
|
||||||
.and("timestamp >= ?", timestamp).execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getScore()
|
|
||||||
{
|
|
||||||
int beginningScore;
|
|
||||||
long beginningTime;
|
|
||||||
|
|
||||||
long today = DateHelper.getStartOfDay(DateHelper.getLocalTime());
|
|
||||||
long day = DateHelper.millisecondsInOneDay;
|
|
||||||
|
|
||||||
double freq = ((double) freq_num) / freq_den;
|
|
||||||
double multiplier = Math.pow(0.5, 1.0 / (14.0 / freq - 1));
|
|
||||||
|
|
||||||
Score newestScore = getNewestScore();
|
|
||||||
if(newestScore == null)
|
|
||||||
{
|
|
||||||
Repetition oldestRep = getOldestRep();
|
|
||||||
if(oldestRep == null)
|
|
||||||
return 0;
|
|
||||||
beginningTime = oldestRep.timestamp;
|
|
||||||
beginningScore = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
beginningTime = newestScore.timestamp + day;
|
|
||||||
beginningScore = newestScore.score;
|
|
||||||
}
|
|
||||||
|
|
||||||
long nDays = (today - beginningTime) / day;
|
|
||||||
if(nDays < 0)
|
|
||||||
return newestScore.score;
|
|
||||||
|
|
||||||
int reps[] = getReps(beginningTime, today);
|
|
||||||
|
|
||||||
int lastScore = beginningScore;
|
|
||||||
for (int i = 0; i < reps.length; i++)
|
|
||||||
{
|
|
||||||
Score s = new Score();
|
|
||||||
s.habit = this;
|
|
||||||
s.timestamp = beginningTime + day * i;
|
|
||||||
s.score = (int) (lastScore * multiplier);
|
|
||||||
if(reps[reps.length-i-1] == 2) {
|
|
||||||
s.score += 1000000;
|
|
||||||
s.score = Math.min(s.score, 19259500);
|
|
||||||
}
|
|
||||||
s.save();
|
|
||||||
|
|
||||||
lastScore = s.score;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastScore;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
||||||
* Ordering *
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
public static void reorder(int from, int to)
|
|
||||||
{
|
|
||||||
if(from == to)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Habit h = Habit.getByPosition(from);
|
|
||||||
if(to < from)
|
|
||||||
new Update(Habit.class).set("position = position + 1")
|
|
||||||
.where("position >= ? and position < ?", to, from)
|
|
||||||
.execute();
|
|
||||||
else
|
|
||||||
new Update(Habit.class).set("position = position - 1")
|
|
||||||
.where("position > ? and position <= ?", from, to)
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
h.position = to;
|
|
||||||
h.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void rebuildOrder()
|
|
||||||
{
|
|
||||||
List<Habit> habits = select().execute();
|
|
||||||
int i = 0;
|
|
||||||
for (Habit h : habits)
|
|
||||||
{
|
|
||||||
h.position = i++;
|
|
||||||
h.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void roundTimestamps()
|
|
||||||
{
|
|
||||||
List<Repetition> reps = new Select().from(Repetition.class).execute();
|
|
||||||
for (Repetition r : reps)
|
|
||||||
{
|
|
||||||
r.timestamp = DateHelper.getStartOfDay(r.timestamp);
|
|
||||||
r.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
||||||
* Statistics *
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
public static int getStarCount()
|
|
||||||
{
|
|
||||||
String args[] = {};
|
|
||||||
return SQLiteUtils.intQuery(
|
|
||||||
"select count(*) from (select score, max(timestamp) from " +
|
|
||||||
"score group by habit) as scores where scores.score >= "
|
|
||||||
+ Integer.toString(12973000), args);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ public class HabitHistoryView extends View
|
|||||||
private Context context;
|
private Context context;
|
||||||
private Paint pSquareBg, pSquareFg, pTextHeader;
|
private Paint pSquareBg, pSquareFg, pTextHeader;
|
||||||
|
|
||||||
private int width, height;
|
|
||||||
private int squareSize, squareSpacing;
|
private int squareSize, squareSpacing;
|
||||||
private int nColumns, offsetWeeks;
|
private int nColumns, offsetWeeks;
|
||||||
|
|
||||||
@@ -78,8 +77,6 @@ public class HabitHistoryView extends View
|
|||||||
@Override
|
@Override
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
||||||
{
|
{
|
||||||
width = w;
|
|
||||||
height = h;
|
|
||||||
nColumns = (w / squareSize) - 1;
|
nColumns = (w / squareSize) - 1;
|
||||||
fetchReps();
|
fetchReps();
|
||||||
}
|
}
|
||||||
|
|||||||
128
app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java
Normal file
128
app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
package org.isoron.uhabits.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.isoron.helpers.ColorHelper;
|
||||||
|
import org.isoron.helpers.DateHelper;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
|
public class HabitStreakView extends View
|
||||||
|
{
|
||||||
|
private Habit habit;
|
||||||
|
private int columnWidth, columnHeight, nColumns;
|
||||||
|
|
||||||
|
private Paint pText, pBar;
|
||||||
|
private long streaks[];
|
||||||
|
|
||||||
|
private long streakStart[], streakEnd[], streakLength[];
|
||||||
|
private long maxStreakLength;
|
||||||
|
|
||||||
|
private int barHeaderHeight;
|
||||||
|
|
||||||
|
private int[] colors;
|
||||||
|
|
||||||
|
public HabitStreakView(Context context, Habit habit, int columnWidth)
|
||||||
|
{
|
||||||
|
super(context);
|
||||||
|
this.habit = habit;
|
||||||
|
this.columnWidth = columnWidth;
|
||||||
|
|
||||||
|
pText = new Paint();
|
||||||
|
pText.setColor(Color.LTGRAY);
|
||||||
|
pText.setTextAlign(Paint.Align.CENTER);
|
||||||
|
pText.setTextSize(columnWidth * 0.5f);
|
||||||
|
pText.setAntiAlias(true);
|
||||||
|
|
||||||
|
pBar = new Paint();
|
||||||
|
pBar.setTextAlign(Paint.Align.CENTER);
|
||||||
|
pBar.setTextSize(columnWidth * 0.5f);
|
||||||
|
pBar.setAntiAlias(true);
|
||||||
|
|
||||||
|
columnHeight = 8 * columnWidth;
|
||||||
|
barHeaderHeight = columnWidth;
|
||||||
|
|
||||||
|
colors = new int[4];
|
||||||
|
|
||||||
|
colors[0] = Color.rgb(230, 230, 230);
|
||||||
|
colors[3] = habit.color;
|
||||||
|
colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f);
|
||||||
|
colors[2] = ColorHelper.mixColors(colors[0], colors[3], 0.33f);
|
||||||
|
|
||||||
|
fetchStreaks();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchStreaks()
|
||||||
|
{
|
||||||
|
streaks = habit.getStreaks();
|
||||||
|
streakStart = new long[streaks.length / 2];
|
||||||
|
streakEnd = new long[streaks.length / 2];
|
||||||
|
streakLength = new long[streaks.length / 2];
|
||||||
|
|
||||||
|
for(int i=0; i<streaks.length / 2; i++)
|
||||||
|
{
|
||||||
|
streakStart[i] = streaks[i * 2];
|
||||||
|
streakEnd[i] = streaks[i * 2 + 1];
|
||||||
|
streakLength[i] = (streakEnd[i] - streakStart[i]) / DateHelper.millisecondsInOneDay + 1;
|
||||||
|
maxStreakLength = Math.max(maxStreakLength, streakLength[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||||
|
{
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
setMeasuredDimension(getMeasuredWidth(), columnHeight + 2*barHeaderHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
||||||
|
{
|
||||||
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
nColumns = w / columnWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas)
|
||||||
|
{
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
float lineHeight = pText.getFontSpacing();
|
||||||
|
float barHeaderOffset = lineHeight * 0.4f;
|
||||||
|
|
||||||
|
int start = Math.max(0, streakStart.length - nColumns);
|
||||||
|
SimpleDateFormat dfMonth = new SimpleDateFormat("MMM");
|
||||||
|
|
||||||
|
String previousMonth = "";
|
||||||
|
|
||||||
|
for (int offset = 0; offset < nColumns && start+offset < streakStart.length; offset++)
|
||||||
|
{
|
||||||
|
String month = dfMonth.format(streakStart[start+offset]);
|
||||||
|
|
||||||
|
long l = streakLength[offset+start];
|
||||||
|
double lRelative = ((double) l) / maxStreakLength;
|
||||||
|
|
||||||
|
pBar.setColor(colors[(int) Math.floor(lRelative*3)]);
|
||||||
|
|
||||||
|
int height = (int) (columnHeight * lRelative);
|
||||||
|
Rect r = new Rect(0,0,columnWidth-2, height);
|
||||||
|
r.offset(offset * columnWidth, barHeaderHeight + columnHeight - height);
|
||||||
|
|
||||||
|
canvas.drawRect(r, pBar);
|
||||||
|
canvas.drawText(Long.toString(streakLength[offset+start]), r.centerX(), r.top - barHeaderOffset, pBar);
|
||||||
|
|
||||||
|
if(!month.equals(previousMonth))
|
||||||
|
canvas.drawText(month, r.centerX(), r.bottom + lineHeight * 1.2f, pText);
|
||||||
|
|
||||||
|
previousMonth = month;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
67
app/src/main/java/org/isoron/uhabits/views/RingView.java
Normal file
67
app/src/main/java/org/isoron/uhabits/views/RingView.java
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package org.isoron.uhabits.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
public class RingView extends View
|
||||||
|
{
|
||||||
|
|
||||||
|
private int size;
|
||||||
|
private int color;
|
||||||
|
private float perc;
|
||||||
|
private Paint pRing;
|
||||||
|
private float lineHeight;
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
public RingView(Context context, int size, int color, float perc, String label)
|
||||||
|
{
|
||||||
|
super(context);
|
||||||
|
this.size = size;
|
||||||
|
this.color = color;
|
||||||
|
this.perc = perc;
|
||||||
|
|
||||||
|
pRing = new Paint();
|
||||||
|
pRing.setColor(color);
|
||||||
|
pRing.setAntiAlias(true);
|
||||||
|
pRing.setTextAlign(Paint.Align.CENTER);
|
||||||
|
pRing.setTextSize(size * 0.15f);
|
||||||
|
|
||||||
|
this.label = label;
|
||||||
|
|
||||||
|
lineHeight = pRing.getFontSpacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||||
|
{
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
setMeasuredDimension(size, size + (int) (2*lineHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas)
|
||||||
|
{
|
||||||
|
super.onDraw(canvas);
|
||||||
|
float thickness = size * 0.15f;
|
||||||
|
|
||||||
|
pRing.setColor(color);
|
||||||
|
RectF r = new RectF(0, 0, size, size);
|
||||||
|
canvas.drawArc(r, -90, 360 * perc, true, pRing);
|
||||||
|
|
||||||
|
|
||||||
|
pRing.setColor(Color.rgb(230, 230, 230));
|
||||||
|
canvas.drawArc(r, 360 * perc - 90 + 2, 360 * (1-perc) - 4, true, pRing);
|
||||||
|
|
||||||
|
pRing.setColor(Color.WHITE);
|
||||||
|
r.inset(thickness, thickness);
|
||||||
|
canvas.drawArc(r, -90, 360, true, pRing);
|
||||||
|
|
||||||
|
pRing.setColor(Color.GRAY);
|
||||||
|
canvas.drawText(String.format("%.2f%%", perc*100), r.centerX(), r.centerY()+lineHeight/3, pRing);
|
||||||
|
canvas.drawText(label, size/2, size + lineHeight * 1.2f, pRing);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
app/src/main/res/drawable/card_background.xml
Normal file
39
app/src/main/res/drawable/card_background.xml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:top="0dp"
|
||||||
|
android:bottom="0dp"
|
||||||
|
android:left="0dp"
|
||||||
|
android:right="0dp">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="#d6d6d6" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="0dp"
|
||||||
|
android:bottom="1dp"
|
||||||
|
android:left="0dp"
|
||||||
|
android:right="0dp">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="#c0c0c0" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="0dp"
|
||||||
|
android:bottom="1.5dp"
|
||||||
|
android:left="0dp"
|
||||||
|
android:right="0dp">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="#d6d6d6"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="0.5dp"
|
||||||
|
android:bottom="1.5dp"
|
||||||
|
android:left="0.5dp"
|
||||||
|
android:right="0.5dp">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="@color/white"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
26
app/src/main/res/drawable/habits_list_header_background.xml
Normal file
26
app/src/main/res/drawable/habits_list_header_background.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<item android:top="40dp">
|
||||||
|
<shape android:shape="rectangle" >
|
||||||
|
<gradient
|
||||||
|
android:startColor="#30000000"
|
||||||
|
android:endColor="#00000000"
|
||||||
|
android:angle="270"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:top="21dp" android:bottom="2dp">
|
||||||
|
<shape android:shape="rectangle" >
|
||||||
|
<gradient
|
||||||
|
android:angle="270"
|
||||||
|
android:endColor="#ccffffff"
|
||||||
|
android:startColor="#ffffff" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:bottom="21dp">
|
||||||
|
<shape android:shape="rectangle" >
|
||||||
|
<solid android:color="#ffffff" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:minHeight="48dp"
|
android:minHeight="48dp"
|
||||||
android:text="Clear"
|
android:text="@string/clear"
|
||||||
android:textSize="@dimen/done_label_size"
|
android:textSize="@dimen/done_label_size"
|
||||||
android:textColor="@color/done_text_color" />
|
android:textColor="@color/done_text_color" />
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/input_description"
|
android:id="@+id/input_description"
|
||||||
android:hint="Description"
|
android:hint="@string/description"
|
||||||
style="@style/dialogFormInputMultiline" />
|
style="@style/dialogFormInputMultiline" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -39,29 +39,29 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textView1"
|
android:id="@+id/textView1"
|
||||||
style="@style/dialogFormLabel"
|
style="@style/dialogFormLabel"
|
||||||
android:text="Repeat " />
|
android:text="@string/repeat" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/input_freq_num"
|
android:id="@+id/input_freq_num"
|
||||||
android:text="3"
|
android:text="@string/default_freq_num"
|
||||||
style="@style/dialogFormInputSmallNumber" />
|
style="@style/dialogFormInputSmallNumber" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textView3"
|
android:id="@+id/textView3"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text=" times every " />
|
android:text="@string/times_every" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/input_freq_den"
|
android:id="@+id/input_freq_den"
|
||||||
android:text="7"
|
android:text="@string/default_freq_den"
|
||||||
style="@style/dialogFormInputSmallNumber" />
|
style="@style/dialogFormInputSmallNumber" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textView5"
|
android:id="@+id/textView5"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text=" days" />
|
android:text="@string/days" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/TextView2"
|
android:id="@+id/TextView2"
|
||||||
style="@style/dialogFormLabel"
|
style="@style/dialogFormLabel"
|
||||||
android:text="Reminder" />
|
android:text="@string/reminder" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/input_reminder_time"
|
android:id="@+id/input_reminder_time"
|
||||||
@@ -85,7 +85,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:onClick="onClick"
|
|
||||||
android:paddingEnd="16dp">
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@@ -93,13 +92,13 @@
|
|||||||
style="?android:attr/buttonBarButtonStyle"
|
style="?android:attr/buttonBarButtonStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Discard" />
|
android:text="@string/discard" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/buttonSave"
|
android:id="@+id/buttonSave"
|
||||||
style="?android:attr/buttonBarButtonStyle"
|
style="?android:attr/buttonBarButtonStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Save" />
|
android:text="@string/save" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -14,7 +14,8 @@
|
|||||||
dslv:float_alpha="0.5"
|
dslv:float_alpha="0.5"
|
||||||
dslv:sort_enabled="true"
|
dslv:sort_enabled="true"
|
||||||
dslv:track_drag_sort="false"
|
dslv:track_drag_sort="false"
|
||||||
dslv:use_default_controller="true" />
|
dslv:use_default_controller="true"
|
||||||
|
/>
|
||||||
|
|
||||||
<LinearLayout style="@style/habitsListHeaderStyle">
|
<LinearLayout style="@style/habitsListHeaderStyle">
|
||||||
|
|
||||||
|
|||||||
@@ -2,31 +2,20 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fillViewport="true">
|
android:fillViewport="true"
|
||||||
|
android:background="@color/windowBackground">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
style="@style/cardsListStyle"
|
style="@style/cardsListStyle"
|
||||||
tools:context="org.isoron.uhabits.ShowHabitActivity">
|
tools:context="org.isoron.uhabits.ShowHabitActivity">
|
||||||
|
|
||||||
<LinearLayout style="@style/cardStyle">
|
<LinearLayout style="@style/cardStyle"
|
||||||
|
android:id="@+id/llOverview">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvOverview"
|
android:id="@+id/tvOverview"
|
||||||
style="@style/cardHeaderStyle"
|
style="@style/cardHeaderStyle"
|
||||||
android:text="Overview" />
|
android:text="@string/overview" />
|
||||||
|
|
||||||
<LinearLayout style="@style/cardRowStyle">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/cardLabelStyle"
|
|
||||||
android:text="Habit strength" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvStrength"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -35,7 +24,7 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvHistory"
|
android:id="@+id/tvHistory"
|
||||||
style="@style/cardHeaderStyle"
|
style="@style/cardHeaderStyle"
|
||||||
android:text="History" />
|
android:text="@string/history" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/llHistory"
|
android:id="@+id/llHistory"
|
||||||
@@ -43,5 +32,19 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal" />
|
android:orientation="horizontal" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout style="@style/cardStyle">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvStreaks"
|
||||||
|
style="@style/cardHeaderStyle"
|
||||||
|
android:text="@string/streaks" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llStreaks"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
@@ -14,4 +14,19 @@
|
|||||||
<style name="MyDialogStyle" parent="android:Theme.Material.Light.Dialog">
|
<style name="MyDialogStyle" parent="android:Theme.Material.Light.Dialog">
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="cardStyle">
|
||||||
|
<item name="android:layout_width">match_parent</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:background">@color/white</item>
|
||||||
|
<item name="android:elevation">1dp</item>
|
||||||
|
<item name="android:orientation">vertical</item>
|
||||||
|
<item name="android:paddingTop">16dp</item>
|
||||||
|
<item name="android:paddingBottom">16dp</item>
|
||||||
|
<item name="android:paddingLeft">16dp</item>
|
||||||
|
<item name="android:paddingRight">4dp</item>
|
||||||
|
<item name="android:layout_marginBottom">3dp</item>
|
||||||
|
<item name="android:layout_marginLeft">3dp</item>
|
||||||
|
<item name="android:layout_marginRight">3dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
20
app/src/main/res/values-v21/styles_list_habits.xml
Normal file
20
app/src/main/res/values-v21/styles_list_habits.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="habitsListHeaderStyle">
|
||||||
|
<item name="android:layout_width">match_parent</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:layout_alignParentTop">true</item>
|
||||||
|
<item name="android:background">#f0f0f0</item>
|
||||||
|
<item name="android:elevation">2dp</item>
|
||||||
|
<item name="android:paddingRight">4dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="habitsListCheckStyle">
|
||||||
|
<item name="android:focusable">false</item>
|
||||||
|
<item name="android:minHeight">42dp</item>
|
||||||
|
<item name="android:minWidth">42dp</item>
|
||||||
|
<item name="android:gravity">center</item>
|
||||||
|
<item name="android:background">@drawable/ripple_background</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="square_size">20dp</dimen>
|
||||||
|
|
||||||
<!-- Color picker -->
|
<!-- Color picker -->
|
||||||
<dimen name="color_swatch_large">64dip</dimen>
|
<dimen name="color_swatch_large">64dip</dimen>
|
||||||
<dimen name="color_swatch_small">48dip</dimen>
|
<dimen name="color_swatch_small">48dip</dimen>
|
||||||
|
|||||||
@@ -42,5 +42,19 @@
|
|||||||
|
|
||||||
<string name="title_activity_show_habit">ShowHabitActivity</string>
|
<string name="title_activity_show_habit">ShowHabitActivity</string>
|
||||||
<string name="hello_world">Hello world!</string>
|
<string name="hello_world">Hello world!</string>
|
||||||
|
<string name="overview">Overview</string>
|
||||||
|
<string name="habit_strength">Habit strength</string>
|
||||||
|
<string name="history">History</string>
|
||||||
|
<string name="clear">Clear</string>
|
||||||
|
<string name="description">Description</string>
|
||||||
|
<string name="repeat">Repeat</string>
|
||||||
|
<string name="default_freq_num">3</string>
|
||||||
|
<string name="times_every">times every</string>
|
||||||
|
<string name="default_freq_den">7</string>
|
||||||
|
<string name="days">days</string>
|
||||||
|
<string name="reminder">Reminder</string>
|
||||||
|
<string name="discard">Discard</string>
|
||||||
|
<string name="save">Save</string>
|
||||||
|
<string name="streaks">Streaks</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -28,14 +28,13 @@
|
|||||||
<style name="cardStyle">
|
<style name="cardStyle">
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
<item name="android:layout_height">wrap_content</item>
|
<item name="android:layout_height">wrap_content</item>
|
||||||
<item name="android:background">@color/white</item>
|
<item name="android:background">@drawable/card_background</item>
|
||||||
<item name="android:elevation">1dp</item>
|
|
||||||
<item name="android:orientation">vertical</item>
|
<item name="android:orientation">vertical</item>
|
||||||
<item name="android:paddingTop">16dp</item>
|
<item name="android:paddingTop">16dp</item>
|
||||||
<item name="android:paddingBottom">16dp</item>
|
<item name="android:paddingBottom">16dp</item>
|
||||||
<item name="android:paddingLeft">16dp</item>
|
<item name="android:paddingLeft">16dp</item>
|
||||||
<item name="android:paddingRight">4dp</item>
|
<item name="android:paddingRight">4dp</item>
|
||||||
<item name="android:layout_marginBottom">3dp</item>
|
<item name="android:layout_marginBottom">1dp</item>
|
||||||
<item name="android:layout_marginLeft">3dp</item>
|
<item name="android:layout_marginLeft">3dp</item>
|
||||||
<item name="android:layout_marginRight">3dp</item>
|
<item name="android:layout_marginRight">3dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -14,9 +14,8 @@
|
|||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
<item name="android:layout_height">wrap_content</item>
|
<item name="android:layout_height">wrap_content</item>
|
||||||
<item name="android:layout_alignParentTop">true</item>
|
<item name="android:layout_alignParentTop">true</item>
|
||||||
<item name="android:background">#f0f0f0</item>
|
|
||||||
<item name="android:elevation">2dp</item>
|
|
||||||
<item name="android:paddingRight">4dp</item>
|
<item name="android:paddingRight">4dp</item>
|
||||||
|
<item name="android:background">@drawable/habits_list_header_background</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="habitsListStarStyle">
|
<style name="habitsListStarStyle">
|
||||||
@@ -64,13 +63,12 @@
|
|||||||
<item name="android:minHeight">42dp</item>
|
<item name="android:minHeight">42dp</item>
|
||||||
<item name="android:minWidth">42dp</item>
|
<item name="android:minWidth">42dp</item>
|
||||||
<item name="android:gravity">center</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:background">@drawable/ripple_background</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="habitsListHeaderCheckStyle" parent="habitsListCheckStyle">
|
<style name="habitsListHeaderCheckStyle" parent="habitsListCheckStyle">
|
||||||
<item name="android:layout_width">42dp</item>
|
<item name="android:layout_width">42dp</item>
|
||||||
<item name="android:layout_height">match_parent</item>
|
<item name="android:layout_height">match_parent</item>
|
||||||
<item name="android:background">#f0f0f0</item>
|
<item name="android:background">@color/transparent</item>
|
||||||
<item name="android:focusable">false</item>
|
<item name="android:focusable">false</item>
|
||||||
<item name="android:textSize">10sp</item>
|
<item name="android:textSize">10sp</item>
|
||||||
<item name="android:textColor">#606060</item>
|
<item name="android:textColor">#606060</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user