Reorganizing
@@ -1,5 +1,5 @@
|
||||
<?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">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
@@ -12,8 +12,9 @@
|
||||
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<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="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="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
@@ -89,5 +90,4 @@
|
||||
<orderEntry type="library" exported="" name="ActiveAndroid" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-annotations-22.0.0" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
</module>
|
||||
@@ -14,7 +14,7 @@
|
||||
<application
|
||||
android:name="com.activeandroid.app.Application"
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
|
||||
BIN
app/src/main/ic_launcher-web.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
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";
|
||||
|
||||
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<Habit> 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);
|
||||
}
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
ListHabitsAdapter adapter;
|
||||
DragSortListView listView;
|
||||
MainActivity mainActivity;
|
||||
TextView tvNameHeader;
|
||||
long lastLongClick = 0;
|
||||
private int tvNameWidth;
|
||||
|
||||
class ListHabitsAdapter extends BaseAdapter
|
||||
{
|
||||
private int button_count;
|
||||
|
||||
private Context context;
|
||||
private LayoutInflater inflater;
|
||||
private Typeface fontawesome;
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState)
|
||||
{
|
||||
View view = inflater.inflate(R.layout.list_habits_fragment, container, false);
|
||||
|
||||
String habits[] = { "wake up early", "work out", "meditate", "take vitamins",
|
||||
"go to school",
|
||||
"cook dinner & lunch" };
|
||||
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);
|
||||
|
||||
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
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
GregorianCalendar day = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
|
||||
day.setTimeInMillis(DateHelper.getStartOfDay(DateHelper.getLocalTime()));
|
||||
|
||||
day.add(GregorianCalendar.DAY_OF_MONTH, -1);
|
||||
}
|
||||
|
||||
mainActivity = (MainActivity) getActivity();
|
||||
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);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
return view;
|
||||
}
|
||||
day.add(GregorianCalendar.DAY_OF_MONTH, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
|
||||
{
|
||||
inflater.inflate(R.menu.show_habits_options, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
mainActivity = (MainActivity) getActivity();
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo)
|
||||
{
|
||||
super.onCreateContextMenu(menu, view, menuInfo);
|
||||
getActivity().getMenuInflater().inflate(R.menu.show_habits_context, menu);
|
||||
}
|
||||
setHasOptionsMenu(true);
|
||||
return view;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Callback *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
|
||||
{
|
||||
inflater.inflate(R.menu.show_habits_options, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
int id = item.getItemId();
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo)
|
||||
{
|
||||
super.onCreateContextMenu(menu, view, menuInfo);
|
||||
getActivity().getMenuInflater().inflate(R.menu.show_habits_context, menu);
|
||||
}
|
||||
|
||||
if(id == R.id.action_add)
|
||||
{
|
||||
EditHabitFragment frag = EditHabitFragment.createHabitFragment();
|
||||
frag.setOnSavedListener(this);
|
||||
frag.show(getFragmentManager(), "dialog");
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
int id = item.getItemId();
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
if (id == R.id.action_add)
|
||||
{
|
||||
EditHabitFragment frag = EditHabitFragment.createHabitFragment();
|
||||
frag.setOnSavedListener(this);
|
||||
frag.show(getFragmentManager(), "dialog");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem menuItem)
|
||||
{
|
||||
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuItem.getMenuInfo();
|
||||
final int id = menuItem.getItemId();
|
||||
final Habit habit = Habit.get(info.id);
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
if(id == R.id.action_edit_habit)
|
||||
{
|
||||
EditHabitFragment frag = EditHabitFragment.editSingleHabitFragment(habit.getId());
|
||||
frag.setOnSavedListener(this);
|
||||
frag.show(getFragmentManager(), "dialog");
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem menuItem)
|
||||
{
|
||||
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuItem.getMenuInfo();
|
||||
final int id = menuItem.getItemId();
|
||||
final Habit habit = Habit.get(info.id);
|
||||
|
||||
return super.onContextItemSelected(menuItem);
|
||||
}
|
||||
|
||||
long lastLongClick = 0;
|
||||
if (id == R.id.action_edit_habit)
|
||||
{
|
||||
EditHabitFragment frag = EditHabitFragment.editSingleHabitFragment(habit.getId());
|
||||
frag.setOnSavedListener(this);
|
||||
frag.show(getFragmentManager(), "dialog");
|
||||
return true;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
return super.onContextItemSelected(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaved(Command command)
|
||||
{
|
||||
executeCommand(command);
|
||||
MainActivity.createReminderAlarms(mainActivity);
|
||||
}
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
|
||||
{
|
||||
if (new Date().getTime() - lastLongClick < 1000) return;
|
||||
|
||||
public void notifyDataSetChanged()
|
||||
{
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
Habit habit = Habit.getByPosition(position);
|
||||
Log.d("ItemClick", Long.toString(id));
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v)
|
||||
{
|
||||
int id = v.getId();
|
||||
Intent intent = new Intent(getActivity(), ShowHabitActivity.class);
|
||||
intent.setData(Uri.parse("content://org.isoron.uhabits/habit/" + habit.getId()));
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
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);
|
||||
@Override
|
||||
public void onSaved(Command command)
|
||||
{
|
||||
executeCommand(command);
|
||||
MainActivity.createReminderAlarms(mainActivity);
|
||||
}
|
||||
|
||||
executeCommand(habit.new ToggleRepetitionCommand(timestamp));
|
||||
public void notifyDataSetChanged()
|
||||
{
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
Vibrator vb = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vb.vibrate(100);
|
||||
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onLongClick(View v)
|
||||
{
|
||||
int id = v.getId();
|
||||
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
|
||||
private void executeCommand(Command c)
|
||||
{
|
||||
mainActivity.executeCommand(c, false);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
executeCommand(habit.new ToggleRepetitionCommand(timestamp));
|
||||
|
||||
@Override
|
||||
public void drop(int from, int to)
|
||||
{
|
||||
Habit.reorder(from, to);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
Vibrator vb = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vb.vibrate(100);
|
||||
|
||||
@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);
|
||||
}
|
||||
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 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,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 llHistory = (LinearLayout) view.findViewById(R.id.llHistory);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<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()
|
||||
{
|
||||
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<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()
|
||||
@@ -455,7 +496,28 @@ public class Habit extends Model
|
||||
habit.copyAttributes(original);
|
||||
habit.save();
|
||||
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()
|
||||
|
||||
@@ -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 nColumns, offsetWeeks;
|
||||
|
||||
private int colorPrimary, colorPrimaryBrighter, grey;
|
||||
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;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 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)
|
||||
{
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
||||
{
|
||||
nColumns = (w / squareSize) - 1;
|
||||
fetchReps();
|
||||
}
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
long dateFrom = dateTo;
|
||||
for (int i = 0; i < nColumns * 7; i++)
|
||||
dateFrom -= DateHelper.millisecondsInOneDay;
|
||||
|
||||
reps = habit.getReps(dateFrom, dateTo);
|
||||
}
|
||||
reps = habit.getReps(dateFrom, dateTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas)
|
||||
{
|
||||
super.onDraw(canvas);
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas)
|
||||
{
|
||||
super.onDraw(canvas);
|
||||
|
||||
Rect square = new Rect(0, 0, squareSize - squareSpacing, squareSize - squareSpacing);
|
||||
Rect square = new Rect(0, 0, squareSize - squareSpacing, squareSize - squareSpacing);
|
||||
|
||||
Calendar currentDate = new GregorianCalendar();
|
||||
currentDate.add(Calendar.DAY_OF_YEAR, -(offsetWeeks-1) * 7);
|
||||
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;
|
||||
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, -nDays);
|
||||
currentDate.add(Calendar.DAY_OF_YEAR, -todayWeekday);
|
||||
|
||||
SimpleDateFormat dfMonth = new SimpleDateFormat("MMM");
|
||||
SimpleDateFormat dfYear = new SimpleDateFormat("yyyy");
|
||||
SimpleDateFormat dfMonth = new SimpleDateFormat("MMM");
|
||||
SimpleDateFormat dfYear = new SimpleDateFormat("yyyy");
|
||||
|
||||
String previousMonth = "";
|
||||
String previousYear = "";
|
||||
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) };
|
||||
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;
|
||||
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());
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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--;
|
||||
}
|
||||
currentDate.add(Calendar.DAY_OF_MONTH, 1);
|
||||
square.offset(0, squareSize);
|
||||
k--;
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
square.offset(0, squareSize);
|
||||
canvas.drawText(wdays[i], square.left + headerTextOffset, square.bottom
|
||||
- headerTextOffset, pTextHeader);
|
||||
}
|
||||
}
|
||||
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();
|
||||
|
||||
@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);
|
||||
|
||||
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_DOWN)
|
||||
{
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
}
|
||||
if (action == MotionEvent.ACTION_MOVE)
|
||||
{
|
||||
float dx = x - prevX;
|
||||
float dy = y - prevY;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
int newOffsetWeeks = offsetWeeks + (int) (dx / squareSize);
|
||||
newOffsetWeeks = Math.max(0, newOffsetWeeks);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(newOffsetWeeks != offsetWeeks)
|
||||
{
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
offsetWeeks = newOffsetWeeks;
|
||||
|
||||
fetchReps();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
252
app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java
Normal file
@@ -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.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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
BIN
app/src/main/res/drawable/stripe.png
Normal file
|
After Width: | Height: | Size: 344 B |
@@ -1,21 +1,35 @@
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true"
|
||||
android:background="@color/windowBackground">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/windowBackground"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
style="@style/cardsListStyle"
|
||||
tools:context="org.isoron.uhabits.ShowHabitActivity">
|
||||
|
||||
<LinearLayout style="@style/cardStyle"
|
||||
android:id="@+id/llOverview">
|
||||
<LinearLayout
|
||||
android:id="@+id/llOverview"
|
||||
style="@style/cardStyle"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvOverview"
|
||||
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>
|
||||
|
||||
@@ -24,13 +38,13 @@
|
||||
<TextView
|
||||
android:id="@+id/tvHistory"
|
||||
style="@style/cardHeaderStyle"
|
||||
android:text="@string/history" />
|
||||
android:text="@string/history"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llHistory"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal" />
|
||||
android:orientation="horizontal"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/cardStyle">
|
||||
@@ -38,13 +52,13 @@
|
||||
<TextView
|
||||
android:id="@+id/tvStreaks"
|
||||
style="@style/cardHeaderStyle"
|
||||
android:text="@string/streaks" />
|
||||
android:text="@string/streaks"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/llStreaks"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal" />
|
||||
android:orientation="horizontal"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
@@ -14,19 +14,9 @@
|
||||
<style name="MyDialogStyle" parent="android:Theme.Material.Light.Dialog">
|
||||
</style>
|
||||
|
||||
<style name="cardStyle">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<style name="cardStyle" parent="cardBasicStyle">
|
||||
<item name="android:background">@color/white</item>
|
||||
<item name="android:elevation">1dp</item>
|
||||
<item name="android:orientation">vertical</item>
|
||||
<item name="android:paddingTop">16dp</item>
|
||||
<item name="android:paddingBottom">16dp</item>
|
||||
<item name="android:paddingLeft">16dp</item>
|
||||
<item name="android:paddingRight">4dp</item>
|
||||
<item name="android:layout_marginBottom">3dp</item>
|
||||
<item name="android:layout_marginLeft">3dp</item>
|
||||
<item name="android:layout_marginRight">3dp</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -1,20 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="habitsListHeaderStyle">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_alignParentTop">true</item>
|
||||
<style name="habitsListHeaderStyle" parent="habitsListHeaderBasicStyle">
|
||||
<item name="android:background">#f0f0f0</item>
|
||||
<item name="android:elevation">2dp</item>
|
||||
<item name="android:paddingRight">4dp</item>
|
||||
</style>
|
||||
|
||||
<style name="habitsListCheckStyle">
|
||||
<item name="android:focusable">false</item>
|
||||
<item name="android:minHeight">42dp</item>
|
||||
<item name="android:minWidth">42dp</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<style name="habitsListCheckStyle" parent="habitsListCheckBasicStyle">
|
||||
<item name="android:background">@drawable/ripple_background</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
30
app/src/main/res/values/attrs_dslv.xml
Normal file
@@ -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>
|
||||
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
|
||||
<dimen name="square_size">20dp</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>
|
||||
<dimen name="small_square_size">20dp</dimen>
|
||||
<dimen name="check_square_size">42dp</dimen>
|
||||
</resources>
|
||||
7
app/src/main/res/values/dimens_color_picker.xml
Normal file
@@ -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>
|
||||
42
app/src/main/res/values/dimens_date_time.xml
Normal file
@@ -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>
|
||||
</style>
|
||||
|
||||
<style name="cardStyle">
|
||||
<style name="cardBasicStyle">
|
||||
<item name="android:layout_width">match_parent</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: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">1dp</item>
|
||||
<item name="android:layout_marginBottom">3dp</item>
|
||||
<item name="android:layout_marginLeft">3dp</item>
|
||||
<item name="android:layout_marginRight">3dp</item>
|
||||
</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">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
|
||||
@@ -10,11 +10,15 @@
|
||||
<item name="android:background">@color/windowBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="habitsListHeaderStyle">
|
||||
|
||||
<style name="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:paddingRight">4dp</item>
|
||||
</style>
|
||||
|
||||
<style name="habitsListHeaderStyle" parent="habitsListHeaderBasicStyle">
|
||||
<item name="android:background">@drawable/habits_list_header_background</item>
|
||||
</style>
|
||||
|
||||
@@ -58,13 +62,16 @@
|
||||
<item name="android:padding">3dp</item>
|
||||
</style>
|
||||
|
||||
<style name="habitsListCheckStyle">
|
||||
<style name="habitsListCheckBasicStyle">
|
||||
<item name="android:focusable">false</item>
|
||||
<item name="android:minHeight">42dp</item>
|
||||
<item name="android:minWidth">42dp</item>
|
||||
<item name="android:minHeight">@dimen/check_square_size</item>
|
||||
<item name="android:minWidth">@dimen/check_square_size</item>
|
||||
<item name="android:gravity">center</item>
|
||||
</style>
|
||||
|
||||
<style name="habitsListCheckStyle" parent="habitsListCheckBasicStyle">
|
||||
</style>
|
||||
|
||||
<style name="habitsListHeaderCheckStyle" parent="habitsListCheckStyle">
|
||||
<item name="android:layout_width">42dp</item>
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
|
||||