From de02e119d1016d96fc901e162057c9aef8e9d51d Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Tue, 25 Aug 2015 12:32:16 -0400 Subject: [PATCH] Reorganizing --- app/app.iml | 8 +- app/src/main/AndroidManifest.xml | 2 +- app/src/main/ic_launcher-web.png | Bin 0 -> 41511 bytes .../java/org/isoron/uhabits/MainActivity.java | 16 +- .../isoron/uhabits/ReminderAlarmReceiver.java | 263 +++---- .../uhabits/dialogs/ListHabitsFragment.java | 718 +++++++++--------- .../uhabits/dialogs/ShowHabitFragment.java | 79 +- .../java/org/isoron/uhabits/models/Habit.java | 140 +++- .../uhabits/views/HabitHistoryView.java | 426 +++++------ .../isoron/uhabits/views/HabitScoreView.java | 252 ++++++ .../isoron/uhabits/views/HabitStreakView.java | 54 +- .../org/isoron/uhabits/views/RingView.java | 12 +- .../main/res/drawable-hdpi/ic_launcher.png | Bin 3812 -> 0 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 2224 -> 0 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 5514 -> 0 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 9418 -> 0 bytes app/src/main/res/drawable/stripe.png | Bin 0 -> 344 bytes app/src/main/res/layout/show_habit.xml | 38 +- app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2985 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1804 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4240 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7257 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10820 bytes app/src/main/res/values-v21/styles.xml | 12 +- .../res/values-v21/styles_list_habits.xml | 13 +- app/src/main/res/values/attrs_dslv.xml | 30 + app/src/main/res/values/dimens.xml | 52 +- .../main/res/values/dimens_color_picker.xml | 7 + app/src/main/res/values/dimens_date_time.xml | 42 + app/src/main/res/values/styles.xml | 10 +- .../main/res/values/styles_list_habits.xml | 15 +- 31 files changed, 1279 insertions(+), 910 deletions(-) create mode 100644 app/src/main/ic_launcher-web.png create mode 100644 app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java delete mode 100644 app/src/main/res/drawable-hdpi/ic_launcher.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_launcher.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_launcher.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable/stripe.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/values/attrs_dslv.xml create mode 100644 app/src/main/res/values/dimens_color_picker.xml create mode 100644 app/src/main/res/values/dimens_date_time.xml diff --git a/app/app.iml b/app/app.iml index c8d4626b3..b9364a714 100644 --- a/app/app.iml +++ b/app/app.iml @@ -1,5 +1,5 @@ - + @@ -12,8 +12,9 @@ - - + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 376c34db9..b34cfa3ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,7 +14,7 @@ diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png new file mode 100644 index 0000000000000000000000000000000000000000..85ad242d1959f6c0699868de8c2cfb3f3f3d1f4e GIT binary patch literal 41511 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 Bx)A^X literal 0 HcmV?d00001 diff --git a/app/src/main/java/org/isoron/uhabits/MainActivity.java b/app/src/main/java/org/isoron/uhabits/MainActivity.java index 7db75aa54..bbb97c0d8 100644 --- a/app/src/main/java/org/isoron/uhabits/MainActivity.java +++ b/app/src/main/java/org/isoron/uhabits/MainActivity.java @@ -6,6 +6,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.util.Log; @@ -125,25 +126,24 @@ public class MainActivity extends Activity 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); if (undoList.size() > MAX_UNDO_LEVEL) undoList.removeLast(); if (clearRedoStack) redoList.clear(); + command.execute(); + listHabitsFragment.notifyDataSetChanged(); showToast(command.getExecuteStringId()); - if (datasetChanged) - { - listHabitsFragment.notifyDataSetChanged(); - } } public void undo() @@ -170,7 +170,7 @@ public class MainActivity extends Activity return; } Command last = redoList.pop(); - executeCommand(last, true, false); + executeCommand(last, false); } private void showToast(Integer stringId) diff --git a/app/src/main/java/org/isoron/uhabits/ReminderAlarmReceiver.java b/app/src/main/java/org/isoron/uhabits/ReminderAlarmReceiver.java index ab0ee593b..f78135202 100644 --- a/app/src/main/java/org/isoron/uhabits/ReminderAlarmReceiver.java +++ b/app/src/main/java/org/isoron/uhabits/ReminderAlarmReceiver.java @@ -1,12 +1,6 @@ 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.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -14,148 +8,133 @@ import android.content.BroadcastReceiver; import android.content.ContentUris; import android.content.Context; import android.content.Intent; +import android.graphics.BitmapFactory; import android.media.RingtoneManager; import android.net.Uri; import android.support.v4.app.NotificationCompat; import android.util.Log; +import org.isoron.uhabits.models.Habit; + +import java.util.Date; + public class ReminderAlarmReceiver extends BroadcastReceiver { - - public static String ACTION_CHECK = "org.isoron.uhabits.ACTION_CHECK"; - public static String ACTION_DISMISS = "org.isoron.uhabits.ACTION_DISMISS"; - public static String ACTION_REMIND = "org.isoron.uhabits.ACTION_REMIND"; - public static String ACTION_REMOVE_REMINDER = "org.isoron.uhabits.ACTION_REMOVE_REMINDER"; - public static String ACTION_SNOOZE = "org.isoron.uhabits.ACTION_SNOOZE"; - - @Override - public void onReceive(Context context, Intent intent) - { - String action = intent.getAction(); - - if(action.equals(ACTION_REMIND)) - createNotification(context, intent.getData()); - - else if(action.equals(ACTION_DISMISS)) - dismissAllHabits(); - - else if(action.equals(ACTION_CHECK)) - checkHabit(context, intent.getData()); - - else if(action.equals(ACTION_SNOOZE)) - snoozeHabit(context, intent.getData()); - } - - private void snoozeHabit(Context context, Uri data) - { - int delayMinutes = 15; - Habit habit = Habit.get(ContentUris.parseId(data)); - MainActivity.createReminderAlarm(context, habit, new Date().getTime() + delayMinutes * 1000); - dismissNotification(context); - } - - private void checkHabit(Context context, Uri data) - { - Habit habit = Habit.get(ContentUris.parseId(data)); - habit.toggleRepetitionToday(); - habit.save(); - dismissNotification(context); - } - - private void dismissAllHabits() - { - for(Habit h : Habit.getHighlightedHabits()) - { - Log.d("Alarm", String.format("Removing highlight from: %s", h.name)); - h.highlight = 0; - h.save(); - } - } - - private void dismissNotification(Context context) - { - NotificationManager notificationManager = (NotificationManager) context - .getSystemService(Activity.NOTIFICATION_SERVICE); - - notificationManager.cancel(1); - } - - - private void createNotification(Context context, Uri data) - { - Log.d("Alarm", "Alarm received!"); - - Habit habit = Habit.get(ContentUris.parseId(data)); - - if(habit.hasImplicitRepToday()) - { - Log.d("Alarm", String.format("(%s) has implicit rep today", habit.name)); - return; - } - - Log.d("Alarm", String.format("Applying highlight: %s", habit.name)); - habit.highlight = 1; - habit.save(); - - // Check if reminder has been turned off after alarm was scheduled - if(habit.reminder_hour == null) - return; - - Intent contentIntent = new Intent(context, MainActivity.class); - contentIntent.setData(data); - PendingIntent contentPendingIntent = PendingIntent.getActivity(context, 0, contentIntent, 0); - - Intent deleteIntent = new Intent(context, ReminderAlarmReceiver.class); - deleteIntent.setAction(ACTION_DISMISS); - PendingIntent deletePendingIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0); - - Intent checkIntent = new Intent(context, ReminderAlarmReceiver.class); - checkIntent.setData(data); - checkIntent.setAction(ACTION_CHECK); - PendingIntent checkIntentPending = PendingIntent.getBroadcast(context, 0, checkIntent, 0); - - Intent snoozeIntent = new Intent(context, ReminderAlarmReceiver.class); - snoozeIntent.setData(data); - snoozeIntent.setAction(ACTION_SNOOZE); - PendingIntent snoozeIntentPending = PendingIntent.getBroadcast(context, 0, snoozeIntent, 0); - - Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - - NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); - inboxStyle.setBigContentTitle("Habit Reminder:"); - List pendingHabits = Habit.getHighlightedHabits(); - 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 = - new NotificationCompat.Builder(context) - .setSmallIcon(R.drawable.ic_notification) - .setContentTitle("Habit Reminder") - .setContentText(contentText) - .setContentIntent(contentPendingIntent) - .setDeleteIntent(deletePendingIntent) - .addAction(R.drawable.ic_action_check, "Check", checkIntentPending) - .addAction(R.drawable.ic_action_snooze, "Later", snoozeIntentPending) - .setSound(soundUri) - .setStyle(inboxStyle) - .build(); - - notification.flags |= Notification.FLAG_AUTO_CANCEL; - - NotificationManager notificationManager = (NotificationManager) context - .getSystemService(Activity.NOTIFICATION_SERVICE); - - notificationManager.notify(1, notification); - } + + public static String ACTION_CHECK = "org.isoron.uhabits.ACTION_CHECK"; + public static String ACTION_DISMISS = "org.isoron.uhabits.ACTION_DISMISS"; + public static String ACTION_REMIND = "org.isoron.uhabits.ACTION_REMIND"; + public static String ACTION_REMOVE_REMINDER = "org.isoron.uhabits.ACTION_REMOVE_REMINDER"; + public static String ACTION_SNOOZE = "org.isoron.uhabits.ACTION_SNOOZE"; + + @Override + public void onReceive(Context context, Intent intent) + { + String action = intent.getAction(); + + if (action.equals(ACTION_REMIND)) createNotification(context, intent.getData()); + + else if (action.equals(ACTION_DISMISS)) dismissAllHabits(); + + else if (action.equals(ACTION_CHECK)) checkHabit(context, intent.getData()); + + else if (action.equals(ACTION_SNOOZE)) snoozeHabit(context, intent.getData()); + } + + private void snoozeHabit(Context context, Uri data) + { + int delayMinutes = 60; + Habit habit = Habit.get(ContentUris.parseId(data)); + MainActivity.createReminderAlarm(context, habit, + new Date().getTime() + delayMinutes * 60 * 1000); + dismissNotification(context, habit); + } + + private void checkHabit(Context context, Uri data) + { + Habit habit = Habit.get(ContentUris.parseId(data)); + habit.toggleRepetitionToday(); + habit.save(); + dismissNotification(context, habit); + } + + private void dismissAllHabits() + { + for (Habit h : Habit.getHighlightedHabits()) + { + h.highlight = 0; + h.save(); + } + } + + private void dismissNotification(Context context, Habit habit) + { + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Activity.NOTIFICATION_SERVICE); + + int notificationId = (int) (habit.getId() % Integer.MAX_VALUE); + notificationManager.cancel(notificationId); + } + + + private void createNotification(Context context, Uri data) + { + + Habit habit = Habit.get(ContentUris.parseId(data)); + + if (habit.hasImplicitRepToday()) return; + + Log.d("Alarm", String.format("Applying highlight: %s", habit.name)); + habit.highlight = 1; + habit.save(); + + // Check if reminder has been turned off after alarm was scheduled + if (habit.reminder_hour == null) return; + + Intent contentIntent = new Intent(context, MainActivity.class); + contentIntent.setData(data); + PendingIntent contentPendingIntent = + PendingIntent.getActivity(context, 0, contentIntent, 0); + + Intent deleteIntent = new Intent(context, ReminderAlarmReceiver.class); + deleteIntent.setAction(ACTION_DISMISS); + PendingIntent deletePendingIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0); + + Intent checkIntent = new Intent(context, ReminderAlarmReceiver.class); + checkIntent.setData(data); + checkIntent.setAction(ACTION_CHECK); + PendingIntent checkIntentPending = PendingIntent.getBroadcast(context, 0, checkIntent, 0); + + Intent snoozeIntent = new Intent(context, ReminderAlarmReceiver.class); + snoozeIntent.setData(data); + snoozeIntent.setAction(ACTION_SNOOZE); + PendingIntent snoozeIntentPending = PendingIntent.getBroadcast(context, 0, snoozeIntent, 0); + + Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + + NotificationCompat.WearableExtender wearableExtender = + new NotificationCompat.WearableExtender().setBackground( + BitmapFactory.decodeResource(context.getResources(), R.drawable.stripe)); + + Notification notification = + new NotificationCompat.Builder(context).setSmallIcon(R.drawable.ic_notification) + .setContentTitle(habit.name) + .setContentText(habit.description) + .setContentIntent(contentPendingIntent) + .setDeleteIntent(deletePendingIntent) + .addAction(R.drawable.ic_action_check, "Check", checkIntentPending) + .addAction(R.drawable.ic_action_snooze, "Later", snoozeIntentPending) + .setSound(soundUri) + .extend(wearableExtender) + .build(); + + notification.flags |= Notification.FLAG_AUTO_CANCEL; + + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Activity.NOTIFICATION_SERVICE); + + int notificationId = (int) (habit.getId() % Integer.MAX_VALUE); + notificationManager.notify(notificationId, notification); + } } diff --git a/app/src/main/java/org/isoron/uhabits/dialogs/ListHabitsFragment.java b/app/src/main/java/org/isoron/uhabits/dialogs/ListHabitsFragment.java index e4e63c126..7b87f3de5 100644 --- a/app/src/main/java/org/isoron/uhabits/dialogs/ListHabitsFragment.java +++ b/app/src/main/java/org/isoron/uhabits/dialogs/ListHabitsFragment.java @@ -1,18 +1,5 @@ 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.content.Context; import android.content.Intent; @@ -20,9 +7,9 @@ import android.graphics.Color; import android.graphics.Point; import android.graphics.Typeface; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Vibrator; -import android.transition.Explode; import android.util.DisplayMetrics; import android.util.Log; import android.view.ContextMenu; @@ -50,362 +37,359 @@ import com.mobeta.android.dslv.DragSortController; import com.mobeta.android.dslv.DragSortListView; import com.mobeta.android.dslv.DragSortListView.DropListener; -public class ListHabitsFragment extends Fragment implements OnSavedListener, OnItemClickListener, - OnLongClickListener, DropListener, OnClickListener +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 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; - DragSortListView listView; - MainActivity mainActivity; - TextView tvNameHeader; - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * 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); + + ListHabitsAdapter adapter; + DragSortListView listView; + MainActivity mainActivity; + TextView tvNameHeader; + long lastLongClick = 0; + private int tvNameWidth; + + private int button_count; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) + { + View view = inflater.inflate(R.layout.list_habits_fragment, container, false); + + DisplayMetrics dm = getResources().getDisplayMetrics(); + int width = (int) (dm.widthPixels / dm.density); + button_count = (int) ((width - 160) / 42); + tvNameWidth = (int) ((width - 30 - button_count * 42) * dm.density); + + tvNameHeader = (TextView) view.findViewById(R.id.tvNameHeader); +// updateStarCount(); + + adapter = new ListHabitsAdapter(getActivity()); + listView = (DragSortListView) view.findViewById(R.id.listView); + listView.setAdapter(adapter); + listView.setOnItemClickListener(this); + registerForContextMenu(listView); + listView.setDropListener(this); + + DragSortController controller = new DragSortController(listView); + controller.setDragHandleId(R.id.tvStar); + controller.setRemoveEnabled(false); + controller.setSortEnabled(true); + controller.setDragInitMode(1); + + listView.setFloatViewManager(controller); + listView.setOnTouchListener(controller); + listView.setDragEnabled(true); + + GregorianCalendar day = new GregorianCalendar(TimeZone.getTimeZone("GMT")); + day.setTimeInMillis(DateHelper.getStartOfDay(DateHelper.getLocalTime())); + + for (int i = 0; i < button_count; i++) + { + View check = inflater.inflate(R.layout.list_habits_header_check, null); + Button btCheck = (Button) check.findViewById(R.id.tvCheck); + btCheck.setText( + day.getDisplayName(GregorianCalendar.DAY_OF_WEEK, GregorianCalendar.SHORT, + Locale.US) + "\n" + + Integer.toString(day.get(GregorianCalendar.DAY_OF_MONTH))); + ((LinearLayout) view.findViewById(R.id.llButtonsHeader)).addView(check); + + day.add(GregorianCalendar.DAY_OF_MONTH, -1); + } + + mainActivity = (MainActivity) getActivity(); + + setHasOptionsMenu(true); + return view; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) + { + inflater.inflate(R.menu.show_habits_options, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) + { + super.onCreateContextMenu(menu, view, menuInfo); + getActivity().getMenuInflater().inflate(R.menu.show_habits_context, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + int id = item.getItemId(); + + if (id == R.id.action_add) + { + EditHabitFragment frag = EditHabitFragment.createHabitFragment(); + frag.setOnSavedListener(this); + frag.show(getFragmentManager(), "dialog"); + return true; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public boolean onContextItemSelected(MenuItem menuItem) + { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuItem.getMenuInfo(); + final int id = menuItem.getItemId(); + final Habit habit = Habit.get(info.id); + + if (id == R.id.action_edit_habit) + { + EditHabitFragment frag = EditHabitFragment.editSingleHabitFragment(habit.getId()); + frag.setOnSavedListener(this); + frag.show(getFragmentManager(), "dialog"); + return true; + } + + return super.onContextItemSelected(menuItem); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) + { + if (new Date().getTime() - lastLongClick < 1000) return; + + Habit habit = Habit.getByPosition(position); + Log.d("ItemClick", Long.toString(id)); + + Intent intent = new Intent(getActivity(), ShowHabitActivity.class); + intent.setData(Uri.parse("content://org.isoron.uhabits/habit/" + habit.getId())); + startActivity(intent); + } + + @Override + public void onSaved(Command command) + { + executeCommand(command); + MainActivity.createReminderAlarms(mainActivity); + } + + public void notifyDataSetChanged() + { + adapter.notifyDataSetChanged(); + } + + @Override + public boolean onLongClick(View v) + { + int id = v.getId(); + + if (id == R.id.tvCheck) + { + lastLongClick = new Date().getTime(); + Habit habit = Habit.get((Long) v.getTag(R.string.habit_key)); + int offset = (Integer) v.getTag(R.string.offset_key); + long timestamp = DateHelper.getStartOfDay( + DateHelper.getLocalTime() - offset * DateHelper.millisecondsInOneDay); + + executeCommand(habit.new ToggleRepetitionCommand(timestamp)); + + Vibrator vb = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE); + vb.vibrate(100); + + return true; + } + + return false; + } + + private void executeCommand(Command c) + { + mainActivity.executeCommand(c); + } + + @Override + public void drop(int from, int to) + { + Habit.reorder(from, to); + notifyDataSetChanged(); + } + + @Override + public void onClick(View v) + { + } + + void updateStarCount() + { + Log.d("StarCount", "updating star count"); + String msg = ""; + int starCount = Habit.getStarCount(); + + if (starCount == 1) msg = String.format("%d star", starCount); + else if (starCount > 1) msg = String.format("%d stars", starCount); + + 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) 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 - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) - { - View view = inflater.inflate(R.layout.list_habits_fragment, container, false); - - DisplayMetrics dm = getResources().getDisplayMetrics(); - int width = (int) (dm.widthPixels / dm.density); - button_count = (int) ((width - 160) / 42); - tvNameWidth = (int) ((width - 30 - button_count * 42) * dm.density); - - tvNameHeader = (TextView) view.findViewById(R.id.tvNameHeader); -// updateStarCount(); - adapter = new ListHabitsAdapter(getActivity()); - listView = (DragSortListView) view.findViewById(R.id.listView); - listView.setAdapter(adapter); - listView.setOnItemClickListener(this); - registerForContextMenu(listView); - listView.setDropListener(this); - - DragSortController controller = new DragSortController(listView); - controller.setDragHandleId(R.id.tvStar); - controller.setRemoveEnabled(false); - controller.setSortEnabled(true); - controller.setDragInitMode(1); - - listView.setFloatViewManager(controller); - listView.setOnTouchListener(controller); - listView.setDragEnabled(true); - - GregorianCalendar day = new GregorianCalendar(TimeZone.getTimeZone("GMT")); - day.setTimeInMillis(DateHelper.getStartOfDay(DateHelper.getLocalTime())); - - for (int i = 0; i < button_count; i++) - { - View check = inflater.inflate(R.layout.list_habits_header_check, null); - Button btCheck = (Button) check.findViewById(R.id.tvCheck); - btCheck.setText(day.getDisplayName(GregorianCalendar.DAY_OF_WEEK, - GregorianCalendar.SHORT, Locale.US) + "\n" - + Integer.toString(day.get(GregorianCalendar.DAY_OF_MONTH))); - ((LinearLayout) view.findViewById(R.id.llButtonsHeader)).addView(check); - - day.add(GregorianCalendar.DAY_OF_MONTH, -1); - } - - mainActivity = (MainActivity) getActivity(); - - setHasOptionsMenu(true); - return view; - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) - { - inflater.inflate(R.menu.show_habits_options, menu); - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) - { - super.onCreateContextMenu(menu, view, menuInfo); - getActivity().getMenuInflater().inflate(R.menu.show_habits_context, menu); - } - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Callback * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - @Override - public boolean onOptionsItemSelected(MenuItem item) - { - int id = item.getItemId(); - - if(id == R.id.action_add) - { - EditHabitFragment frag = EditHabitFragment.createHabitFragment(); - frag.setOnSavedListener(this); - frag.show(getFragmentManager(), "dialog"); - return true; - } - - return super.onOptionsItemSelected(item); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) - { - AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuItem.getMenuInfo(); - final int id = menuItem.getItemId(); - final Habit habit = Habit.get(info.id); - - if(id == R.id.action_edit_habit) - { - EditHabitFragment frag = EditHabitFragment.editSingleHabitFragment(habit.getId()); - frag.setOnSavedListener(this); - frag.show(getFragmentManager(), "dialog"); - return true; - } - - return super.onContextItemSelected(menuItem); - } - - long lastLongClick = 0; - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) - { - if(new Date().getTime() - lastLongClick < 1000) return; - - Habit habit = Habit.getByPosition(position); - Log.d("ItemClick", Long.toString(id)); - - Intent intent = new Intent(getActivity(), ShowHabitActivity.class); - intent.setData(Uri.parse("content://org.isoron.uhabits/habit/" - + habit.getId())); - startActivity(intent); - } - - @Override - public void onSaved(Command command) - { - executeCommand(command); - MainActivity.createReminderAlarms(mainActivity); - } - - public void notifyDataSetChanged() - { - adapter.notifyDataSetChanged(); - } - - @Override - public boolean onLongClick(View v) - { - int id = v.getId(); - - if(id == R.id.tvCheck) - { - lastLongClick = new Date().getTime(); - Habit habit = Habit.get((Long) v.getTag(R.string.habit_key)); - int offset = (Integer) v.getTag(R.string.offset_key); - long timestamp = DateHelper.getStartOfDay(DateHelper.getLocalTime() - offset - * DateHelper.millisecondsInOneDay); - - executeCommand(habit.new ToggleRepetitionCommand(timestamp)); - - Vibrator vb = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE); - vb.vibrate(100); - - return true; - } - - return false; - } - - private void executeCommand(Command c) - { - mainActivity.executeCommand(c, false); - notifyDataSetChanged(); - } - - @Override - public void drop(int from, int to) - { - Habit.reorder(from, to); - notifyDataSetChanged(); - } - - @Override - public void onClick(View v) - { - } - - void updateStarCount() - { - Log.d("StarCount", "updating star count"); - String msg = ""; - int starCount = Habit.getStarCount(); - - if(starCount == 1) - msg = String.format("%d star", starCount); - else if(starCount > 1) - msg = String.format("%d stars", starCount); - - tvNameHeader.setText(msg); - } + 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; + } + + } } diff --git a/app/src/main/java/org/isoron/uhabits/dialogs/ShowHabitFragment.java b/app/src/main/java/org/isoron/uhabits/dialogs/ShowHabitFragment.java index 8997d9ed4..782515e1b 100644 --- a/app/src/main/java/org/isoron/uhabits/dialogs/ShowHabitFragment.java +++ b/app/src/main/java/org/isoron/uhabits/dialogs/ShowHabitFragment.java @@ -1,49 +1,42 @@ 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.graphics.Color; -import android.graphics.Typeface; import android.os.Bundle; -import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; 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 { - protected ShowHabitActivity activity; + protected ShowHabitActivity activity; @Override - public void onStart() - { - super.onStart(); - } + public void onStart() + { + super.onStart(); + } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) - { - Log.d("ShowHabitActivity", "Creating view..."); + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) + { + Log.d("ShowHabitActivity", "Creating view..."); - View view = inflater.inflate(R.layout.show_habit, container, false); - activity = (ShowHabitActivity) getActivity(); + View view = inflater.inflate(R.layout.show_habit, container, false); + activity = (ShowHabitActivity) getActivity(); Habit habit = activity.habit; if (android.os.Build.VERSION.SDK_INT >= 21) @@ -52,26 +45,34 @@ public class ShowHabitFragment extends Fragment activity.getWindow().setStatusBarColor(darkerHabitColor); } - TextView tvHistory = (TextView) view.findViewById(R.id.tvHistory); - TextView tvOverview = (TextView) view.findViewById(R.id.tvOverview); - TextView tvStreaks= (TextView) view.findViewById(R.id.tvStreaks); - tvHistory.setTextColor(habit.color); - tvOverview.setTextColor(habit.color); + TextView tvHistory = (TextView) view.findViewById(R.id.tvHistory); + TextView tvOverview = (TextView) view.findViewById(R.id.tvOverview); + TextView tvStrength = (TextView) view.findViewById(R.id.tvStrength); + TextView tvStreaks = (TextView) view.findViewById(R.id.tvStreaks); + tvHistory.setTextColor(habit.color); + tvOverview.setTextColor(habit.color); + tvStrength.setTextColor(habit.color); tvStreaks.setTextColor(habit.color); 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, - (int) activity.getResources().getDimension(R.dimen.square_size)); + (int) activity.getResources().getDimension(R.dimen.small_square_size)); 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)); + (int) activity.getResources().getDimension(R.dimen.small_square_size)); llStreaks.addView(hsv); - return view; - } + return view; + } } diff --git a/app/src/main/java/org/isoron/uhabits/models/Habit.java b/app/src/main/java/org/isoron/uhabits/models/Habit.java index 3ab6ac635..4f770c693 100644 --- a/app/src/main/java/org/isoron/uhabits/models/Habit.java +++ b/app/src/main/java/org/isoron/uhabits/models/Habit.java @@ -3,6 +3,7 @@ package org.isoron.uhabits.models; import android.annotation.SuppressLint; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.os.AsyncTask; import android.util.Log; import com.activeandroid.Cache; @@ -20,6 +21,7 @@ import org.isoron.helpers.Command; import org.isoron.helpers.DateHelper; import org.isoron.uhabits.R; +import java.util.Date; import java.util.List; @Table(name = "Habits") @@ -77,8 +79,7 @@ public class Habit extends Model @SuppressLint("DefaultLocale") public static void updateId(long oldId, long newId) { - SQLiteUtils.execSql(String.format( - "update Habits set Id = %d where Id = %d", newId, oldId)); + SQLiteUtils.execSql(String.format("update Habits set Id = %d where Id = %d", newId, oldId)); } protected static From select() @@ -114,18 +115,13 @@ public class Habit extends Model public static void reorder(int from, int to) { - if (from == to) - return; + 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(); + 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(); @@ -152,13 +148,20 @@ public class Habit extends Model } } + public static void recomputeAllScores() + { + for (Habit habit : getHabits()) + { + habit.deleteScoresNewerThan(0); + } + } + 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); + return SQLiteUtils.intQuery("select count(*) from (select score, max(timestamp) from " + + "score group by habit) as scores where scores.score >= " + + Integer.toString(12973000), args); } @@ -184,14 +187,12 @@ public class Habit extends Model protected From selectReps() { - return new Select().from(Repetition.class).where("habit = ?", getId()) - .orderBy("timestamp"); + 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); + return selectReps().and("timestamp >= ?", timeFrom).and("timestamp <= ?", timeTo); } public boolean hasRep(long timestamp) @@ -236,8 +237,7 @@ public class Habit extends Model 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); + if (counter >= freq_num) checkExtended[i] = Math.max(checkExtended[i], 1); } int check[] = new int[nDays + 1]; @@ -247,6 +247,13 @@ public class Habit extends Model 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() { long today = DateHelper.getStartOfToday(); @@ -282,14 +289,14 @@ public class Habit extends Model public Score getNewestScore() { - return new Select().from(Score.class).where("habit = ?", getId()) - .orderBy("timestamp desc").limit(1).executeSingle(); + 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(); + new Delete().from(Score.class).where("habit = ?", getId()).and("timestamp >= ?", timestamp) + .execute(); } public Integer getScore() @@ -307,8 +314,7 @@ public class Habit extends Model if (newestScore == null) { Repetition oldestRep = getOldestRep(); - if (oldestRep == null) - return 0; + if (oldestRep == null) return 0; beginningTime = oldestRep.timestamp; beginningScore = 0; } else @@ -318,8 +324,7 @@ public class Habit extends Model } long nDays = (today - beginningTime) / day; - if (nDays < 0) - return newestScore.score; + if (nDays < 0) return newestScore.score; int reps[] = getReps(beginningTime, today); @@ -343,13 +348,26 @@ public class Habit extends Model return lastScore; } + public List getScores(long fromTimestamp, long toTimestamp) + { + return getScores(fromTimestamp, toTimestamp, 1, 0); + } + + public List 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() { - 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 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" + @@ -436,8 +454,8 @@ public class Habit extends Model this.modified = new Habit(modified); this.original = new Habit(Habit.this); - hasIntervalChanged = (this.original.freq_den != this.modified.freq_den - || this.original.freq_num != this.modified.freq_num); + hasIntervalChanged = (this.original.freq_den != this.modified.freq_den || + this.original.freq_num != this.modified.freq_num); } public void execute() @@ -446,7 +464,30 @@ public class Habit extends Model habit.copyAttributes(modified); habit.save(); if (hasIntervalChanged) - habit.deleteScoresNewerThan(0); + { + new AsyncTask() + { + @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() @@ -455,7 +496,28 @@ public class Habit extends Model habit.copyAttributes(original); habit.save(); if (hasIntervalChanged) - habit.deleteScoresNewerThan(0); + { + new AsyncTask() + { + @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() diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitHistoryView.java b/app/src/main/java/org/isoron/uhabits/views/HabitHistoryView.java index c7e958499..68c9bd082 100644 --- a/app/src/main/java/org/isoron/uhabits/views/HabitHistoryView.java +++ b/app/src/main/java/org/isoron/uhabits/views/HabitHistoryView.java @@ -1,233 +1,233 @@ 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.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Rect; -import android.graphics.Typeface; import android.support.v4.view.MotionEventCompat; -import android.util.Log; import android.view.MotionEvent; 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 { - private Habit habit; - private int reps[]; + private Habit habit; + private int reps[]; - private Context context; - private Paint pSquareBg, pSquareFg, pTextHeader; + private Context context; + private Paint pSquareBg, pSquareFg, pTextHeader; private int squareSize, squareSpacing; - private int nColumns, offsetWeeks; - - private int colorPrimary, colorPrimaryBrighter, grey; - - public HabitHistoryView(Context context, Habit habit, int squareSize) - { - super(context); - this.habit = habit; - this.context = context; - this.squareSize = squareSize; - - Typeface fontawesome = Typeface.createFromAsset(context.getAssets(), - "fontawesome-webfont.ttf"); - - colorPrimary = habit.color; - colorPrimaryBrighter = ColorHelper.mixColors(colorPrimary, Color.WHITE, 0.5f); - grey = Color.rgb(230, 230, 230); - squareSpacing = 2; - - pTextHeader = new Paint(); - pTextHeader.setColor(Color.LTGRAY); - pTextHeader.setTextAlign(Align.LEFT); - pTextHeader.setTextSize(squareSize * 0.5f); - pTextHeader.setAntiAlias(true); - - pSquareBg = new Paint(); - pSquareBg.setColor(habit.color); - - pSquareFg = new Paint(); - pSquareFg.setColor(Color.WHITE); - pSquareFg.setAntiAlias(true); -// pSquareFg.setTypeface(fontawesome); - pSquareFg.setTextSize(squareSize * 0.5f); - pSquareFg.setTextAlign(Align.CENTER); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) - { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - setMeasuredDimension(getMeasuredWidth(), 8 * squareSize); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) - { + private int nColumns, offsetWeeks; + + private int colorPrimary, colorPrimaryBrighter, grey; + private Float prevX, prevY; + + public HabitHistoryView(Context context, Habit habit, int squareSize) + { + super(context); + this.habit = habit; + this.context = context; + this.squareSize = squareSize; + + colorPrimary = habit.color; + colorPrimaryBrighter = ColorHelper.mixColors(colorPrimary, Color.WHITE, 0.5f); + grey = Color.rgb(230, 230, 230); + squareSpacing = 2; + + pTextHeader = new Paint(); + pTextHeader.setColor(Color.LTGRAY); + pTextHeader.setTextAlign(Align.LEFT); + pTextHeader.setTextSize(squareSize * 0.5f); + pTextHeader.setAntiAlias(true); + + pSquareBg = new Paint(); + pSquareBg.setColor(habit.color); + + pSquareFg = new Paint(); + pSquareFg.setColor(Color.WHITE); + pSquareFg.setAntiAlias(true); + pSquareFg.setTextSize(squareSize * 0.5f); + pSquareFg.setTextAlign(Align.CENTER); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) + { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(getMeasuredWidth(), 8 * squareSize); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) + { nColumns = (w / squareSize) - 1; - fetchReps(); - } - - private void fetchReps() - { - Calendar currentDate = new GregorianCalendar(); - currentDate.add(Calendar.DAY_OF_YEAR, -offsetWeeks * 7); - int dayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK) % 7; - - long dateTo = DateHelper.getStartOfToday(); - for (int i = 0; i < 7 - dayOfWeek; i++) - dateTo += DateHelper.millisecondsInOneDay; - - for (int i = 0; i < offsetWeeks * 7; i++) - dateTo -= DateHelper.millisecondsInOneDay; - - long dateFrom = dateTo; - for (int i = 0; i < nColumns * 7; i++) - dateFrom -= DateHelper.millisecondsInOneDay; - - reps = habit.getReps(dateFrom, dateTo); - } - - @Override - protected void onDraw(Canvas canvas) - { - super.onDraw(canvas); - - Rect square = new Rect(0, 0, squareSize - squareSpacing, squareSize - squareSpacing); - - Calendar currentDate = new GregorianCalendar(); - currentDate.add(Calendar.DAY_OF_YEAR, -(offsetWeeks-1) * 7); - - int nDays = nColumns * 7; - int todayWeekday = new GregorianCalendar().get(Calendar.DAY_OF_WEEK) % 7; - - currentDate.add(Calendar.DAY_OF_YEAR, -nDays); - - SimpleDateFormat dfMonth = new SimpleDateFormat("MMM"); - SimpleDateFormat dfYear = new SimpleDateFormat("yyyy"); - - String previousMonth = ""; - String previousYear = ""; - - int colors[] = { grey, colorPrimaryBrighter, colorPrimary }; - String markers[] = { 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 headerTextOffset = pTextHeader.getFontSpacing() * 0.3f; - boolean justPrintedYear = false; - - int k = nDays; - for (int i = 0; i < nColumns; i++) - { - String month = dfMonth.format(currentDate.getTime()); - String year = dfYear.format(currentDate.getTime()); - - if(!month.equals(previousMonth)) - { - int offset = 0; - if(justPrintedYear) - offset += squareSize; - - canvas.drawText(month, square.left + offset, square.bottom - headerTextOffset, - pTextHeader); - previousMonth = month; - justPrintedYear = false; - } - else if(!year.equals(previousYear)) - { - canvas.drawText(year, square.left, square.bottom - headerTextOffset, pTextHeader); - previousYear = year; - justPrintedYear = true; - } - else - { - justPrintedYear = false; - } - - - square.offset(0, squareSize); - - for (int j = 0; j < 7; j++) - { - if(!(i == nColumns - 1 && offsetWeeks == 0 && j > todayWeekday)) - { - pSquareBg.setColor(colors[reps[k]]); - 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)), - square.centerX(), square.centerY() + squareTextOffset, pSquareFg); - } - - currentDate.add(Calendar.DAY_OF_MONTH, 1); - square.offset(0, squareSize); - k--; - } - - square.offset(squareSize, -8 * squareSize); - } - - String wdays[] = { "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri" }; - - for (int i = 0; i < 7; i++) - { - square.offset(0, squareSize); - canvas.drawText(wdays[i], square.left + headerTextOffset, square.bottom - - headerTextOffset, pTextHeader); - } - } - - private Float prevX, prevY; - - @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; - - int newOffsetWeeks = offsetWeeks + (int) (dx / squareSize); - newOffsetWeeks = Math.max(0, newOffsetWeeks); - - if(newOffsetWeeks != offsetWeeks) - { - prevX = x; - prevY = y; - offsetWeeks = newOffsetWeeks; - - fetchReps(); - invalidate(); - } - - } - return true; - } - + fetchReps(); + } + + private void fetchReps() + { + Calendar currentDate = new GregorianCalendar(); + currentDate.add(Calendar.DAY_OF_YEAR, -offsetWeeks * 7); + int dayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK) % 7; + + long dateTo = DateHelper.getStartOfToday(); + for (int i = 0; i < 7 - dayOfWeek; i++) + dateTo += DateHelper.millisecondsInOneDay; + + for (int i = 0; i < offsetWeeks * 7; i++) + dateTo -= DateHelper.millisecondsInOneDay; + + long dateFrom = dateTo; + for (int i = 0; i < nColumns * 7; i++) + dateFrom -= DateHelper.millisecondsInOneDay; + + reps = habit.getReps(dateFrom, dateTo); + } + + @Override + protected void onDraw(Canvas canvas) + { + super.onDraw(canvas); + + Rect square = new Rect(0, 0, squareSize - squareSpacing, squareSize - squareSpacing); + + Calendar currentDate = new GregorianCalendar(); + currentDate.add(Calendar.DAY_OF_YEAR, - (offsetWeeks - 1) * 7); + + int nDays = nColumns * 7; + int todayWeekday = new GregorianCalendar().get(Calendar.DAY_OF_WEEK) % 7; + + currentDate.add(Calendar.DAY_OF_YEAR, -nDays); + currentDate.add(Calendar.DAY_OF_YEAR, -todayWeekday); + + SimpleDateFormat dfMonth = new SimpleDateFormat("MMM"); + SimpleDateFormat dfYear = new SimpleDateFormat("yyyy"); + + String previousMonth = ""; + String previousYear = ""; + + int colors[] = {grey, colorPrimaryBrighter, colorPrimary}; + String markers[] = + {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 headerTextOffset = pTextHeader.getFontSpacing() * 0.3f; + boolean justPrintedYear = false; + + int k = nDays; + for (int i = 0; i < nColumns; i++) + { + String month = dfMonth.format(currentDate.getTime()); + String year = dfYear.format(currentDate.getTime()); + + if (!month.equals(previousMonth)) + { + int offset = 0; + if (justPrintedYear) offset += squareSize; + + canvas.drawText(month, square.left + offset, square.bottom - headerTextOffset, + pTextHeader); + previousMonth = month; + justPrintedYear = false; + } else if (!year.equals(previousYear)) + { + canvas.drawText(year, square.left, square.bottom - headerTextOffset, pTextHeader); + previousYear = year; + justPrintedYear = true; + } else + { + justPrintedYear = false; + } + + + square.offset(0, squareSize); + + for (int j = 0; j < 7; j++) + { + if (!(i == nColumns - 1 && offsetWeeks == 0 && j > todayWeekday)) + { + pSquareBg.setColor(colors[reps[k]]); + canvas.drawRect(square, pSquareBg); + canvas.drawText(Integer.toString(currentDate.get(Calendar.DAY_OF_MONTH)), + square.centerX(), square.centerY() + squareTextOffset, pSquareFg); + } + + currentDate.add(Calendar.DAY_OF_MONTH, 1); + square.offset(0, squareSize); + k--; + } + + square.offset(squareSize, -8 * squareSize); + } + + String wdays[] = {"Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri"}; + + for (int i = 0; i < 7; i++) + { + square.offset(0, squareSize); + canvas.drawText(wdays[i], square.left + headerTextOffset, + square.bottom - headerTextOffset, pTextHeader); + } + } + + @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 newOffsetWeeks = offsetWeeks + (int) (dx / squareSize); + newOffsetWeeks = Math.max(0, newOffsetWeeks); + + if (newOffsetWeeks != offsetWeeks) + { + offsetWeeks = newOffsetWeeks; + fetchReps(); + invalidate(); + return true; + } + else + return false; + } } diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java b/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java new file mode 100644 index 000000000..324044243 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java @@ -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 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; + } +} diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java b/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java index c90a96bd0..ec02a7a40 100644 --- a/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java +++ b/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java @@ -5,6 +5,8 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; +import android.support.v4.view.MotionEventCompat; +import android.view.MotionEvent; import android.view.View; import org.isoron.helpers.ColorHelper; @@ -22,6 +24,7 @@ public class HabitStreakView extends View private Paint pText, pBar; private long streaks[]; + private int dataOffset; private long streakStart[], streakEnd[], streakLength[]; private long maxStreakLength; @@ -29,6 +32,8 @@ public class HabitStreakView extends View private int barHeaderHeight; private int[] colors; + private float prevX; + private float prevY; public HabitStreakView(Context context, Habit habit, int columnWidth) { @@ -98,7 +103,7 @@ public class HabitStreakView extends View float lineHeight = pText.getFontSpacing(); 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"); String previousMonth = ""; @@ -125,4 +130,51 @@ public class HabitStreakView extends View 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; + } } diff --git a/app/src/main/java/org/isoron/uhabits/views/RingView.java b/app/src/main/java/org/isoron/uhabits/views/RingView.java index a672e899e..07315657f 100644 --- a/app/src/main/java/org/isoron/uhabits/views/RingView.java +++ b/app/src/main/java/org/isoron/uhabits/views/RingView.java @@ -28,11 +28,8 @@ public class RingView extends View pRing.setColor(color); pRing.setAntiAlias(true); pRing.setTextAlign(Paint.Align.CENTER); - pRing.setTextSize(size * 0.15f); this.label = label; - - lineHeight = pRing.getFontSpacing(); } @Override @@ -52,16 +49,19 @@ public class RingView extends View 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); + 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); + 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); } } diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 7bc14b13c5bec1ca23b106ee562ba20b20a0ae57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3812 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%0A5@c8PTfP1}=*(1%Y;zE|9KO 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 diff --git a/app/src/main/res/drawable/stripe.png b/app/src/main/res/drawable/stripe.png new file mode 100644 index 0000000000000000000000000000000000000000..16dd9fc72dd689685870e62f9add69508824d05a GIT binary patch literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^A3&Ii8Av)?Gcp1xmUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5l;8~T32_xoJs=#t_W%F? zE;8Htfr5-l-tI0;Y1}m_K+Zu=7srr{dvC8V6g=#};}R&jgXQ~VA*Q0g+l5XmC=|5X z)E#FLvnev(|LS|#{ttJ4{YgoGTf2Yr=DvOLH#>VEpeDSC_e3=BiE7>x?z|^fvpvb4 zGiiOH*S=$#JC7T}(NCG@Pm1SEK40i(cigh_YQvr^hd5J(|Mebr1t}2l#CpQkCDX1< ziVE_+_l4Qr4Fax#_*tI1Gbhad+o%i$*`B&9RkuDVj{d~`@w1h5%&)RzK+iCEy85}S Ib4q9e0Kut)Gynhq literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/show_habit.xml b/app/src/main/res/layout/show_habit.xml index f1f631dab..bca7927bf 100644 --- a/app/src/main/res/layout/show_habit.xml +++ b/app/src/main/res/layout/show_habit.xml @@ -1,21 +1,35 @@ + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="@color/windowBackground" + android:fillViewport="true"> - + + android:text="@string/overview"/> + + + + + + @@ -24,13 +38,13 @@ + android:text="@string/history"/> + android:orientation="horizontal"/> @@ -38,13 +52,13 @@ + android:text="@string/streaks"/> + android:orientation="horizontal"/> \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c2cd08fa02612b4b7b4e487ecd31c764367f9ee2 GIT binary patch literal 2985 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a9fcd24c7bfe990ab7b50464c9049e027468f4ce GIT binary patch literal 4240 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 n4|&K#9`cZfJmet{OXL3mqL*`0`Vdx z+$YmgReJ8f_}84o|M|e8#ll(lLT=QhU{*I2V(`m9 zNP8pW<^Upu9T5N&AyU}CZEY(ti^QVPKVWU^V-}Ug{hpI3UaXru`ilj+gAM(9Q{0@0 z$AgZ#k4`XK^bzx}Zdd_HI|*#=d&?L)um(pa`(E9Jv7BsywT?{t!(0qpSX|ZC`7D0) z!)g2vJxSHAO{P*WGV~Lx*m1#Gjh#(Kt}o)`DX)*CW6$cYwFGO=XxDfCsQ7l3Q7lp) z$XY2;C0%fiJt85;xH%jf5omRy+&X%`WOEU56VQHv6_RwyKFzpUa(Et*f+93>fc18{X07-iw2*br===Ls@n5kf2T9+D-O2e{A?0BK)2kpSf05SgN5;)skvI(ypMS{W6j6#@p0Zw5c{El!4{i6VV519TQyEC+Mk z{pKpq?J}Xu;|nVd&`FBW3;@>L8}-J&*Y9m^7!c9xsINmz)nLIc`BOJGY49Q-muQU9 zsV?-U)GN`(ay@jVVH9a=FiXT9K2I*J^I+Bj#jGDR!S{Ri+5x8~ zw~*cLISY}A-LOke>gI51>Yf~$p6;-tdd8-2A33?+%E9(YN z@$H)g%psLZHRT@7!RV}qG1coU7GHwUTm7>k`gHsu zQFqNz`1WI9pq|M2{u3uErE|gT=IeZI{S`|~>%0K&i^ICLeRsD|e$N>ddvXa8~?Vs93 z|3CZ{I(^&Yy2Pd<7?SJbj(Hhk`FVO}_6Rg-(znvcqf1^M8)9@2cNm3wl-N%z83RFv{hz zBDJ@IQ9VbS3*`-_>^Y5^^mlVwysgv3M=GxJ3OH?Rh|-4QQjooTNtJjk9Lsk!VZ)Ig zrX?YBS*o9O8NG3NLil*dVw9(e1!F$PE$wq2Ka7tL(|@@(-O(M9Io^K+2V3Bh)qLOa zh_YkiT=pspK1-7>6@6vg-DKpQCdPN_tZlA%TNSt2z#=&@$8U(oUdxuZAXV2>r% zuA4=a-%EDoiUh(^WW!wGz22FfNA~m4n$)?;`&Dk&a*w~iA7T@S%-+N1!sX6sa#kN1 zEUZlH>WurK-DYSI8b;MncL1vL_M0rKPAq!3F%`J$l$K6cgX0clDN;c%1b8>yc8i*J+UBHEq{Ax)!xsObPq$k#~Q z9IA9(0Vi%?LX=B$YfOgpY-&?nIHck5NU#5>i!og{d69ExQ5{q^^XJOUQu2Xw?K>jx zsWua{yvseZ7L~v%t~yD*#>qXO%lIE=&T+bw`KGZrx1ZLt@;^T~U0Bb04+4!?)ZcGg zKSG+MazEZg?XA+(XtuNr3ra2Cpw4oiuG2QQk`{CYGH7vL9x5m1GW^)lIvCs2)YI);}6v1?{W`C^}HlTKDT zu*Ad#O_Fd7z3DIC%ltKZ(TL!b8P1I?(-gOPC>9C7bp(LhG&|`+2FznhuSasRc4Uj> zVE@eTC#C7trwYE7mh0VOp;2}Vsd5&zea;8TuA@?uAo7EZheZ~R;+$Ia0-{j|%4DSX z1!!EA(xn=OnOTh^uZem? z_fV!GI+sc0`(YLl_!;~mV0)VD|z1B}eY~n8irUl1d z<`}@p4PWnO{9^HbVFO9$RbV^wQVC@cq{b>Q*$liY(1we ztsFiiH2YMF*}Tg~U!DmDE3!-=%#iJWs=!6*;Y1{z``eDyW@GP&A*aPO{Iz5@VNTWe zd=_tAF358yayCu0U)tRZ9d>7Pfxs8sK!ox#-S2)iemP?ov@%zS_Plc z`Hi#ip#Ga(R&=A}Lu3)|@E+_BZ=tEW)})t3{hXG83=l#@sL2&&O;2PE4?vV5>P@hR zaN*zTtn%Z7^2V(Pn#D<)3LB_{e|H8aXTm>M={f*6_8J(Qo9l!Qw?L4yYas@6gv(RN zr0OdoP&$DELP!+^!kx}Pz>n`V{8kbf`%xK2(3YY&7i1wcIE7bg%pY?AmiIo6uD8q8s+; z@M!K&+2Bcgem!8WATy06&*h0>XK8lDVIbjspcPKv%I{dt?L5-U-O>efD8=}BfFjXV&wl zEozjF83JRUBA$FWOvgUZl@!p2O@_=7Dp12d#hx*x6fZGoO!3m7cHXUIsz^9J%#tTQ z|14SVmC&p&747Nx`X}k}ctZ@QSWt`^5p&kcggwiJ^ygRY4}>Euk&i- zJ*jSN3K>R2NP*KaVpM&R+L#DfLjZ-Uz0?gSire->&-3AxnC4|b&pr{M*;4Bp$3gbL zUg+6PzC~sG-~Rh%HUYT7Bi3|hu}DWyzrqs?x77=!aQY*L(worS+w9as;CyG`uwp`= zTLqE|*x0X}=11%9GI3W-7sA@UZ$fT7ULx3*p3~=8c6KKsI06)qgXwQ8!Ds>0_iliB zN=~H~by^IQ&bT6T6He@p-{ZgwrV}cQ81D_}fSyNUvrO3G5j4T$0wgh7MVMn9kgaeH z4(iLC4eu}d13d^GZ{d}rSLm(@}|F{75tQzi|lULW=!508*3`aQ_2oZ zpG*A-mp&SJ{D-Rwk`cwo)3G}-cw;hpae}|O47(z=qC^{mY?Yg8ij}nmIKzOUhgltZ zxh_<~mUt4$dmV{Vmw!|)JqZxyq7kJ{AMTD9b`jbo3zaHKTyLy&eq9l%M7PhPLLFCV zmx&97OXfia# zLm8?yQ7adJH50z>=&DAP>p~sXU4qRi;rKxDsHaIqT_2bzEhB?Tf@7ZOFNJ?_TMqCB zCD1^SIw%rQ_V_P)0~oPtWl2a({8%N?J~2MF1t~K4Hd8`#b^nCUU|3FYrg;c zO&V3cdM<9&ozX1#TE8Xh2tkH_*D_h9lV!@F{IAdz*jPu92k?30kr$psy1&dIgfg7Y7b^7EDz<# zTOU_0-8&wsfp^K43S^# z`AhRCqIZ4dV_>5k7`^%=+GC#f1c)=*BJd~qMTSTx6aGeBS7QsfX;w zQ5YsZTe=4Zivmc&y1ome$#!7?ie<1SjDYugauVs;=XB)&&U4+?@ZJqn|)>Up*3tcx~DxFea}#9n|97JlW9e(q82 zM%(^1)lh_H9aP9Rc4B0FzxNU`xM7M{|l-8 z0Z$(EKHY`O1Hy2t`PE!oGV^Q?e?jQK(xLl+P4ga}88{)?p)N1OI zfGP6fQH~7F$|mv-qffbuQ6lTaE?7_9OhxP*)T}^X#}d}8c+uNnk2h%RR@ki)0FLTz zY(l)iYhh}Jg>OlJ&oen6XvhD2FVSjJBP6<*k(V&YXl(?1T-GSigs4H3Q| zfcD$2zHXfF+3e&#O;vpAzrZ&{DxJjzu@wrNj5X&J3f|DrUehy2cKUSSW+znt1|qoemy*cqJ7X|kfUuRU2oDWK2Z@3NMM$7#I=lNHJ+K)08^b3T zjl}=nCGrJ@IIL?WAXY>r$M+?bDr8`>2_KCTW#t4tH?`o|KAK}OXT9rAL>R}vv$Mh8 ze=kA|gD$;?n9576H=f>&f#xiVKqt8REt%sl&$tHJ1wRB)4)U2wG9Y&VoyXeC+;@Td z`VUm+-4p_eF>Jmt=7d)tW@mA$jygL_vX}q`6mnsylyvglK3^>1KnAbk3zRf5@w8eB z;AloS0Rau)zUSt&4SJSlWw=m1tqXn3QSBhlS>`ChMTsrbQvux=BKl`)Fb2DLZY1;*@R^(Yf=N7b!U?8bdf_HF z1$alA%;h=p-d%cn@?~-`}{(TdRHU&Zx0kz@- zyfhJrSXye1VV$6tVJ5I1Yfj~W1%%jr&QCI77=)gYtSCdY<2XeOiTu!CQ;Fmj+_DMqY zM*?L)v-D^$!l4Hc6Ls8=voUI-MVHRi(cqv=V_q=1VcSn|#s>fpKgRGB zTxz}LBdDfqS7h732}q zs`rRT?+a>kUKF(p?(-6dbjOU?r4Ca1$6ZiDp|RQ7hDw*uaB8@|&sRf7tO>!5{e?M; zRG&OPh~jYE@3;~&m2W@K6IrQ%yvum)?NPi8dy$QT$AS(Jc)*CYC90#Amb;uFn@_Qu zgw#i+XD6*y1{RKev){TP$}^8C7m5<4@7ue@`M7z3+lP?(l`M}{&$2d~bqQo3tArwPt!RgA?&w4;A z&Gt2u`R3`PsV5>vHs~}TO#Zik5=+4XmdhLxr+VITiJiL;B)vQINxx;NIg`27Prr^1I#Ky+Pit`~_IT0H4ftG(@$ z<>jLa*VvMWDQv8R5`9$OmOnHna~`Y*f_%5>r>>q}9|wK2u#hEIc>M)>*Y6{wL~jIK z+g6B5Hvjos{Fn5E-r8xoYut0sk3)yVSOb&t4lOx$7l;gf$|#`=V|UI4A@gT$=LuAU zYzs9jLf{bjIDm}>ReaveobX=vL3okSJiPt8=5M-&NJBbPmFF*8(-YnM_4!j?<$Pt7 zeOcD(UZ$h7@Yxpt^`fA$pz(W!0`R|L#PX1J;uELMS$Vczr8k``rlp!_?~%xz_5i0& zkA^4b)i;?25o2)saFWpn_~~rVZEP^oYhEe0_ti zK^o6M$yx+C{5bj>8+#W4n1ewoN?rXQK;bn3{S9Xz$Ip*Tmj=JrM!rE}k2{EBqI{4O zQHs))*2`VI=MJiGg%xM;ODofmVu0?d_cIA#{c3xRsj4e{16O74q=BO9Zw+0`St`AB z2stry#tCiJ>sA; z^%$^3>K2+q+^v{8Y_GQDyn1Jjo`J*y<6FZBgsyl4-n|dc&pi)dD(dwsp95Vv z%$~d*GHc@7qVtVy9XjHJV_C5gb*IuKG&nafiL@d5JPy+4eta9dR9$pFi3@lo=3Q1 zl<*m*WSBMGRX@y!*IJ*&s!53=`8gHD+Ex5ntI5aMyb7?Y<9An8&((!unAfA=h+D%l z{gN)TdKJyO!Rki;5X$n3CGHfWs#{oLl82MlnE@vtWv$1-jFJVpgJTVxA}{Qw3Zt~L zCJAgU7@vkx8Bx6+|4pI}u{=BbDv!CbIeErHq1#&wYR;hJotzU)m~m9`9nZ=K6cgF_ z> zgRlVro>mGtEHUQl>_9BN2o#T<0fjwUs4Cu#UIcPE1ypsH?9GI(5v$-~q>dI+pB|b>H-z&Ytc`nqj-L~ZFP`FnSN_i1 z5D7M?=Rq>->(yrr?<7}jO@9n>uwD;1Tg0v!DC!heWm(vfx*yP-4JRU0{XAc2G$mOm z0^LM5gej!yJ5xN9g>H4bM)^5C-KDL-vF_z~D4Ogyap&V|=oWwtf-_?Ji^{D0Y!IAHGOKi89 z4(CaDuFi;R%=ogR(U8wU72BXyqHHk5O}cqPW~G_(Dz8O(*7Ib+Ffk2G z%7e#U1vXNXhWyJ_Lr)DT9(IUYAnfo9o< z)aq77RQZKhly!d4w|B{Vk=31T3U_fEpBOz@ym?8C;1t{VFg@l+K8yPry~y5uRgtJ1 z&2>OCS+jz*5p7(vRROJ2scsdwiZg;EQK6@OE@u7q{ZCwH+XUhBKT!N5J7W{lq|ey> zcjk5L;h_Qczuv5^PXm^cU!P2Y{POnGn0JxTAHHPL{r9kus zBB;;s?qlG6g{5AMikr+6M21XXv$4+2&v|a!3L-)t|G@Y6pDFlOybQ;a`}$Xp>5sAn zo{W%Sn~%P(n&fewX^A29$(|rsHp!tS^zM~w_ZhOHqi;J!uW1w&!>?0@9bB$+Oo?#$ zWendOs671R#`MS7u3+r4EAxNc;dtgr%y^7^!4~v7Z=ZHD2=OQgCiH{*{xO(5Ep<}X zDO5b@IDa{kXX53d%;>;X40J**sH!iIiy1vLga7!e2zkL!h&ya`zs~y!%I>-T9Qn72 z8=w!uhJ#51N5>Vv4 zRVG!c6+b<>u%0JH6g=H0>!%|8cav*O=xmm~>#j~A-ORf&NCZ2+u0!vmMLsd_1Z&Bb zp;Ij!QQZj`MiF7oa%7D%DLshN1d>2e0Qg~5i^Jk&P7^-}h?{?NYMAz@)`3dI@ol*Y zGF5=8Yk(*)pv;yS%5;&h-&?3+g?gba5OC2H^(|EQedG|`s`_>EZ>KF?Skodbo1&a^ zS!7p3Vr|JbJqTO+31;bi>~^-cPyXaIXem_(IEcZE@6_J)Bw;8bo)-b58O_= zDNVa-_-W_neIrk1?zZH^9I(@Fi>gGrmZCn(5=!^^gDG43oHzZebG$v1H5&V8Oke&M zEAKsq*x>rl0$4t;y&p+*^U>j?s@awc&Rd(gKhvsd0Mkm=ad8S@?em(0 z8$9$~rGa_YcGr^)29F*-EttN!>i_}g#q@|I>0?1oQ3EZyI9O&ntAUM`SJeCXHK$~z ze-NfME_^|@IN>g4NAOo;G^a_*v?k@0+*!H)wyRwV%JYu6<22;*r^?%sZ!YWIyzn@JLqP?aiDkPA zfpqi0vndbc_0$(87Ca-K3LK$!@S8~DafBJyvpWWYScCXs zj-h}h*e|HXdt*Y;RE{l9lzt7V=f*QZ^Lq!_(&C-00vP*0;TSsM!ZPb#m6%1FONCLo z^)LOnJN!x8*T)`9&bfqKJ(k26UqYz!_}w|fISK-J7G1lfvHNAv@q)!W7m$KJphQ9O znFYaZ*Z0j^j*4G=V55a$w>#K1L5BRBH+s?cCxlUF#J#c%i#IJF0Ll>b6;SM`v9PRr z@3cK`xJ^nc9Q~XaYVBvD8rW!DMp-`O0#FS$Rr-jiG3!M93|mb%KKP*#&4Ml3iv^~- zG4NE?@rSAozQ`IhUyX9-7xWCG=aTQWH7QsmhZ^fOGCLcnkRX1FF!5C$e07A(uBRbb zFj^s@D*j(xTc-Bv9H&^?aFr<$pBGPE|6F zL!sr#?5GG3nvklVfcIOnR#Rr=H9=BZpxbh84BhUZ81^`nA@%}IDMEl?WO-{zTGVp3 zk2_Sw_BQ-t0t;0ArNBPA;x$-O`N6yr$z!7JZ!)?j$qmNH0kw)Hyj)h`BEG^@3qs%n z0G4NTZ^d_)MZozF(H6xRinaP4=3yE?I*cxmmPFr0!v$UG)4Ih#=T7lJiV`|K3OdIU zl+=7-oxQ;H$=Y~8$x@I+`x<8kTE7PWwNT;Xl?l+c4mSO1EY*&AO|DeeZi?yfy9X_7 z7lk=;kW@tnNHr%&$!?_iG+5q0L0&?BRZ26N`vE%5lej@|ZB_B|rNYpDYeW}CWEXv| z961(}tJ-TI*g(N#_;0qSq-?^8eOxpWUXXqZgLv6`$VAon9hg=yvl{A&wc8rFXna0r z2J3~)dvfX#LvylK$CCqi;>5))Q^{Yu{6($*elcgi!lI&j?YNMpSSs80+%4ove0fxi zI^WFZusQlEIqa!V%u_qQq|p{2yD;xmTwrngk_}hqr$BDsR;bYrc2C}LYtQ;QWJA*E zxBVqQoVvz~5D-?$YA4Moy7jaDxfRtFnosuJWmMXoAfqngOs>sy2mfE!v$I1tr@rX3 z?3={#rXJE@Z5RTur$Vb2aGBkvvscN;{rI>;;G1k)VRYAY&q~{)H>tISfB3MmOH8A1)(wg;ei&x zFK%`qn)O$;8@np%hM}i&z%pDsX z@_)0Q)PPiwqk9C6*hKX2JfsC0DgACo9JRzq<3FQGHk?1`-vTqRw6D-d<;ja6PE+{& zPuV^(et4%6{vKA8f3`UF=A_f|pH)s7ZZ8h=k38CdFK*X6`sf#=+l%7>=(aD4nircH zy2~O5nZF>QEe7)hSrq#=ez6z1jndrD2^gRaWD9MUOn(gwWH9_Yzvn)#dM*2**8d)g zBovh0)|%mI-6F7Vvf!+j=-*68zZZRe_LX`M`NEB;B~Jjfie%OZb!xC95uC3vqvL`3 zT!{G_iUfo6oUga#jO$l<3EaKp^{@dg(EvPa$g6e6ze6AQYNQdE;j+K6Nf|3X8U(1- zZ~;9(|DQW+3wgbMVA#<%!D>d*z5pYdktThsIUF8d>#;UG30PknyK8p7K?Z0tsp8(- zT%2$7fO}XJ^sbnk7k)8#>ad{xAC&$3R{_!WWPjQ%-7P+PH$M;4+`Yk&=9lzqyMhca zD?bpoXA?Ul@Kays{&duVd^u~Ipt-p10OgCLwpuyas0pu-nxKSfb7n%rysya2Bk%+o zB4^Ajx>XoyPYH8Kywjali)yw<+8b58bSFllbHmPBnUJooq#RDfa3L^ztBLzO)|<$n zn|N(t#VYZvPnEIw7QB6N3%MRvxl%{s{UWDFM9tPV_1?Q^atDOQj-N%W?okvSGvyzc zuemkHAQtWvu4(yKD*CH`M3wtR9rfx3@s&zMkg00Q0nOgW<|p$d2U^)l5Xx;kM#ZCi~?L?d2M;ab@W2S^IXSPL@>&UA#7 zi8X+n%c%5o5a2p|p`1iR9H6&#ZIw!mN`3Z&-%2ui0RL|TElz>*1FeZ;QQ|FV>0p#w zAW|F+^Rq3sw{a9hM~bT5u?Id{1{N0rUb+G5pM4It2IKRnu%8&P^(4WWdC2@nL>EuC z3RA$ewKS!2g8nw>O%%8{t-NN72k@;7<(2*dRsbxFbB;4C - \ No newline at end of file diff --git a/app/src/main/res/values-v21/styles_list_habits.xml b/app/src/main/res/values-v21/styles_list_habits.xml index f82246677..a7ce04361 100644 --- a/app/src/main/res/values-v21/styles_list_habits.xml +++ b/app/src/main/res/values-v21/styles_list_habits.xml @@ -1,20 +1,13 @@ - - + \ No newline at end of file diff --git a/app/src/main/res/values/attrs_dslv.xml b/app/src/main/res/values/attrs_dslv.xml new file mode 100644 index 000000000..eda059eb4 --- /dev/null +++ b/app/src/main/res/values/attrs_dslv.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index f996ac29b..d207cb030 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,54 +1,6 @@ - - 16dp 16dp - - 20dp - - - 64dip - 48dip - 8dip - 4dip - - - 0.82 - 0.85 - 0.16 - 0.19 - 0.81 - 0.60 - 0.83 - 0.17 - 0.14 - 0.11 - 60sp - -30dp - 16sp - 14sp - 6dip - 4dip - 96dip - 48dip - 48dip - 24dip - 270dip - 270dp - 30dp - 155dp - 270dp - 42dp - 50dp - 10sp - 16dp - 45dp - 30dp - 75dp - 30dp - 14dp - 16sp - 16sp - 64dp - 22dp + 20dp + 42dp \ No newline at end of file diff --git a/app/src/main/res/values/dimens_color_picker.xml b/app/src/main/res/values/dimens_color_picker.xml new file mode 100644 index 000000000..27517fbae --- /dev/null +++ b/app/src/main/res/values/dimens_color_picker.xml @@ -0,0 +1,7 @@ + + + 64dip + 48dip + 8dip + 4dip + \ No newline at end of file diff --git a/app/src/main/res/values/dimens_date_time.xml b/app/src/main/res/values/dimens_date_time.xml new file mode 100644 index 000000000..ca2417527 --- /dev/null +++ b/app/src/main/res/values/dimens_date_time.xml @@ -0,0 +1,42 @@ + + + 0.82 + 0.85 + 0.16 + 0.19 + 0.81 + 0.60 + 0.83 + 0.17 + 0.14 + 0.11 + + 60sp + -30dp + 16sp + 14sp + 6dip + 4dip + 96dip + 48dip + 48dip + 24dip + 270dip + 270dp + 30dp + 155dp + 270dp + 42dp + 50dp + 10sp + 16dp + 45dp + 30dp + 75dp + 30dp + 14dp + 16sp + 16sp + 64dp + 22dp + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ce091907f..752a982dd 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -25,20 +25,24 @@ vertical - + + - + + @@ -58,13 +62,16 @@ 3dp - + +