Reorganizing

pull/30/head
Alinson S. Xavier 10 years ago
parent a1f05714ba
commit de02e119d1

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="uHabits" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> <module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$USER_HOME$/Android/uHabits" external.system.id="GRADLE" external.system.module.group="uHabits" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle"> <facet type="android-gradle" name="Android-Gradle">
<configuration> <configuration>
@ -12,8 +12,9 @@
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" /> <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" /> <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" /> <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" /> <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" /> <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
<option name="ALLOW_USER_CONFIGURATION" value="false" /> <option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
@ -90,4 +91,3 @@
<orderEntry type="library" exported="" name="support-annotations-22.0.0" level="project" /> <orderEntry type="library" exported="" name="support-annotations-22.0.0" level="project" />
</component> </component>
</module> </module>

@ -14,7 +14,7 @@
<application <application
android:name="com.activeandroid.app.Application" android:name="com.activeandroid.app.Application"
android:allowBackup="true" android:allowBackup="true"
android:icon="@drawable/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

@ -6,6 +6,7 @@ import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
@ -125,25 +126,24 @@ public class MainActivity extends Activity
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
public void executeCommand(Command command, boolean datasetChanged) public void executeCommand(Command command)
{ {
executeCommand(command, datasetChanged, true); executeCommand(command, false);
} }
public void executeCommand(Command command, boolean datasetChanged, boolean clearRedoStack)
public void executeCommand(Command command, boolean clearRedoStack)
{ {
undoList.push(command); undoList.push(command);
if (undoList.size() > MAX_UNDO_LEVEL) if (undoList.size() > MAX_UNDO_LEVEL)
undoList.removeLast(); undoList.removeLast();
if (clearRedoStack) if (clearRedoStack)
redoList.clear(); redoList.clear();
command.execute(); command.execute();
listHabitsFragment.notifyDataSetChanged();
showToast(command.getExecuteStringId()); showToast(command.getExecuteStringId());
if (datasetChanged)
{
listHabitsFragment.notifyDataSetChanged();
}
} }
public void undo() public void undo()
@ -170,7 +170,7 @@ public class MainActivity extends Activity
return; return;
} }
Command last = redoList.pop(); Command last = redoList.pop();
executeCommand(last, true, false); executeCommand(last, false);
} }
private void showToast(Integer stringId) private void showToast(Integer stringId)

@ -1,12 +1,6 @@
package org.isoron.uhabits; package org.isoron.uhabits;
import java.util.Date;
import java.util.List;
import org.isoron.uhabits.models.Habit;
import android.app.Activity; import android.app.Activity;
import android.app.AlarmManager;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
@ -14,11 +8,16 @@ import android.content.BroadcastReceiver;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager; import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.util.Log; import android.util.Log;
import org.isoron.uhabits.models.Habit;
import java.util.Date;
public class ReminderAlarmReceiver extends BroadcastReceiver public class ReminderAlarmReceiver extends BroadcastReceiver
{ {
@ -33,25 +32,22 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
{ {
String action = intent.getAction(); String action = intent.getAction();
if(action.equals(ACTION_REMIND)) if (action.equals(ACTION_REMIND)) createNotification(context, intent.getData());
createNotification(context, intent.getData());
else if(action.equals(ACTION_DISMISS)) else if (action.equals(ACTION_DISMISS)) dismissAllHabits();
dismissAllHabits();
else if(action.equals(ACTION_CHECK)) else if (action.equals(ACTION_CHECK)) checkHabit(context, intent.getData());
checkHabit(context, intent.getData());
else if(action.equals(ACTION_SNOOZE)) else if (action.equals(ACTION_SNOOZE)) snoozeHabit(context, intent.getData());
snoozeHabit(context, intent.getData());
} }
private void snoozeHabit(Context context, Uri data) private void snoozeHabit(Context context, Uri data)
{ {
int delayMinutes = 15; int delayMinutes = 60;
Habit habit = Habit.get(ContentUris.parseId(data)); Habit habit = Habit.get(ContentUris.parseId(data));
MainActivity.createReminderAlarm(context, habit, new Date().getTime() + delayMinutes * 1000); MainActivity.createReminderAlarm(context, habit,
dismissNotification(context); new Date().getTime() + delayMinutes * 60 * 1000);
dismissNotification(context, habit);
} }
private void checkHabit(Context context, Uri data) private void checkHabit(Context context, Uri data)
@ -59,51 +55,46 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
Habit habit = Habit.get(ContentUris.parseId(data)); Habit habit = Habit.get(ContentUris.parseId(data));
habit.toggleRepetitionToday(); habit.toggleRepetitionToday();
habit.save(); habit.save();
dismissNotification(context); dismissNotification(context, habit);
} }
private void dismissAllHabits() private void dismissAllHabits()
{ {
for(Habit h : Habit.getHighlightedHabits()) for (Habit h : Habit.getHighlightedHabits())
{ {
Log.d("Alarm", String.format("Removing highlight from: %s", h.name));
h.highlight = 0; h.highlight = 0;
h.save(); h.save();
} }
} }
private void dismissNotification(Context context) private void dismissNotification(Context context, Habit habit)
{ {
NotificationManager notificationManager = (NotificationManager) context NotificationManager notificationManager =
.getSystemService(Activity.NOTIFICATION_SERVICE); (NotificationManager) context.getSystemService(Activity.NOTIFICATION_SERVICE);
notificationManager.cancel(1); int notificationId = (int) (habit.getId() % Integer.MAX_VALUE);
notificationManager.cancel(notificationId);
} }
private void createNotification(Context context, Uri data) private void createNotification(Context context, Uri data)
{ {
Log.d("Alarm", "Alarm received!");
Habit habit = Habit.get(ContentUris.parseId(data)); Habit habit = Habit.get(ContentUris.parseId(data));
if(habit.hasImplicitRepToday()) if (habit.hasImplicitRepToday()) return;
{
Log.d("Alarm", String.format("(%s) has implicit rep today", habit.name));
return;
}
Log.d("Alarm", String.format("Applying highlight: %s", habit.name)); Log.d("Alarm", String.format("Applying highlight: %s", habit.name));
habit.highlight = 1; habit.highlight = 1;
habit.save(); habit.save();
// Check if reminder has been turned off after alarm was scheduled // Check if reminder has been turned off after alarm was scheduled
if(habit.reminder_hour == null) if (habit.reminder_hour == null) return;
return;
Intent contentIntent = new Intent(context, MainActivity.class); Intent contentIntent = new Intent(context, MainActivity.class);
contentIntent.setData(data); contentIntent.setData(data);
PendingIntent contentPendingIntent = PendingIntent.getActivity(context, 0, contentIntent, 0); PendingIntent contentPendingIntent =
PendingIntent.getActivity(context, 0, contentIntent, 0);
Intent deleteIntent = new Intent(context, ReminderAlarmReceiver.class); Intent deleteIntent = new Intent(context, ReminderAlarmReceiver.class);
deleteIntent.setAction(ACTION_DISMISS); deleteIntent.setAction(ACTION_DISMISS);
@ -121,41 +112,29 @@ public class ReminderAlarmReceiver extends BroadcastReceiver
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); NotificationCompat.WearableExtender wearableExtender =
inboxStyle.setBigContentTitle("Habit Reminder:"); new NotificationCompat.WearableExtender().setBackground(
List<Habit> pendingHabits = Habit.getHighlightedHabits(); BitmapFactory.decodeResource(context.getResources(), R.drawable.stripe));
StringBuffer contentText = new StringBuffer();
for(Habit h : pendingHabits)
{
if(h.hasImplicitRepToday())
continue;
inboxStyle.addLine(h.name);
if(contentText.length() > 0)
contentText.append(", ");
contentText.append(h.name);
Log.d("Alarm", String.format("Found highlighted: %s", h.name));
}
Notification notification = Notification notification =
new NotificationCompat.Builder(context) new NotificationCompat.Builder(context).setSmallIcon(R.drawable.ic_notification)
.setSmallIcon(R.drawable.ic_notification) .setContentTitle(habit.name)
.setContentTitle("Habit Reminder") .setContentText(habit.description)
.setContentText(contentText)
.setContentIntent(contentPendingIntent) .setContentIntent(contentPendingIntent)
.setDeleteIntent(deletePendingIntent) .setDeleteIntent(deletePendingIntent)
.addAction(R.drawable.ic_action_check, "Check", checkIntentPending) .addAction(R.drawable.ic_action_check, "Check", checkIntentPending)
.addAction(R.drawable.ic_action_snooze, "Later", snoozeIntentPending) .addAction(R.drawable.ic_action_snooze, "Later", snoozeIntentPending)
.setSound(soundUri) .setSound(soundUri)
.setStyle(inboxStyle) .extend(wearableExtender)
.build(); .build();
notification.flags |= Notification.FLAG_AUTO_CANCEL; notification.flags |= Notification.FLAG_AUTO_CANCEL;
NotificationManager notificationManager = (NotificationManager) context NotificationManager notificationManager =
.getSystemService(Activity.NOTIFICATION_SERVICE); (NotificationManager) context.getSystemService(Activity.NOTIFICATION_SERVICE);
notificationManager.notify(1, notification); int notificationId = (int) (habit.getId() % Integer.MAX_VALUE);
notificationManager.notify(notificationId, notification);
} }
} }

@ -1,18 +1,5 @@
package org.isoron.uhabits.dialogs; package org.isoron.uhabits.dialogs;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
import org.isoron.helpers.Command;
import org.isoron.helpers.DateHelper;
import org.isoron.helpers.DialogHelper.OnSavedListener;
import org.isoron.uhabits.MainActivity;
import org.isoron.uhabits.R;
import org.isoron.uhabits.ShowHabitActivity;
import org.isoron.uhabits.models.Habit;
import android.app.Fragment; import android.app.Fragment;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -20,9 +7,9 @@ import android.graphics.Color;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.Vibrator; import android.os.Vibrator;
import android.transition.Explode;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
@ -50,176 +37,32 @@ import com.mobeta.android.dslv.DragSortController;
import com.mobeta.android.dslv.DragSortListView; import com.mobeta.android.dslv.DragSortListView;
import com.mobeta.android.dslv.DragSortListView.DropListener; import com.mobeta.android.dslv.DragSortListView.DropListener;
public class ListHabitsFragment extends Fragment implements OnSavedListener, OnItemClickListener, import org.isoron.helpers.Command;
OnLongClickListener, DropListener, OnClickListener import org.isoron.helpers.DateHelper;
import org.isoron.helpers.DialogHelper.OnSavedListener;
import org.isoron.uhabits.MainActivity;
import org.isoron.uhabits.R;
import org.isoron.uhabits.ShowHabitActivity;
import org.isoron.uhabits.models.Habit;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
public class ListHabitsFragment extends Fragment
implements OnSavedListener, OnItemClickListener, OnLongClickListener, DropListener,
OnClickListener
{ {
private int tvNameWidth;
private int button_count;
ListHabitsAdapter adapter; ListHabitsAdapter adapter;
DragSortListView listView; DragSortListView listView;
MainActivity mainActivity; MainActivity mainActivity;
TextView tvNameHeader; TextView tvNameHeader;
long lastLongClick = 0;
private int tvNameWidth;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * private int button_count;
* Adapter *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
class ListHabitsAdapter extends BaseAdapter
{
private Context context;
private LayoutInflater inflater;
private Typeface fontawesome;
String habits[] = { "wake up early", "work out", "meditate", "take vitamins",
"go to school",
"cook dinner & lunch" };
public ListHabitsAdapter(Context context)
{
this.context = context;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
fontawesome = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
}
@Override
public int getCount()
{
return Habit.getCount();
}
@Override
public Object getItem(int position)
{
return Habit.getByPosition(position);
}
@Override
public long getItemId(int position)
{
return ((Habit) getItem(position)).getId();
}
@Override
public View getView(int position, View view, ViewGroup parent)
{
final Habit habit = (Habit) getItem(position);
if(view == null || (Long) view.getTag(R.id.KEY_TIMESTAMP) != DateHelper.getStartOfToday())
{
view = inflater.inflate(R.layout.list_habits_item, null);
((TextView) view.findViewById(R.id.tvStar)).setTypeface(fontawesome);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(tvNameWidth,
LayoutParams.WRAP_CONTENT, 1);
((TextView) view.findViewById(R.id.tvName)).setLayoutParams(params);
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
llp.setMargins(2, 0, 2, 0);
for (int i = 0; i < button_count; i++)
{
View check = inflater.inflate(R.layout.list_habits_item_check, null);
TextView btCheck = (TextView) check.findViewById(R.id.tvCheck);
btCheck.setTypeface(fontawesome);
btCheck.setOnLongClickListener(ListHabitsFragment.this);
// btCheck.setLayoutParams(llp);
((LinearLayout) view.findViewById(R.id.llButtons)).addView(check);
}
// LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner);
// llInner.setOnClickListener(ListHabitsFragment.this);
view.setTag(R.id.KEY_TIMESTAMP, DateHelper.getStartOfToday());
}
TextView tvStar = (TextView) view.findViewById(R.id.tvStar);
TextView tvName = (TextView) view.findViewById(R.id.tvName);
if(habit == null)
{
tvName.setText(null);
return view;
}
LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner);
llInner.setTag(R.string.habit_key, habit.getId());
int inactiveColor = Color.rgb(230, 230, 230);
int activeColor = habit.color;
tvName.setText(habit.name);
tvName.setTextColor(activeColor);
int score = habit.getScore();
if(score < Habit.HALF_STAR_CUTOFF)
{
tvStar.setText(context.getString(R.string.fa_star_o));
tvStar.setTextColor(inactiveColor);
}
else if(score < Habit.FULL_STAR_CUTOFF)
{
tvStar.setText(context.getString(R.string.fa_star_half_o));
tvStar.setTextColor(inactiveColor);
}
else
{
tvStar.setText(context.getString(R.string.fa_star));
tvStar.setTextColor(activeColor);
}
LinearLayout llButtons = (LinearLayout) view.findViewById(R.id.llButtons);
int m = llButtons.getChildCount();
long dateTo = DateHelper.getStartOfDay(DateHelper.getLocalTime());
long dateFrom = dateTo - m * DateHelper.millisecondsInOneDay;
int isChecked[] = habit.getReps(dateFrom, dateTo);
for (int i = 0; i < m; i++)
{
TextView tvCheck = (TextView) llButtons.getChildAt(i);
tvCheck.setTag(R.string.habit_key, habit.getId());
tvCheck.setTag(R.string.offset_key, i);
switch(isChecked[i])
{
case 2:
tvCheck.setText(R.string.fa_check);
tvCheck.setTextColor(activeColor);
break;
case 1:
tvCheck.setText(R.string.fa_check);
tvCheck.setTextColor(inactiveColor);
break;
case 0:
tvCheck.setText(R.string.fa_times);
tvCheck.setTextColor(inactiveColor);
break;
}
}
return view;
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Creation *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
@ -259,9 +102,10 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnI
{ {
View check = inflater.inflate(R.layout.list_habits_header_check, null); View check = inflater.inflate(R.layout.list_habits_header_check, null);
Button btCheck = (Button) check.findViewById(R.id.tvCheck); Button btCheck = (Button) check.findViewById(R.id.tvCheck);
btCheck.setText(day.getDisplayName(GregorianCalendar.DAY_OF_WEEK, btCheck.setText(
GregorianCalendar.SHORT, Locale.US) + "\n" day.getDisplayName(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.SHORT,
+ Integer.toString(day.get(GregorianCalendar.DAY_OF_MONTH))); Locale.US) + "\n" +
Integer.toString(day.get(GregorianCalendar.DAY_OF_MONTH)));
((LinearLayout) view.findViewById(R.id.llButtonsHeader)).addView(check); ((LinearLayout) view.findViewById(R.id.llButtonsHeader)).addView(check);
day.add(GregorianCalendar.DAY_OF_MONTH, -1); day.add(GregorianCalendar.DAY_OF_MONTH, -1);
@ -287,16 +131,12 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnI
getActivity().getMenuInflater().inflate(R.menu.show_habits_context, menu); getActivity().getMenuInflater().inflate(R.menu.show_habits_context, menu);
} }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Callback *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) public boolean onOptionsItemSelected(MenuItem item)
{ {
int id = item.getItemId(); int id = item.getItemId();
if(id == R.id.action_add) if (id == R.id.action_add)
{ {
EditHabitFragment frag = EditHabitFragment.createHabitFragment(); EditHabitFragment frag = EditHabitFragment.createHabitFragment();
frag.setOnSavedListener(this); frag.setOnSavedListener(this);
@ -314,7 +154,7 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnI
final int id = menuItem.getItemId(); final int id = menuItem.getItemId();
final Habit habit = Habit.get(info.id); final Habit habit = Habit.get(info.id);
if(id == R.id.action_edit_habit) if (id == R.id.action_edit_habit)
{ {
EditHabitFragment frag = EditHabitFragment.editSingleHabitFragment(habit.getId()); EditHabitFragment frag = EditHabitFragment.editSingleHabitFragment(habit.getId());
frag.setOnSavedListener(this); frag.setOnSavedListener(this);
@ -325,19 +165,16 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnI
return super.onContextItemSelected(menuItem); return super.onContextItemSelected(menuItem);
} }
long lastLongClick = 0;
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{ {
if(new Date().getTime() - lastLongClick < 1000) return; if (new Date().getTime() - lastLongClick < 1000) return;
Habit habit = Habit.getByPosition(position); Habit habit = Habit.getByPosition(position);
Log.d("ItemClick", Long.toString(id)); Log.d("ItemClick", Long.toString(id));
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()));
startActivity(intent); startActivity(intent);
} }
@ -358,13 +195,13 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnI
{ {
int id = v.getId(); int id = v.getId();
if(id == R.id.tvCheck) if (id == R.id.tvCheck)
{ {
lastLongClick = new Date().getTime(); lastLongClick = new Date().getTime();
Habit habit = Habit.get((Long) v.getTag(R.string.habit_key)); Habit habit = Habit.get((Long) v.getTag(R.string.habit_key));
int offset = (Integer) v.getTag(R.string.offset_key); int offset = (Integer) v.getTag(R.string.offset_key);
long timestamp = DateHelper.getStartOfDay(DateHelper.getLocalTime() - offset long timestamp = DateHelper.getStartOfDay(
* DateHelper.millisecondsInOneDay); DateHelper.getLocalTime() - offset * DateHelper.millisecondsInOneDay);
executeCommand(habit.new ToggleRepetitionCommand(timestamp)); executeCommand(habit.new ToggleRepetitionCommand(timestamp));
@ -379,8 +216,7 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnI
private void executeCommand(Command c) private void executeCommand(Command c)
{ {
mainActivity.executeCommand(c, false); mainActivity.executeCommand(c);
notifyDataSetChanged();
} }
@Override @Override
@ -401,11 +237,159 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnI
String msg = ""; String msg = "";
int starCount = Habit.getStarCount(); int starCount = Habit.getStarCount();
if(starCount == 1) if (starCount == 1) msg = String.format("%d star", starCount);
msg = String.format("%d star", starCount); else if (starCount > 1) msg = String.format("%d stars", starCount);
else if(starCount > 1)
msg = String.format("%d stars", starCount);
tvNameHeader.setText(msg); tvNameHeader.setText(msg);
} }
class ListHabitsAdapter extends BaseAdapter
{
String habits[] = {"wake up early", "work out", "meditate", "take vitamins", "go to school",
"cook dinner & lunch"};
private Context context;
private LayoutInflater inflater;
private Typeface fontawesome;
public ListHabitsAdapter(Context context)
{
this.context = context;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
fontawesome = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
}
@Override
public int getCount()
{
return Habit.getCount();
}
@Override
public Object getItem(int position)
{
return Habit.getByPosition(position);
}
@Override
public long getItemId(int position)
{
return ((Habit) getItem(position)).getId();
}
@Override
public View getView(int position, View view, ViewGroup parent)
{
final Habit habit = (Habit) getItem(position);
if (view == null ||
(Long) view.getTag(R.id.KEY_TIMESTAMP) != DateHelper.getStartOfToday())
{
view = inflater.inflate(R.layout.list_habits_item, null);
((TextView) view.findViewById(R.id.tvStar)).setTypeface(fontawesome);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(tvNameWidth, LayoutParams.WRAP_CONTENT, 1);
((TextView) view.findViewById(R.id.tvName)).setLayoutParams(params);
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
LinearLayout.LayoutParams llp =
new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
llp.setMargins(2, 0, 2, 0);
for (int i = 0; i < button_count; i++)
{
View check = inflater.inflate(R.layout.list_habits_item_check, null);
TextView btCheck = (TextView) check.findViewById(R.id.tvCheck);
btCheck.setTypeface(fontawesome);
btCheck.setOnLongClickListener(ListHabitsFragment.this);
// btCheck.setLayoutParams(llp);
((LinearLayout) view.findViewById(R.id.llButtons)).addView(check);
}
// LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner);
// llInner.setOnClickListener(ListHabitsFragment.this);
view.setTag(R.id.KEY_TIMESTAMP, DateHelper.getStartOfToday());
}
TextView tvStar = (TextView) view.findViewById(R.id.tvStar);
TextView tvName = (TextView) view.findViewById(R.id.tvName);
if (habit == null)
{
tvName.setText(null);
return view;
}
LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner);
llInner.setTag(R.string.habit_key, habit.getId());
int inactiveColor = Color.rgb(230, 230, 230);
int activeColor = habit.color;
tvName.setText(habit.name);
tvName.setTextColor(activeColor);
int score = habit.getScore();
if (score < Habit.HALF_STAR_CUTOFF)
{
tvStar.setText(context.getString(R.string.fa_star_o));
tvStar.setTextColor(inactiveColor);
} else if (score < Habit.FULL_STAR_CUTOFF)
{
tvStar.setText(context.getString(R.string.fa_star_half_o));
tvStar.setTextColor(inactiveColor);
} else
{
tvStar.setText(context.getString(R.string.fa_star));
tvStar.setTextColor(activeColor);
}
LinearLayout llButtons = (LinearLayout) view.findViewById(R.id.llButtons);
int m = llButtons.getChildCount();
long dateTo = DateHelper.getStartOfDay(DateHelper.getLocalTime());
long dateFrom = dateTo - m * DateHelper.millisecondsInOneDay;
int isChecked[] = habit.getReps(dateFrom, dateTo);
for (int i = 0; i < m; i++)
{
TextView tvCheck = (TextView) llButtons.getChildAt(i);
tvCheck.setTag(R.string.habit_key, habit.getId());
tvCheck.setTag(R.string.offset_key, i);
switch (isChecked[i])
{
case 2:
tvCheck.setText(R.string.fa_check);
tvCheck.setTextColor(activeColor);
break;
case 1:
tvCheck.setText(R.string.fa_check);
tvCheck.setTextColor(inactiveColor);
break;
case 0:
tvCheck.setText(R.string.fa_times);
tvCheck.setTextColor(inactiveColor);
break;
}
}
return view;
}
}
} }

@ -1,31 +1,24 @@
package org.isoron.uhabits.dialogs; package org.isoron.uhabits.dialogs;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import org.isoron.helpers.ColorHelper;
import org.isoron.helpers.DateHelper;
import org.isoron.uhabits.R;
import org.isoron.uhabits.ShowHabitActivity;
import org.isoron.uhabits.models.Habit;
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;
import android.graphics.Typeface;
import android.os.Bundle; import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView; import android.widget.TextView;
import org.isoron.helpers.ColorHelper;
import org.isoron.uhabits.R;
import org.isoron.uhabits.ShowHabitActivity;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.views.HabitHistoryView;
import org.isoron.uhabits.views.HabitScoreView;
import org.isoron.uhabits.views.HabitStreakView;
import org.isoron.uhabits.views.RingView;
public class ShowHabitFragment extends Fragment public class ShowHabitFragment extends Fragment
{ {
protected ShowHabitActivity activity; protected ShowHabitActivity activity;
@ -54,22 +47,30 @@ public class ShowHabitFragment extends Fragment
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); TextView tvStrength = (TextView) view.findViewById(R.id.tvStrength);
TextView tvStreaks = (TextView) view.findViewById(R.id.tvStreaks);
tvHistory.setTextColor(habit.color); tvHistory.setTextColor(habit.color);
tvOverview.setTextColor(habit.color); tvOverview.setTextColor(habit.color);
tvStrength.setTextColor(habit.color);
tvStreaks.setTextColor(habit.color); tvStreaks.setTextColor(habit.color);
LinearLayout llOverview = (LinearLayout) view.findViewById(R.id.llOverview); LinearLayout llOverview = (LinearLayout) view.findViewById(R.id.llOverview);
llOverview.addView(new RingView(activity, 200, habit.color, ((float) habit.getScore() / Habit.MAX_SCORE), "Habit strength")); llOverview.addView(new RingView(activity,
(int) activity.getResources().getDimension(R.dimen.small_square_size) * 4, habit.color,
((float) habit.getScore() / Habit.MAX_SCORE), "Habit strength"));
LinearLayout llStrength = (LinearLayout) view.findViewById(R.id.llStrength);
llStrength.addView(new HabitScoreView(activity, habit,
(int) activity.getResources().getDimension(R.dimen.small_square_size)));
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,
(int) activity.getResources().getDimension(R.dimen.square_size)); (int) activity.getResources().getDimension(R.dimen.small_square_size));
llHistory.addView(hhv); llHistory.addView(hhv);
LinearLayout llStreaks = (LinearLayout) view.findViewById(R.id.llStreaks); LinearLayout llStreaks = (LinearLayout) view.findViewById(R.id.llStreaks);
HabitStreakView hsv = new HabitStreakView(activity, habit, HabitStreakView hsv = new HabitStreakView(activity, habit,
(int) activity.getResources().getDimension(R.dimen.square_size)); (int) activity.getResources().getDimension(R.dimen.small_square_size));
llStreaks.addView(hsv); llStreaks.addView(hsv);
return view; return view;

@ -3,6 +3,7 @@ package org.isoron.uhabits.models;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import com.activeandroid.Cache; import com.activeandroid.Cache;
@ -20,6 +21,7 @@ import org.isoron.helpers.Command;
import org.isoron.helpers.DateHelper; import org.isoron.helpers.DateHelper;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import java.util.Date;
import java.util.List; import java.util.List;
@Table(name = "Habits") @Table(name = "Habits")
@ -77,8 +79,7 @@ public class Habit extends Model
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
public static void updateId(long oldId, long newId) public static void updateId(long oldId, long newId)
{ {
SQLiteUtils.execSql(String.format( SQLiteUtils.execSql(String.format("update Habits set Id = %d where Id = %d", newId, oldId));
"update Habits set Id = %d where Id = %d", newId, oldId));
} }
protected static From select() protected static From select()
@ -114,18 +115,13 @@ public class Habit extends Model
public static void reorder(int from, int to) public static void reorder(int from, int to)
{ {
if (from == to) if (from == to) return;
return;
Habit h = Habit.getByPosition(from); Habit h = Habit.getByPosition(from);
if (to < from) if (to < from) new Update(Habit.class).set("position = position + 1")
new Update(Habit.class).set("position = position + 1") .where("position >= ? and position < ?", to, from).execute();
.where("position >= ? and position < ?", to, from) else new Update(Habit.class).set("position = position - 1")
.execute(); .where("position > ? and position <= ?", from, to).execute();
else
new Update(Habit.class).set("position = position - 1")
.where("position > ? and position <= ?", from, to)
.execute();
h.position = to; h.position = to;
h.save(); h.save();
@ -152,13 +148,20 @@ public class Habit extends Model
} }
} }
public static void recomputeAllScores()
{
for (Habit habit : getHabits())
{
habit.deleteScoresNewerThan(0);
}
}
public static int getStarCount() public static int getStarCount()
{ {
String args[] = {}; String args[] = {};
return SQLiteUtils.intQuery( return SQLiteUtils.intQuery("select count(*) from (select score, max(timestamp) from " +
"select count(*) from (select score, max(timestamp) from " + "score group by habit) as scores where scores.score >= " +
"score group by habit) as scores where scores.score >= " Integer.toString(12973000), args);
+ Integer.toString(12973000), args);
} }
@ -184,14 +187,12 @@ public class Habit extends Model
protected From selectReps() protected From selectReps()
{ {
return new Select().from(Repetition.class).where("habit = ?", getId()) return new Select().from(Repetition.class).where("habit = ?", getId()).orderBy("timestamp");
.orderBy("timestamp");
} }
protected From selectRepsFromTo(long timeFrom, long timeTo) protected From selectRepsFromTo(long timeFrom, long timeTo)
{ {
return selectReps().and("timestamp >= ?", timeFrom).and( return selectReps().and("timestamp >= ?", timeFrom).and("timestamp <= ?", timeTo);
"timestamp <= ?", timeTo);
} }
public boolean hasRep(long timestamp) public boolean hasRep(long timestamp)
@ -236,8 +237,7 @@ public class Habit extends Model
for (int j = 0; j < freq_den; j++) for (int j = 0; j < freq_den; j++)
if (checkExtended[i + j] == 2) counter++; if (checkExtended[i + j] == 2) counter++;
if (counter >= freq_num) if (counter >= freq_num) checkExtended[i] = Math.max(checkExtended[i], 1);
checkExtended[i] = Math.max(checkExtended[i], 1);
} }
int check[] = new int[nDays + 1]; int check[] = new int[nDays + 1];
@ -247,6 +247,13 @@ public class Habit extends Model
return check; return check;
} }
public int getRepsCount(int days)
{
long timeTo = DateHelper.getStartOfToday();
long timeFrom = timeTo - DateHelper.millisecondsInOneDay * days;
return selectRepsFromTo(timeFrom, timeTo).count();
}
public boolean hasImplicitRepToday() public boolean hasImplicitRepToday()
{ {
long today = DateHelper.getStartOfToday(); long today = DateHelper.getStartOfToday();
@ -282,14 +289,14 @@ public class Habit extends Model
public Score getNewestScore() public Score getNewestScore()
{ {
return new Select().from(Score.class).where("habit = ?", getId()) return new Select().from(Score.class).where("habit = ?", getId()).orderBy("timestamp desc")
.orderBy("timestamp desc").limit(1).executeSingle(); .limit(1).executeSingle();
} }
public void deleteScoresNewerThan(long timestamp) public void deleteScoresNewerThan(long timestamp)
{ {
new Delete().from(Score.class).where("habit = ?", getId()) new Delete().from(Score.class).where("habit = ?", getId()).and("timestamp >= ?", timestamp)
.and("timestamp >= ?", timestamp).execute(); .execute();
} }
public Integer getScore() public Integer getScore()
@ -307,8 +314,7 @@ public class Habit extends Model
if (newestScore == null) if (newestScore == null)
{ {
Repetition oldestRep = getOldestRep(); Repetition oldestRep = getOldestRep();
if (oldestRep == null) if (oldestRep == null) return 0;
return 0;
beginningTime = oldestRep.timestamp; beginningTime = oldestRep.timestamp;
beginningScore = 0; beginningScore = 0;
} else } else
@ -318,8 +324,7 @@ public class Habit extends Model
} }
long nDays = (today - beginningTime) / day; long nDays = (today - beginningTime) / day;
if (nDays < 0) if (nDays < 0) return newestScore.score;
return newestScore.score;
int reps[] = getReps(beginningTime, today); int reps[] = getReps(beginningTime, today);
@ -343,9 +348,22 @@ public class Habit extends Model
return lastScore; return lastScore;
} }
public List<Score> getScores(long fromTimestamp, long toTimestamp)
{
return getScores(fromTimestamp, toTimestamp, 1, 0);
}
public List<Score> getScores(long fromTimestamp, long toTimestamp, int divisor, long offset)
{
return new Select().from(Score.class).where("habit = ? and timestamp > ? and " +
"timestamp <= ? and (timestamp - ?) % ? = 0", getId(), fromTimestamp, toTimestamp,
offset, divisor).execute();
}
public long[] getStreaks() public long[] getStreaks()
{ {
String query = "create temporary table T as select distinct r1.habit as habit, r1.timestamp as time,\n" + 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" + " (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 or\n" +
" r1.timestamp = r2.timestamp + 24*60*60*1000)) as neighbors\n" + " r1.timestamp = r2.timestamp + 24*60*60*1000)) as neighbors\n" +
@ -436,8 +454,8 @@ public class Habit extends Model
this.modified = new Habit(modified); this.modified = new Habit(modified);
this.original = new Habit(Habit.this); this.original = new Habit(Habit.this);
hasIntervalChanged = (this.original.freq_den != this.modified.freq_den hasIntervalChanged = (this.original.freq_den != this.modified.freq_den ||
|| this.original.freq_num != this.modified.freq_num); this.original.freq_num != this.modified.freq_num);
} }
public void execute() public void execute()
@ -446,7 +464,30 @@ public class Habit extends Model
habit.copyAttributes(modified); habit.copyAttributes(modified);
habit.save(); habit.save();
if (hasIntervalChanged) if (hasIntervalChanged)
habit.deleteScoresNewerThan(0); {
new AsyncTask<Habit, Integer, Integer>()
{
@Override
protected Integer doInBackground(Habit... habits)
{
// HACK: We wait one second before deleting old score, otherwise the view will
// trigger the very slow getScore on the main thread at the same time, or even
// before us.
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
habits[0].deleteScoresNewerThan(0);
habits[0].getScore();
return 0;
}
}.execute(habit);
}
} }
public void undo() public void undo()
@ -455,7 +496,28 @@ public class Habit extends Model
habit.copyAttributes(original); habit.copyAttributes(original);
habit.save(); habit.save();
if (hasIntervalChanged) if (hasIntervalChanged)
habit.deleteScoresNewerThan(0); {
new AsyncTask<Habit, Integer, Integer>()
{
@Override
protected Integer doInBackground(Habit... habits)
{
try
{
Thread.sleep(1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
habits[0].deleteScoresNewerThan(0);
habits[0].getScore();
return 0;
}
}.execute(habit);
}
} }
public Integer getExecuteStringId() public Integer getExecuteStringId()

@ -1,26 +1,24 @@
package org.isoron.uhabits.views; package org.isoron.uhabits.views;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import org.isoron.helpers.ColorHelper;
import org.isoron.helpers.DateHelper;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import android.content.Context; import android.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Paint.Align; import android.graphics.Paint.Align;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Typeface;
import android.support.v4.view.MotionEventCompat; import android.support.v4.view.MotionEventCompat;
import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import org.isoron.helpers.ColorHelper;
import org.isoron.helpers.DateHelper;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class HabitHistoryView extends View public class HabitHistoryView extends View
{ {
@ -34,6 +32,7 @@ public class HabitHistoryView extends View
private int nColumns, offsetWeeks; private int nColumns, offsetWeeks;
private int colorPrimary, colorPrimaryBrighter, grey; private int colorPrimary, colorPrimaryBrighter, grey;
private Float prevX, prevY;
public HabitHistoryView(Context context, Habit habit, int squareSize) public HabitHistoryView(Context context, Habit habit, int squareSize)
{ {
@ -42,9 +41,6 @@ public class HabitHistoryView extends View
this.context = context; this.context = context;
this.squareSize = squareSize; this.squareSize = squareSize;
Typeface fontawesome = Typeface.createFromAsset(context.getAssets(),
"fontawesome-webfont.ttf");
colorPrimary = habit.color; colorPrimary = habit.color;
colorPrimaryBrighter = ColorHelper.mixColors(colorPrimary, Color.WHITE, 0.5f); colorPrimaryBrighter = ColorHelper.mixColors(colorPrimary, Color.WHITE, 0.5f);
grey = Color.rgb(230, 230, 230); grey = Color.rgb(230, 230, 230);
@ -62,7 +58,6 @@ public class HabitHistoryView extends View
pSquareFg = new Paint(); pSquareFg = new Paint();
pSquareFg.setColor(Color.WHITE); pSquareFg.setColor(Color.WHITE);
pSquareFg.setAntiAlias(true); pSquareFg.setAntiAlias(true);
// pSquareFg.setTypeface(fontawesome);
pSquareFg.setTextSize(squareSize * 0.5f); pSquareFg.setTextSize(squareSize * 0.5f);
pSquareFg.setTextAlign(Align.CENTER); pSquareFg.setTextAlign(Align.CENTER);
} }
@ -109,12 +104,13 @@ public class HabitHistoryView extends View
Rect square = new Rect(0, 0, squareSize - squareSpacing, squareSize - squareSpacing); Rect square = new Rect(0, 0, squareSize - squareSpacing, squareSize - squareSpacing);
Calendar currentDate = new GregorianCalendar(); Calendar currentDate = new GregorianCalendar();
currentDate.add(Calendar.DAY_OF_YEAR, -(offsetWeeks-1) * 7); currentDate.add(Calendar.DAY_OF_YEAR, - (offsetWeeks - 1) * 7);
int nDays = nColumns * 7; int nDays = nColumns * 7;
int todayWeekday = new GregorianCalendar().get(Calendar.DAY_OF_WEEK) % 7; int todayWeekday = new GregorianCalendar().get(Calendar.DAY_OF_WEEK) % 7;
currentDate.add(Calendar.DAY_OF_YEAR, -nDays); currentDate.add(Calendar.DAY_OF_YEAR, -nDays);
currentDate.add(Calendar.DAY_OF_YEAR, -todayWeekday);
SimpleDateFormat dfMonth = new SimpleDateFormat("MMM"); SimpleDateFormat dfMonth = new SimpleDateFormat("MMM");
SimpleDateFormat dfYear = new SimpleDateFormat("yyyy"); SimpleDateFormat dfYear = new SimpleDateFormat("yyyy");
@ -122,9 +118,10 @@ public class HabitHistoryView extends View
String previousMonth = ""; String previousMonth = "";
String previousYear = ""; String previousYear = "";
int colors[] = { grey, colorPrimaryBrighter, colorPrimary }; int colors[] = {grey, colorPrimaryBrighter, colorPrimary};
String markers[] = { context.getString(R.string.fa_times), String markers[] =
context.getString(R.string.fa_check), context.getString(R.string.fa_check) }; {context.getString(R.string.fa_times), context.getString(R.string.fa_check),
context.getString(R.string.fa_check)};
float squareTextOffset = pSquareFg.getFontSpacing() * 0.4f; float squareTextOffset = pSquareFg.getFontSpacing() * 0.4f;
float headerTextOffset = pTextHeader.getFontSpacing() * 0.3f; float headerTextOffset = pTextHeader.getFontSpacing() * 0.3f;
@ -136,24 +133,21 @@ public class HabitHistoryView extends View
String month = dfMonth.format(currentDate.getTime()); String month = dfMonth.format(currentDate.getTime());
String year = dfYear.format(currentDate.getTime()); String year = dfYear.format(currentDate.getTime());
if(!month.equals(previousMonth)) if (!month.equals(previousMonth))
{ {
int offset = 0; int offset = 0;
if(justPrintedYear) if (justPrintedYear) offset += squareSize;
offset += squareSize;
canvas.drawText(month, square.left + offset, square.bottom - headerTextOffset, canvas.drawText(month, square.left + offset, square.bottom - headerTextOffset,
pTextHeader); pTextHeader);
previousMonth = month; previousMonth = month;
justPrintedYear = false; justPrintedYear = false;
} } else if (!year.equals(previousYear))
else if(!year.equals(previousYear))
{ {
canvas.drawText(year, square.left, square.bottom - headerTextOffset, pTextHeader); canvas.drawText(year, square.left, square.bottom - headerTextOffset, pTextHeader);
previousYear = year; previousYear = year;
justPrintedYear = true; justPrintedYear = true;
} } else
else
{ {
justPrintedYear = false; justPrintedYear = false;
} }
@ -163,12 +157,10 @@ public class HabitHistoryView extends View
for (int j = 0; j < 7; j++) for (int j = 0; j < 7; j++)
{ {
if(!(i == nColumns - 1 && offsetWeeks == 0 && j > todayWeekday)) if (!(i == nColumns - 1 && offsetWeeks == 0 && j > todayWeekday))
{ {
pSquareBg.setColor(colors[reps[k]]); pSquareBg.setColor(colors[reps[k]]);
canvas.drawRect(square, pSquareBg); canvas.drawRect(square, pSquareBg);
// canvas.drawText(markers[reps[k]], square.centerX(), square.centerY()
// + squareTextOffset, pSquareFg);
canvas.drawText(Integer.toString(currentDate.get(Calendar.DAY_OF_MONTH)), canvas.drawText(Integer.toString(currentDate.get(Calendar.DAY_OF_MONTH)),
square.centerX(), square.centerY() + squareTextOffset, pSquareFg); square.centerX(), square.centerY() + squareTextOffset, pSquareFg);
} }
@ -181,18 +173,16 @@ public class HabitHistoryView extends View
square.offset(squareSize, -8 * squareSize); square.offset(squareSize, -8 * squareSize);
} }
String wdays[] = { "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri" }; String wdays[] = {"Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri"};
for (int i = 0; i < 7; i++) for (int i = 0; i < 7; i++)
{ {
square.offset(0, squareSize); square.offset(0, squareSize);
canvas.drawText(wdays[i], square.left + headerTextOffset, square.bottom canvas.drawText(wdays[i], square.left + headerTextOffset,
- headerTextOffset, pTextHeader); square.bottom - headerTextOffset, pTextHeader);
} }
} }
private Float prevX, prevY;
@Override @Override
public boolean onTouchEvent(MotionEvent event) public boolean onTouchEvent(MotionEvent event)
{ {
@ -202,32 +192,42 @@ public class HabitHistoryView extends View
final float x = MotionEventCompat.getX(event, pointerIndex); final float x = MotionEventCompat.getX(event, pointerIndex);
final float y = MotionEventCompat.getY(event, pointerIndex); final float y = MotionEventCompat.getY(event, pointerIndex);
if(action == MotionEvent.ACTION_DOWN) if (action == MotionEvent.ACTION_DOWN)
{ {
prevX = x; prevX = x;
prevY = y; prevY = y;
} }
if(action == MotionEvent.ACTION_MOVE) if (action == MotionEvent.ACTION_MOVE)
{ {
float dx = x - prevX; float dx = x - prevX;
float dy = y - prevY; float dy = y - prevY;
if (Math.abs(dy) > Math.abs(dx)) return false;
getParent().requestDisallowInterceptTouchEvent(true);
if(move(dx))
{
prevX = x;
prevY = y;
}
}
return true;
}
private boolean move(float dx)
{
int newOffsetWeeks = offsetWeeks + (int) (dx / squareSize); int newOffsetWeeks = offsetWeeks + (int) (dx / squareSize);
newOffsetWeeks = Math.max(0, newOffsetWeeks); newOffsetWeeks = Math.max(0, newOffsetWeeks);
if(newOffsetWeeks != offsetWeeks) if (newOffsetWeeks != offsetWeeks)
{ {
prevX = x;
prevY = y;
offsetWeeks = newOffsetWeeks; offsetWeeks = newOffsetWeeks;
fetchReps(); fetchReps();
invalidate(); invalidate();
}
}
return true; return true;
} }
else
return false;
}
} }

@ -0,0 +1,252 @@
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.support.v4.view.MotionEventCompat;
import android.view.MotionEvent;
import android.view.View;
import org.isoron.helpers.ColorHelper;
import org.isoron.helpers.DateHelper;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.Score;
import java.text.SimpleDateFormat;
import java.util.List;
public class HabitScoreView extends View
{
public static final int BUCKET_SIZE = 7;
private final Paint pGrid;
private final float em;
private Habit habit;
private int columnWidth, columnHeight, nColumns;
private Paint pText, pGraph;
private int dataOffset;
private int barHeaderHeight;
private int[] colors;
private float prevX;
private float prevY;
private List<Score> scores;
public HabitScoreView(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.LEFT);
pText.setTextSize(columnWidth * 0.5f);
pText.setAntiAlias(true);
pGraph = new Paint();
pGraph.setTextAlign(Paint.Align.CENTER);
pGraph.setTextSize(columnWidth * 0.5f);
pGraph.setAntiAlias(true);
pGraph.setStrokeWidth(columnWidth * 0.1f);
pGrid = new Paint();
pGrid.setColor(Color.LTGRAY);
pGrid.setAntiAlias(true);
pGrid.setStrokeWidth(columnWidth * 0.05f);
columnHeight = 8 * columnWidth;
barHeaderHeight = columnWidth;
em = pText.getFontSpacing();
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);
}
private void fetchScores()
{
long toTimestamp = DateHelper.getStartOfToday();
for (int i = 0; i < dataOffset * BUCKET_SIZE; i++)
toTimestamp -= DateHelper.millisecondsInOneDay;
long fromTimestamp = toTimestamp;
for (int i = 0; i < nColumns * BUCKET_SIZE; i++)
fromTimestamp -= DateHelper.millisecondsInOneDay;
scores = habit.getScores(fromTimestamp, toTimestamp, BUCKET_SIZE * DateHelper.millisecondsInOneDay,
toTimestamp);
}
@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;
fetchScores();
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
float lineHeight = pText.getFontSpacing();
float barHeaderOffset = lineHeight * 0.4f;
RectF rGrid = new RectF(0, 0, nColumns * columnWidth, columnHeight);
rGrid.offset(0, barHeaderHeight);
drawGrid(canvas, rGrid);
SimpleDateFormat dfMonth = new SimpleDateFormat("MMM");
SimpleDateFormat dfDay = new SimpleDateFormat("d");
String previousMonth = "";
pGraph.setColor(habit.color);
RectF prevR = null;
for (int offset = nColumns - scores.size(); offset < nColumns; offset++)
{
Score score = scores.get(offset - nColumns + scores.size());
String month = dfMonth.format(score.timestamp);
String day = dfDay.format(score.timestamp);
long s = score.score;
double sRelative = ((double) s) / Habit.MAX_SCORE;
int height = (int) (columnHeight * sRelative);
RectF r = new RectF(0, 0, columnWidth, columnWidth);
r.offset(offset * columnWidth,
barHeaderHeight + columnHeight - height - columnWidth / 2);
if (prevR != null)
{
drawLine(canvas, prevR, r);
drawMarker(canvas, prevR);
}
if (offset == nColumns - 1) drawMarker(canvas, r);
prevR = r;
r = new RectF(0, 0, columnWidth, columnHeight);
r.offset(offset * columnWidth, barHeaderHeight);
if (!month.equals(previousMonth))
{
canvas.drawText(month, r.centerX(), r.bottom + lineHeight * 1.2f, pText);
} else
{
canvas.drawText(day, r.centerX(), r.bottom + lineHeight * 1.2f, pText);
}
previousMonth = month;
}
}
private void drawGrid(Canvas canvas, RectF rGrid)
{
// pGrid.setColor(Color.rgb(230, 230, 230));
// pGrid.setStyle(Paint.Style.STROKE);
// canvas.drawRect(rGrid, pGrid);
int nRows = 5;
float rowHeight = rGrid.height() / nRows;
pGrid.setColor(Color.rgb(240, 240, 240));
for (int i = 0; i < nRows; i++)
{
canvas.drawText(String.format("%d%%", (100 - i * 100 / nRows)), rGrid.left + 0.5f * em,
rGrid.top + 1f * em, pText);
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid);
rGrid.offset(0, rowHeight);
}
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid);
}
private void drawLine(Canvas canvas, RectF rectFrom, RectF rectTo)
{
pGraph.setColor(habit.color);
canvas.drawLine(rectFrom.centerX(), rectFrom.centerY(), rectTo.centerX(), rectTo.centerY(),
pGraph);
}
private void drawMarker(Canvas canvas, RectF rect)
{
rect.inset(columnWidth * 0.15f, columnWidth * 0.15f);
pGraph.setColor(Color.WHITE);
canvas.drawOval(rect, pGraph);
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
pGraph.setColor(habit.color);
canvas.drawOval(rect, pGraph);
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
pGraph.setColor(Color.WHITE);
canvas.drawOval(rect, pGraph);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
int action = event.getAction();
int pointerIndex = MotionEventCompat.getActionIndex(event);
final float x = MotionEventCompat.getX(event, pointerIndex);
final float y = MotionEventCompat.getY(event, pointerIndex);
if (action == MotionEvent.ACTION_DOWN)
{
prevX = x;
prevY = y;
}
if (action == MotionEvent.ACTION_MOVE)
{
float dx = x - prevX;
float dy = y - prevY;
if (Math.abs(dy) > Math.abs(dx)) return false;
getParent().requestDisallowInterceptTouchEvent(true);
if (move(dx))
{
prevX = x;
prevY = y;
}
}
return true;
}
private boolean move(float dx)
{
int newDataOffset = dataOffset + (int) (dx / columnWidth);
newDataOffset = Math.max(0, newDataOffset);
if (newDataOffset != dataOffset)
{
dataOffset = newDataOffset;
fetchScores();
invalidate();
return true;
} else return false;
}
}

@ -5,6 +5,8 @@ import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Rect; import android.graphics.Rect;
import android.support.v4.view.MotionEventCompat;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import org.isoron.helpers.ColorHelper; import org.isoron.helpers.ColorHelper;
@ -22,6 +24,7 @@ public class HabitStreakView extends View
private Paint pText, pBar; private Paint pText, pBar;
private long streaks[]; private long streaks[];
private int dataOffset;
private long streakStart[], streakEnd[], streakLength[]; private long streakStart[], streakEnd[], streakLength[];
private long maxStreakLength; private long maxStreakLength;
@ -29,6 +32,8 @@ public class HabitStreakView extends View
private int barHeaderHeight; private int barHeaderHeight;
private int[] colors; private int[] colors;
private float prevX;
private float prevY;
public HabitStreakView(Context context, Habit habit, int columnWidth) public HabitStreakView(Context context, Habit habit, int columnWidth)
{ {
@ -98,7 +103,7 @@ public class HabitStreakView extends View
float lineHeight = pText.getFontSpacing(); float lineHeight = pText.getFontSpacing();
float barHeaderOffset = lineHeight * 0.4f; float barHeaderOffset = lineHeight * 0.4f;
int start = Math.max(0, streakStart.length - nColumns); int start = Math.max(0, streakStart.length - nColumns - dataOffset);
SimpleDateFormat dfMonth = new SimpleDateFormat("MMM"); SimpleDateFormat dfMonth = new SimpleDateFormat("MMM");
String previousMonth = ""; String previousMonth = "";
@ -125,4 +130,51 @@ public class HabitStreakView extends View
previousMonth = month; previousMonth = month;
} }
} }
@Override
public boolean onTouchEvent(MotionEvent event)
{
int action = event.getAction();
int pointerIndex = MotionEventCompat.getActionIndex(event);
final float x = MotionEventCompat.getX(event, pointerIndex);
final float y = MotionEventCompat.getY(event, pointerIndex);
if (action == MotionEvent.ACTION_DOWN)
{
prevX = x;
prevY = y;
}
if (action == MotionEvent.ACTION_MOVE)
{
float dx = x - prevX;
float dy = y - prevY;
if (Math.abs(dy) > Math.abs(dx)) return false;
getParent().requestDisallowInterceptTouchEvent(true);
if(move(dx))
{
prevX = x;
prevY = y;
}
}
return true;
}
private boolean move(float dx)
{
int newDataOffset = dataOffset + (int) (dx / columnWidth);
newDataOffset = Math.max(0, Math.min(streakStart.length - nColumns, newDataOffset));
if (newDataOffset != dataOffset)
{
dataOffset = newDataOffset;
invalidate();
return true;
}
else
return false;
}
} }

@ -28,11 +28,8 @@ public class RingView extends View
pRing.setColor(color); pRing.setColor(color);
pRing.setAntiAlias(true); pRing.setAntiAlias(true);
pRing.setTextAlign(Paint.Align.CENTER); pRing.setTextAlign(Paint.Align.CENTER);
pRing.setTextSize(size * 0.15f);
this.label = label; this.label = label;
lineHeight = pRing.getFontSpacing();
} }
@Override @Override
@ -52,16 +49,19 @@ public class RingView extends View
RectF r = new RectF(0, 0, size, size); RectF r = new RectF(0, 0, size, size);
canvas.drawArc(r, -90, 360 * perc, true, pRing); canvas.drawArc(r, -90, 360 * perc, true, pRing);
pRing.setColor(Color.rgb(230, 230, 230)); pRing.setColor(Color.rgb(230, 230, 230));
canvas.drawArc(r, 360 * perc - 90 + 2, 360 * (1-perc) - 4, true, pRing); canvas.drawArc(r, 360 * perc - 90 + 2, 360 * (1 - perc) - 4, true, pRing);
pRing.setColor(Color.WHITE); pRing.setColor(Color.WHITE);
r.inset(thickness, thickness); r.inset(thickness, thickness);
canvas.drawArc(r, -90, 360, true, pRing); canvas.drawArc(r, -90, 360, true, pRing);
pRing.setColor(Color.GRAY); pRing.setColor(Color.GRAY);
canvas.drawText(String.format("%.2f%%", perc*100), r.centerX(), r.centerY()+lineHeight/3, pRing); pRing.setTextSize(size * 0.2f);
lineHeight = pRing.getFontSpacing();
canvas.drawText(String.format("%.0f%%", perc * 100), r.centerX(), r.centerY()+lineHeight/3, pRing);
pRing.setTextSize(size * 0.15f);
canvas.drawText(label, size/2, size + lineHeight * 1.2f, pRing); canvas.drawText(label, size/2, size + lineHeight * 1.2f, pRing);
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

@ -2,20 +2,34 @@
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:background="@color/windowBackground"
android:background="@color/windowBackground"> android:fillViewport="true">
<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
android:id="@+id/llOverview"> android:id="@+id/llOverview"
style="@style/cardStyle"
android:gravity="center">
<TextView <TextView
android:id="@+id/tvOverview" android:id="@+id/tvOverview"
style="@style/cardHeaderStyle" style="@style/cardHeaderStyle"
android:text="@string/overview" /> android:text="@string/overview"/>
</LinearLayout>
<LinearLayout
android:id="@+id/llStrength"
style="@style/cardStyle"
android:gravity="center">
<TextView
android:id="@+id/tvStrength"
style="@style/cardHeaderStyle"
android:text="@string/habit_strength"/>
</LinearLayout> </LinearLayout>
@ -24,13 +38,13 @@
<TextView <TextView
android:id="@+id/tvHistory" android:id="@+id/tvHistory"
style="@style/cardHeaderStyle" style="@style/cardHeaderStyle"
android:text="@string/history" /> android:text="@string/history"/>
<LinearLayout <LinearLayout
android:id="@+id/llHistory" android:id="@+id/llHistory"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" /> android:orientation="horizontal"/>
</LinearLayout> </LinearLayout>
<LinearLayout style="@style/cardStyle"> <LinearLayout style="@style/cardStyle">
@ -38,13 +52,13 @@
<TextView <TextView
android:id="@+id/tvStreaks" android:id="@+id/tvStreaks"
style="@style/cardHeaderStyle" style="@style/cardHeaderStyle"
android:text="@string/streaks" /> android:text="@string/streaks"/>
<LinearLayout <LinearLayout
android:id="@+id/llStreaks" android:id="@+id/llStreaks"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" /> android:orientation="horizontal"/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -14,19 +14,9 @@
<style name="MyDialogStyle" parent="android:Theme.Material.Light.Dialog"> <style name="MyDialogStyle" parent="android:Theme.Material.Light.Dialog">
</style> </style>
<style name="cardStyle"> <style name="cardStyle" parent="cardBasicStyle">
<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:background">@color/white</item>
<item name="android:elevation">1dp</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> </style>
</resources> </resources>

@ -1,20 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="habitsListHeaderStyle"> <style name="habitsListHeaderStyle" parent="habitsListHeaderBasicStyle">
<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:background">#f0f0f0</item>
<item name="android:elevation">2dp</item> <item name="android:elevation">2dp</item>
<item name="android:paddingRight">4dp</item>
</style> </style>
<style name="habitsListCheckStyle"> <style name="habitsListCheckStyle" parent="habitsListCheckBasicStyle">
<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> <item name="android:background">@drawable/ripple_background</item>
</style> </style>
</resources> </resources>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="DragSortListView">
<attr name="collapsed_height" format="dimension"/>
<attr name="drag_scroll_start" format="float"/>
<attr name="max_drag_scroll_speed" format="float"/>
<attr name="float_background_color" format="color"/>
<attr name="remove_mode">
<enum name="clickRemove" value="0"/>
<enum name="flingRemove" value="1"/>
</attr>
<attr name="track_drag_sort" format="boolean"/>
<attr name="float_alpha" format="float"/>
<attr name="slide_shuffle_speed" format="float"/>
<attr name="remove_animation_duration" format="integer"/>
<attr name="drop_animation_duration" format="integer"/>
<attr name="drag_enabled" format="boolean"/>
<attr name="sort_enabled" format="boolean"/>
<attr name="remove_enabled" format="boolean"/>
<attr name="drag_start_mode">
<enum name="onDown" value="0"/>
<enum name="onMove" value="1"/>
<enum name="onLongPress" value="2"/>
</attr>
<attr name="drag_handle_id" format="integer"/>
<attr name="fling_handle_id" format="integer"/>
<attr name="click_remove_id" format="integer"/>
<attr name="use_default_controller" format="boolean"/>
</declare-styleable>
</resources>

@ -1,54 +1,6 @@
<resources> <resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<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="small_square_size">20dp</dimen>
<dimen name="square_size">20dp</dimen> <dimen name="check_square_size">42dp</dimen>
<!-- Color picker -->
<dimen name="color_swatch_large">64dip</dimen>
<dimen name="color_swatch_small">48dip</dimen>
<dimen name="color_swatch_margins_large">8dip</dimen>
<dimen name="color_swatch_margins_small">4dip</dimen>
<!-- Date and time picker -->
<item name="circle_radius_multiplier" format="float" type="string">0.82</item>
<item name="circle_radius_multiplier_24HourMode" format="float" type="string">0.85</item>
<item name="selection_radius_multiplier" format="float" type="string">0.16</item>
<item name="ampm_circle_radius_multiplier" format="float" type="string">0.19</item>
<item name="numbers_radius_multiplier_normal" format="float" type="string">0.81</item>
<item name="numbers_radius_multiplier_inner" format="float" type="string">0.60</item>
<item name="numbers_radius_multiplier_outer" format="float" type="string">0.83</item>
<item name="text_size_multiplier_normal" format="float" type="string">0.17</item>
<item name="text_size_multiplier_inner" format="float" type="string">0.14</item>
<item name="text_size_multiplier_outer" format="float" type="string">0.11</item>
<dimen name="time_label_size">60sp</dimen>
<dimen name="extra_time_label_margin">-30dp</dimen>
<dimen name="ampm_label_size">16sp</dimen>
<dimen name="done_label_size">14sp</dimen>
<dimen name="ampm_left_padding">6dip</dimen>
<dimen name="separator_padding">4dip</dimen>
<dimen name="header_height">96dip</dimen>
<dimen name="footer_height">48dip</dimen>
<dimen name="minimum_margin_sides">48dip</dimen>
<dimen name="minimum_margin_top_bottom">24dip</dimen>
<dimen name="picker_dimen">270dip</dimen>
<dimen name="date_picker_component_width">270dp</dimen>
<dimen name="date_picker_header_height">30dp</dimen>
<dimen name="selected_calendar_layout_height">155dp</dimen>
<dimen name="date_picker_view_animator_height">270dp</dimen>
<dimen name="done_button_height">42dp</dimen>
<dimen name="month_list_item_header_height">50dp</dimen>
<dimen name="month_day_label_text_size">10sp</dimen>
<dimen name="day_number_select_circle_radius">16dp</dimen>
<dimen name="month_select_circle_radius">45dp</dimen>
<dimen name="selected_date_year_size">30dp</dimen>
<dimen name="selected_date_day_size">75dp</dimen>
<dimen name="selected_date_month_size">30dp</dimen>
<dimen name="date_picker_header_text_size">14dp</dimen>
<dimen name="month_label_size">16sp</dimen>
<dimen name="day_number_size">16sp</dimen>
<dimen name="year_label_height">64dp</dimen>
<dimen name="year_label_text_size">22dp</dimen>
</resources> </resources>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="color_swatch_large">64dip</dimen>
<dimen name="color_swatch_small">48dip</dimen>
<dimen name="color_swatch_margins_large">8dip</dimen>
<dimen name="color_swatch_margins_small">4dip</dimen>
</resources>

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="circle_radius_multiplier" format="float" type="string">0.82</item>
<item name="circle_radius_multiplier_24HourMode" format="float" type="string">0.85</item>
<item name="selection_radius_multiplier" format="float" type="string">0.16</item>
<item name="ampm_circle_radius_multiplier" format="float" type="string">0.19</item>
<item name="numbers_radius_multiplier_normal" format="float" type="string">0.81</item>
<item name="numbers_radius_multiplier_inner" format="float" type="string">0.60</item>
<item name="numbers_radius_multiplier_outer" format="float" type="string">0.83</item>
<item name="text_size_multiplier_normal" format="float" type="string">0.17</item>
<item name="text_size_multiplier_inner" format="float" type="string">0.14</item>
<item name="text_size_multiplier_outer" format="float" type="string">0.11</item>
<dimen name="time_label_size">60sp</dimen>
<dimen name="extra_time_label_margin">-30dp</dimen>
<dimen name="ampm_label_size">16sp</dimen>
<dimen name="done_label_size">14sp</dimen>
<dimen name="ampm_left_padding">6dip</dimen>
<dimen name="separator_padding">4dip</dimen>
<dimen name="header_height">96dip</dimen>
<dimen name="footer_height">48dip</dimen>
<dimen name="minimum_margin_sides">48dip</dimen>
<dimen name="minimum_margin_top_bottom">24dip</dimen>
<dimen name="picker_dimen">270dip</dimen>
<dimen name="date_picker_component_width">270dp</dimen>
<dimen name="date_picker_header_height">30dp</dimen>
<dimen name="selected_calendar_layout_height">155dp</dimen>
<dimen name="date_picker_view_animator_height">270dp</dimen>
<dimen name="done_button_height">42dp</dimen>
<dimen name="month_list_item_header_height">50dp</dimen>
<dimen name="month_day_label_text_size">10sp</dimen>
<dimen name="day_number_select_circle_radius">16dp</dimen>
<dimen name="month_select_circle_radius">45dp</dimen>
<dimen name="selected_date_year_size">30dp</dimen>
<dimen name="selected_date_day_size">75dp</dimen>
<dimen name="selected_date_month_size">30dp</dimen>
<dimen name="date_picker_header_text_size">14dp</dimen>
<dimen name="month_label_size">16sp</dimen>
<dimen name="day_number_size">16sp</dimen>
<dimen name="year_label_height">64dp</dimen>
<dimen name="year_label_text_size">22dp</dimen>
</resources>

@ -25,20 +25,24 @@
<item name="android:orientation">vertical</item> <item name="android:orientation">vertical</item>
</style> </style>
<style name="cardStyle"> <style name="cardBasicStyle">
<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">@drawable/card_background</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">1dp</item> <item name="android:layout_marginBottom">3dp</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>
<style name="cardStyle" parent="cardBasicStyle">
<item name="android:background">@drawable/card_background</item>
<item name="android:layout_marginBottom">1dp</item>
</style>
<style name="cardHeaderStyle"> <style name="cardHeaderStyle">
<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>

@ -10,11 +10,15 @@
<item name="android:background">@color/windowBackground</item> <item name="android:background">@color/windowBackground</item>
</style> </style>
<style name="habitsListHeaderStyle">
<style name="habitsListHeaderBasicStyle">
<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:paddingRight">4dp</item> <item name="android:paddingRight">4dp</item>
</style>
<style name="habitsListHeaderStyle" parent="habitsListHeaderBasicStyle">
<item name="android:background">@drawable/habits_list_header_background</item> <item name="android:background">@drawable/habits_list_header_background</item>
</style> </style>
@ -58,13 +62,16 @@
<item name="android:padding">3dp</item> <item name="android:padding">3dp</item>
</style> </style>
<style name="habitsListCheckStyle"> <style name="habitsListCheckBasicStyle">
<item name="android:focusable">false</item> <item name="android:focusable">false</item>
<item name="android:minHeight">42dp</item> <item name="android:minHeight">@dimen/check_square_size</item>
<item name="android:minWidth">42dp</item> <item name="android:minWidth">@dimen/check_square_size</item>
<item name="android:gravity">center</item> <item name="android:gravity">center</item>
</style> </style>
<style name="habitsListCheckStyle" parent="habitsListCheckBasicStyle">
</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>

Loading…
Cancel
Save