Make models observable, refactor ShowHabitFragment

pull/145/head
Alinson S. Xavier 9 years ago
parent 16dc9c25d2
commit 071cad73d4

@ -36,6 +36,8 @@ import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder; import android.support.v4.app.TaskStackBuilder;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import org.isoron.uhabits.commands.CommandRunner;
import org.isoron.uhabits.commands.ToggleRepetitionCommand;
import org.isoron.uhabits.utils.DateUtils; import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.ReminderUtils; import org.isoron.uhabits.utils.ReminderUtils;
import org.isoron.uhabits.models.Checkmark; import org.isoron.uhabits.models.Checkmark;
@ -115,9 +117,12 @@ public class HabitBroadcastReceiver extends BroadcastReceiver
long habitId = ContentUris.parseId(data); long habitId = ContentUris.parseId(data);
Habit habit = Habit.get(habitId); Habit habit = Habit.get(habitId);
if(habit != null) if(habit != null)
habit.repetitions.toggle(timestamp); {
dismissNotification(context, habitId); ToggleRepetitionCommand command = new ToggleRepetitionCommand(habit, timestamp);
CommandRunner.getInstance().execute(command, habitId);
}
dismissNotification(context, habitId);
sendRefreshBroadcast(context); sendRefreshBroadcast(context);
} }

@ -19,7 +19,6 @@
package org.isoron.uhabits; package org.isoron.uhabits;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.net.Uri; import android.net.Uri;
@ -31,21 +30,18 @@ import android.support.v7.app.ActionBar;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import org.isoron.uhabits.models.Checkmark;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.tasks.ProgressBar; import org.isoron.uhabits.tasks.ProgressBar;
import org.isoron.uhabits.ui.about.AboutActivity;
import org.isoron.uhabits.ui.AndroidProgressBar; import org.isoron.uhabits.ui.AndroidProgressBar;
import org.isoron.uhabits.ui.BaseActivity; import org.isoron.uhabits.ui.BaseActivity;
import org.isoron.uhabits.ui.intro.IntroActivity; import org.isoron.uhabits.ui.about.AboutActivity;
import org.isoron.uhabits.ui.habits.list.ListHabitsFragment; import org.isoron.uhabits.ui.habits.list.ListHabitsFragment;
import org.isoron.uhabits.ui.habits.show.ShowHabitActivity;
import org.isoron.uhabits.ui.intro.IntroActivity;
import org.isoron.uhabits.ui.settings.FilePickerDialog; import org.isoron.uhabits.ui.settings.FilePickerDialog;
import org.isoron.uhabits.ui.settings.SettingsActivity; import org.isoron.uhabits.ui.settings.SettingsActivity;
import org.isoron.uhabits.ui.habits.show.ShowHabitActivity;
import org.isoron.uhabits.utils.FileUtils; import org.isoron.uhabits.utils.FileUtils;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.InterfaceUtils;
import org.isoron.uhabits.widgets.WidgetManager;
import java.io.File; import java.io.File;
@ -196,31 +192,6 @@ public class MainActivity extends BaseActivity
showHabitScreen(habit); showHabitScreen(habit);
} }
@Override
public void onPostExecuteCommand(Long refreshKey)
{
listHabitsFragment.onPostExecuteCommand(refreshKey);
new BaseTask()
{
@Override
protected void doInBackground()
{
dismissNotifications(MainActivity.this);
WidgetManager.updateWidgets(MainActivity.this);
}
}.execute();
}
private void dismissNotifications(Context context)
{
for(Habit h : Habit.getHabitsWithReminder())
{
if(h.checkmarks.getTodayValue() != Checkmark.UNCHECKED)
HabitBroadcastReceiver.dismissNotification(context, h);
}
}
private void showHabitScreen(Habit habit) private void showHabitScreen(Habit habit)
{ {
Intent intent = new Intent(this, ShowHabitActivity.class); Intent intent = new Intent(this, ShowHabitActivity.class);

@ -0,0 +1,75 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.commands;
import org.isoron.uhabits.tasks.BaseTask;
import java.util.LinkedList;
public class CommandRunner
{
public interface Listener
{
void onCommandExecuted(Command command, Long refreshKey);
}
private static CommandRunner singleton;
private LinkedList<Listener> listeners;
private CommandRunner()
{
listeners = new LinkedList<>();
}
public static CommandRunner getInstance()
{
if(singleton == null) singleton = new CommandRunner();
return singleton;
}
public void execute(final Command command, final Long refreshKey)
{
new BaseTask()
{
@Override
protected void doInBackground()
{
command.execute();
}
@Override
protected void onPostExecute(Void aVoid)
{
for(Listener l : listeners)
l.onCommandExecuted(command, refreshKey);
}
}.execute();
}
public void addListener(Listener l)
{
listeners.add(l);
}
public void removeListener(Listener l)
{
listeners.remove(l);
}
}

@ -41,6 +41,7 @@ import java.util.List;
public class CheckmarkList public class CheckmarkList
{ {
private Habit habit; private Habit habit;
public ModelObservable observable = new ModelObservable();
public CheckmarkList(Habit habit) public CheckmarkList(Habit habit)
{ {
@ -59,6 +60,8 @@ public class CheckmarkList
.where("habit = ?", habit.getId()) .where("habit = ?", habit.getId())
.and("timestamp >= ?", timestamp) .and("timestamp >= ?", timestamp)
.execute(); .execute();
observable.notifyListeners();
} }
/** /**

@ -147,6 +147,8 @@ public class Habit extends Model
@NonNull @NonNull
public CheckmarkList checkmarks; public CheckmarkList checkmarks;
public ModelObservable observable = new ModelObservable();
/** /**
* Constructs a habit with the same attributes as the specified habit. * Constructs a habit with the same attributes as the specified habit.
* *
@ -348,6 +350,8 @@ public class Habit extends Model
this.reminderDays = model.reminderDays; this.reminderDays = model.reminderDays;
this.highlight = model.highlight; this.highlight = model.highlight;
this.archived = model.archived; this.archived = model.archived;
observable.notifyListeners();
} }
/** /**
@ -424,6 +428,8 @@ public class Habit extends Model
finally finally
{ {
ActiveAndroid.endTransaction(); ActiveAndroid.endTransaction();
for(Habit h : habits)
h.observable.notifyListeners();
} }
} }
@ -456,6 +462,8 @@ public class Habit extends Model
public static void setColor(@NonNull List<Habit> habits, int color) public static void setColor(@NonNull List<Habit> habits, int color)
{ {
updateAttributes(habits, color, null); updateAttributes(habits, color, null);
for(Habit h : habits)
h.observable.notifyListeners();
} }
/** /**
@ -476,6 +484,7 @@ public class Habit extends Model
reminderHour = null; reminderHour = null;
reminderMin = null; reminderMin = null;
reminderDays = DateUtils.ALL_WEEK_DAYS; reminderDays = DateUtils.ALL_WEEK_DAYS;
observable.notifyListeners();
} }
/** /**

@ -41,6 +41,7 @@ public class RepetitionList
{ {
@NonNull @NonNull
private Habit habit; private Habit habit;
public ModelObservable observable = new ModelObservable();
public RepetitionList(@NonNull Habit habit) public RepetitionList(@NonNull Habit habit)
{ {
@ -105,6 +106,7 @@ public class RepetitionList
habit.scores.invalidateNewerThan(timestamp); habit.scores.invalidateNewerThan(timestamp);
habit.checkmarks.deleteNewerThan(timestamp); habit.checkmarks.deleteNewerThan(timestamp);
habit.streaks.deleteNewerThan(timestamp); habit.streaks.deleteNewerThan(timestamp);
observable.notifyListeners();
} }
private void insert(long timestamp) private void insert(long timestamp)

@ -44,6 +44,7 @@ public class ScoreList
{ {
@NonNull @NonNull
private Habit habit; private Habit habit;
public ModelObservable observable = new ModelObservable();
/** /**
* Constructs a new ScoreList associated with the given habit. * Constructs a new ScoreList associated with the given habit.
@ -75,6 +76,8 @@ public class ScoreList
.where("habit = ?", habit.getId()) .where("habit = ?", habit.getId())
.and("timestamp >= ?", timestamp) .and("timestamp >= ?", timestamp)
.execute(); .execute();
observable.notifyListeners();
} }
/** /**

@ -37,6 +37,7 @@ import java.util.List;
public class StreakList public class StreakList
{ {
private Habit habit; private Habit habit;
public ModelObservable observable = new ModelObservable();
public StreakList(Habit habit) public StreakList(Habit habit)
{ {
@ -156,5 +157,7 @@ public class StreakList
.where("habit = ?", habit.getId()) .where("habit = ?", habit.getId())
.and("end >= ?", timestamp - DateUtils.millisecondsInOneDay) .and("end >= ?", timestamp - DateUtils.millisecondsInOneDay)
.execute(); .execute();
observable.notifyListeners();
} }
} }

@ -19,6 +19,8 @@
package org.isoron.uhabits.tasks; package org.isoron.uhabits.tasks;
import org.isoron.uhabits.commands.CommandRunner;
import org.isoron.uhabits.commands.ToggleRepetitionCommand;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
public class ToggleRepetitionTask extends BaseTask public class ToggleRepetitionTask extends BaseTask
@ -40,7 +42,8 @@ public class ToggleRepetitionTask extends BaseTask
@Override @Override
protected void doInBackground() protected void doInBackground()
{ {
habit.repetitions.toggle(timestamp); ToggleRepetitionCommand command = new ToggleRepetitionCommand(habit, timestamp);
CommandRunner.getInstance().execute(command, habit.getId());
} }
@Override @Override

@ -20,9 +20,9 @@
package org.isoron.uhabits.ui; package org.isoron.uhabits.ui;
import android.app.backup.BackupManager; import android.app.backup.BackupManager;
import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
@ -31,20 +31,21 @@ import android.support.v7.widget.Toolbar;
import android.view.View; import android.view.View;
import android.widget.Toast; import android.widget.Toast;
import org.isoron.uhabits.HabitBroadcastReceiver;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.HabitsApplication;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.commands.Command; import org.isoron.uhabits.commands.Command;
import org.isoron.uhabits.commands.CommandRunner;
import org.isoron.uhabits.models.Checkmark;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.utils.ColorUtils; import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.InterfaceUtils;
import org.isoron.uhabits.widgets.WidgetManager;
import java.util.LinkedList; abstract public class BaseActivity extends AppCompatActivity implements Thread.UncaughtExceptionHandler,
CommandRunner.Listener
abstract public class BaseActivity extends AppCompatActivity implements Thread.UncaughtExceptionHandler
{ {
private static int MAX_UNDO_LEVEL = 15;
private LinkedList<Command> undoList;
private LinkedList<Command> redoList;
private Toast toast; private Toast toast;
Thread.UncaughtExceptionHandler androidExceptionHandler; Thread.UncaughtExceptionHandler androidExceptionHandler;
@ -58,39 +59,20 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
androidExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); androidExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this); Thread.setDefaultUncaughtExceptionHandler(this);
undoList = new LinkedList<>();
redoList = new LinkedList<>();
} }
public void executeCommand(Command command, Long refreshKey) @Override
protected void onResume()
{ {
executeCommand(command, false, refreshKey); super.onResume();
CommandRunner.getInstance().addListener(this);
} }
protected void undo() @Override
{ protected void onPause()
if (undoList.isEmpty())
{
showMessage(R.string.toast_nothing_to_undo);
return;
}
Command last = undoList.pop();
redoList.push(last);
last.undo();
showMessage(last.getUndoStringId());
}
protected void redo()
{ {
if (redoList.isEmpty()) CommandRunner.getInstance().removeListener(this);
{ super.onPause();
showMessage(R.string.toast_nothing_to_redo);
return;
}
Command last = redoList.pop();
executeCommand(last, false, null);
} }
public void showMessage(Integer stringId) public void showMessage(Integer stringId)
@ -101,34 +83,6 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
toast.show(); toast.show();
} }
public void executeCommand(final Command command, Boolean clearRedoStack, final Long refreshKey)
{
undoList.push(command);
if (undoList.size() > MAX_UNDO_LEVEL) undoList.removeLast();
if (clearRedoStack) redoList.clear();
new AsyncTask<Void, Void, Void>()
{
@Override
protected Void doInBackground(Void... params)
{
command.execute();
return null;
}
@Override
protected void onPostExecute(Void aVoid)
{
BaseActivity.this.onPostExecuteCommand(refreshKey);
BackupManager.dataChanged("org.isoron.uhabits");
}
}.execute();
showMessage(command.getExecuteStringId());
}
protected void setupSupportActionBar(boolean homeButtonEnabled) protected void setupSupportActionBar(boolean homeButtonEnabled)
{ {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
@ -146,10 +100,6 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true);
} }
public void onPostExecuteCommand(Long refreshKey)
{
}
@Override @Override
public void uncaughtException(Thread thread, Throwable ex) public void uncaughtException(Thread thread, Throwable ex)
{ {
@ -203,4 +153,29 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
view = findViewById(R.id.headerShadow); view = findViewById(R.id.headerShadow);
if(view != null) view.setVisibility(View.GONE); if(view != null) view.setVisibility(View.GONE);
} }
private void dismissNotifications(Context context)
{
for(Habit h : Habit.getHabitsWithReminder())
{
if(h.checkmarks.getTodayValue() != Checkmark.UNCHECKED)
HabitBroadcastReceiver.dismissNotification(context, h);
}
}
@Override
public void onCommandExecuted(Command command, Long refreshKey)
{
showMessage(command.getExecuteStringId());
new BaseTask()
{
@Override
protected void doInBackground()
{
dismissNotifications(BaseActivity.this);
BackupManager.dataChanged("org.isoron.uhabits");
WidgetManager.updateWidgets(BaseActivity.this);
}
}.execute();
}
} }

@ -42,12 +42,12 @@ import com.android.datetimepicker.time.TimePickerDialog;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.commands.Command; import org.isoron.uhabits.commands.Command;
import org.isoron.uhabits.commands.CommandRunner;
import org.isoron.uhabits.commands.CreateHabitCommand; import org.isoron.uhabits.commands.CreateHabitCommand;
import org.isoron.uhabits.commands.EditHabitCommand; import org.isoron.uhabits.commands.EditHabitCommand;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.utils.ColorUtils; import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.DateUtils;
import java.util.Arrays; import java.util.Arrays;
@ -59,8 +59,6 @@ public class EditHabitDialogFragment extends AppCompatDialogFragment
static final int EDIT_MODE = 0; static final int EDIT_MODE = 0;
static final int CREATE_MODE = 1; static final int CREATE_MODE = 1;
private InterfaceUtils.OnSavedListener onSavedListener;
private Habit originalHabit; private Habit originalHabit;
private Habit modifiedHabit; private Habit modifiedHabit;
@ -202,11 +200,6 @@ public class EditHabitDialogFragment extends AppCompatDialogFragment
} }
} }
public void setOnSavedListener(InterfaceUtils.OnSavedListener onSavedListener)
{
this.onSavedListener = onSavedListener;
}
@Override @Override
public void onClick(View v) public void onClick(View v)
{ {
@ -264,21 +257,17 @@ public class EditHabitDialogFragment extends AppCompatDialogFragment
if (!validate()) return; if (!validate()) return;
Command command = null;
Habit savedHabit = null;
if (mode == EDIT_MODE) if (mode == EDIT_MODE)
{ {
command = new EditHabitCommand(originalHabit, modifiedHabit); Command command = new EditHabitCommand(originalHabit, modifiedHabit);
savedHabit = originalHabit; CommandRunner.getInstance().execute(command, originalHabit.getId());
} }
else if (mode == CREATE_MODE) else if (mode == CREATE_MODE)
{ {
command = new CreateHabitCommand(modifiedHabit); Command command = new CreateHabitCommand(modifiedHabit);
CommandRunner.getInstance().execute(command, null);
} }
if (onSavedListener != null) onSavedListener.onSaved(command, savedHabit);
dismiss(); dismiss();
} }

@ -21,6 +21,8 @@ package org.isoron.uhabits.ui.habits.list;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.isoron.uhabits.commands.Command;
import org.isoron.uhabits.commands.CommandRunner;
import org.isoron.uhabits.utils.DateUtils; import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.tasks.BaseTask; import org.isoron.uhabits.tasks.BaseTask;
@ -28,7 +30,7 @@ import org.isoron.uhabits.tasks.BaseTask;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
public class HabitListLoader public class HabitListLoader implements CommandRunner.Listener
{ {
public interface Listener public interface Listener
{ {
@ -201,4 +203,21 @@ public class HabitListLoader
} }
}.execute(); }.execute();
} }
public void onResume()
{
CommandRunner.getInstance().addListener(this);
}
public void onPause()
{
CommandRunner.getInstance().removeListener(this);
}
@Override
public void onCommandExecuted(Command command, Long refreshKey)
{
if(refreshKey == null) updateAllHabits(true);
else updateHabit(refreshKey);
}
} }

@ -31,13 +31,13 @@ import com.android.colorpicker.ColorPickerSwatch;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.commands.ArchiveHabitsCommand; import org.isoron.uhabits.commands.ArchiveHabitsCommand;
import org.isoron.uhabits.commands.ChangeHabitColorCommand; import org.isoron.uhabits.commands.ChangeHabitColorCommand;
import org.isoron.uhabits.commands.CommandRunner;
import org.isoron.uhabits.commands.DeleteHabitsCommand; import org.isoron.uhabits.commands.DeleteHabitsCommand;
import org.isoron.uhabits.commands.UnarchiveHabitsCommand; import org.isoron.uhabits.commands.UnarchiveHabitsCommand;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.ui.BaseActivity; import org.isoron.uhabits.ui.BaseActivity;
import org.isoron.uhabits.ui.habits.edit.EditHabitDialogFragment; import org.isoron.uhabits.ui.habits.edit.EditHabitDialogFragment;
import org.isoron.uhabits.utils.ColorUtils; import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -48,7 +48,6 @@ public class HabitListSelectionCallback implements ActionMode.Callback
private List<Integer> selectedPositions; private List<Integer> selectedPositions;
private BaseActivity activity; private BaseActivity activity;
private Listener listener; private Listener listener;
private InterfaceUtils.OnSavedListener onSavedListener;
public interface Listener public interface Listener
{ {
@ -67,11 +66,6 @@ public class HabitListSelectionCallback implements ActionMode.Callback
this.listener = listener; this.listener = listener;
} }
public void setOnSavedListener(InterfaceUtils.OnSavedListener onSavedListener)
{
this.onSavedListener = onSavedListener;
}
public void setSelectedPositions(List<Integer> selectedPositions) public void setSelectedPositions(List<Integer> selectedPositions)
{ {
this.selectedPositions = selectedPositions; this.selectedPositions = selectedPositions;
@ -134,64 +128,33 @@ public class HabitListSelectionCallback implements ActionMode.Callback
switch (item.getItemId()) switch (item.getItemId())
{ {
case R.id.action_archive_habit: case R.id.action_archive_habit:
activity.executeCommand(new ArchiveHabitsCommand(selectedHabits), null); archiveHabits(selectedHabits);
mode.finish(); mode.finish();
return true; return true;
case R.id.action_unarchive_habit: case R.id.action_unarchive_habit:
activity.executeCommand(new UnarchiveHabitsCommand(selectedHabits), null); unarchiveHabits(selectedHabits);
mode.finish(); mode.finish();
return true; return true;
case R.id.action_edit_habit: case R.id.action_edit_habit:
{ {
EditHabitDialogFragment editHabit(firstHabit);
frag = EditHabitDialogFragment.editSingleHabitFragment(firstHabit.getId()); mode.finish();
frag.setOnSavedListener(onSavedListener);
frag.show(activity.getSupportFragmentManager(), "editHabit");
return true; return true;
} }
case R.id.action_color: case R.id.action_color:
{ {
int originalAndroidColor = ColorUtils.getColor(activity, firstHabit.color); showColorPicker(mode, selectedHabits, firstHabit);
mode.finish();
ColorPickerDialog picker = ColorPickerDialog.newInstance(
R.string.color_picker_default_title, ColorUtils.getPalette(activity),
originalAndroidColor, 4, ColorPickerDialog.SIZE_SMALL);
picker.setOnColorSelectedListener(new ColorPickerSwatch.OnColorSelectedListener()
{
public void onColorSelected(int androidColor)
{
int paletteColor = ColorUtils.colorToPaletteIndex(activity,
androidColor);
activity.executeCommand(new ChangeHabitColorCommand(selectedHabits,
paletteColor), null);
mode.finish();
}
});
picker.show(activity.getSupportFragmentManager(), "picker");
return true; return true;
} }
case R.id.action_delete: case R.id.action_delete:
{ {
new AlertDialog.Builder(activity).setTitle(R.string.delete_habits) deleteHabits(mode, selectedHabits);
.setMessage(R.string.delete_habits_message) mode.finish();
.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
activity.executeCommand(
new DeleteHabitsCommand(selectedHabits), null);
mode.finish();
}
}).setNegativeButton(android.R.string.no, null)
.show();
return true; return true;
} }
} }
@ -199,6 +162,64 @@ public class HabitListSelectionCallback implements ActionMode.Callback
return false; return false;
} }
private void deleteHabits(final ActionMode mode, final LinkedList<Habit> selectedHabits)
{
new AlertDialog.Builder(activity).setTitle(R.string.delete_habits)
.setMessage(R.string.delete_habits_message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
CommandRunner.getInstance()
.execute(new DeleteHabitsCommand(selectedHabits), null);
mode.finish();
}
})
.setNegativeButton(android.R.string.no, null)
.show();
}
private void showColorPicker(final ActionMode mode, final LinkedList<Habit> selectedHabits,
Habit firstHabit)
{
int originalAndroidColor = ColorUtils.getColor(activity, firstHabit.color);
ColorPickerDialog picker =
ColorPickerDialog.newInstance(R.string.color_picker_default_title,
ColorUtils.getPalette(activity), originalAndroidColor, 4,
ColorPickerDialog.SIZE_SMALL);
picker.setOnColorSelectedListener(new ColorPickerSwatch.OnColorSelectedListener()
{
public void onColorSelected(int androidColor)
{
int paletteColor = ColorUtils.colorToPaletteIndex(activity, androidColor);
CommandRunner.getInstance()
.execute(new ChangeHabitColorCommand(selectedHabits, paletteColor), null);
mode.finish();
}
});
picker.show(activity.getSupportFragmentManager(), "picker");
}
private void editHabit(Habit habit)
{
EditHabitDialogFragment
frag = EditHabitDialogFragment.editSingleHabitFragment(habit.getId());
frag.show(activity.getSupportFragmentManager(), "editHabit");
}
private void unarchiveHabits(LinkedList<Habit> selectedHabits)
{
CommandRunner.getInstance().execute(new UnarchiveHabitsCommand(selectedHabits), null);
}
private void archiveHabits(LinkedList<Habit> selectedHabits)
{
CommandRunner.getInstance().execute(new ArchiveHabitsCommand(selectedHabits), null);
}
@Override @Override
public void onDestroyActionMode(ActionMode mode) public void onDestroyActionMode(ActionMode mode)
{ {

@ -35,17 +35,15 @@ import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.commands.Command; import org.isoron.uhabits.commands.CommandRunner;
import org.isoron.uhabits.commands.ToggleRepetitionCommand; import org.isoron.uhabits.commands.ToggleRepetitionCommand;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.ui.BaseActivity; import org.isoron.uhabits.ui.BaseActivity;
import org.isoron.uhabits.ui.HintManager; import org.isoron.uhabits.ui.HintManager;
import org.isoron.uhabits.ui.habits.edit.EditHabitDialogFragment; import org.isoron.uhabits.ui.habits.edit.EditHabitDialogFragment;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.InterfaceUtils;
import org.isoron.uhabits.utils.InterfaceUtils.OnSavedListener;
import org.isoron.uhabits.utils.ReminderUtils;
public class ListHabitsFragment extends Fragment implements OnSavedListener, OnClickListener, public class ListHabitsFragment extends Fragment implements OnClickListener,
HabitListSelectionCallback.Listener, ListHabitsController.Screen HabitListSelectionCallback.Listener, ListHabitsController.Screen
{ {
private ActionMode actionMode; private ActionMode actionMode;
@ -84,7 +82,6 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnC
{ {
EditHabitDialogFragment frag = (EditHabitDialogFragment) getFragmentManager() EditHabitDialogFragment frag = (EditHabitDialogFragment) getFragmentManager()
.findFragmentByTag("editHabit"); .findFragmentByTag("editHabit");
if(frag != null) frag.setOnSavedListener(this);
} }
return view; return view;
@ -104,12 +101,20 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnC
{ {
super.onResume(); super.onResume();
listView.getLoader().onResume();
listView.refreshData(null); listView.refreshData(null);
helper.updateEmptyMessage(llEmpty); helper.updateEmptyMessage(llEmpty);
helper.updateHeader(llButtonsHeader); helper.updateHeader(llButtonsHeader);
hintManager.showHintIfAppropriate(); hintManager.showHintIfAppropriate();
} }
@Override
public void onPause()
{
listView.getLoader().onPause();
super.onPause();
}
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{ {
@ -146,7 +151,6 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnC
private void showCreateHabitScreen() private void showCreateHabitScreen()
{ {
EditHabitDialogFragment frag = EditHabitDialogFragment.createHabitFragment(); EditHabitDialogFragment frag = EditHabitDialogFragment.createHabitFragment();
frag.setOnSavedListener(this);
frag.show(getFragmentManager(), "editHabit"); frag.show(getFragmentManager(), "editHabit");
} }
@ -155,7 +159,6 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnC
HabitListSelectionCallback callback = HabitListSelectionCallback callback =
new HabitListSelectionCallback(activity, listView.getLoader()); new HabitListSelectionCallback(activity, listView.getLoader());
callback.setSelectedPositions(listView.getSelectedPositions()); callback.setSelectedPositions(listView.getSelectedPositions());
callback.setOnSavedListener(this);
callback.setListener(this); callback.setListener(this);
actionMode = activity.startSupportActionMode(callback); actionMode = activity.startSupportActionMode(callback);
} }
@ -172,26 +175,6 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnC
listView.cancelSelection(); listView.cancelSelection();
} }
@Override
public void onSaved(Command command, Object savedObject)
{
Habit h = (Habit) savedObject;
if (h == null) activity.executeCommand(command, null);
else activity.executeCommand(command, h.getId());
listView.refreshData(null);
ReminderUtils.createReminderAlarms(activity);
finishActionMode();
}
private void executeCommand(Command c, Long refreshKey)
{
activity.executeCommand(c, refreshKey);
}
@Override @Override
public void onClick(View v) public void onClick(View v)
{ {
@ -199,11 +182,6 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnC
hintManager.dismissHint(); hintManager.dismissHint();
} }
public void onPostExecuteCommand(Long refreshKey)
{
listView.refreshData(refreshKey);
}
public ProgressBar getProgressBar() public ProgressBar getProgressBar()
{ {
return progressBar; return progressBar;
@ -224,7 +202,8 @@ public class ListHabitsFragment extends Fragment implements OnSavedListener, OnC
@Override @Override
public void onToggleCheckmark(Habit habit, long timestamp) public void onToggleCheckmark(Habit habit, long timestamp)
{ {
executeCommand(new ToggleRepetitionCommand(habit, timestamp), habit.getId()); CommandRunner.getInstance().execute(new ToggleRepetitionCommand(habit, timestamp),
habit.getId());
} }
@Override @Override

@ -42,12 +42,11 @@ public class ShowHabitActivity extends BaseActivity
habit = Habit.get(ContentUris.parseId(data)); habit = Habit.get(ContentUris.parseId(data));
setContentView(R.layout.show_habit_activity); setContentView(R.layout.show_habit_activity);
setupSupportActionBar(true); setupSupportActionBar(true);
setupHabitActionBar(); setupHabitActionBar();
} }
private void setupHabitActionBar() public void setupHabitActionBar()
{ {
if(habit == null) return; if(habit == null) return;
@ -55,7 +54,6 @@ public class ShowHabitActivity extends BaseActivity
if(actionBar == null) return; if(actionBar == null) return;
actionBar.setTitle(habit.name); actionBar.setTitle(habit.name);
setupActionBarColor(ColorUtils.getColor(this, habit.color)); setupActionBarColor(ColorUtils.getColor(this, habit.color));
} }

@ -31,60 +31,42 @@ import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.Button; import android.widget.Button;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView;
import org.isoron.uhabits.HabitBroadcastReceiver;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.commands.Command; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.ModelObservable;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.ui.habits.edit.EditHabitDialogFragment; import org.isoron.uhabits.ui.habits.edit.EditHabitDialogFragment;
import org.isoron.uhabits.ui.habits.edit.HistoryEditorDialog; import org.isoron.uhabits.ui.habits.edit.HistoryEditorDialog;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.DateUtils; import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.ReminderUtils;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.InterfaceUtils;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.Score;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitDataView;
import org.isoron.uhabits.views.HabitFrequencyView; import org.isoron.uhabits.views.HabitFrequencyView;
import org.isoron.uhabits.views.HabitHistoryView; import org.isoron.uhabits.views.HabitHistoryView;
import org.isoron.uhabits.views.HabitScoreView; import org.isoron.uhabits.views.HabitScoreView;
import org.isoron.uhabits.views.HabitStreakView; import org.isoron.uhabits.views.HabitStreakView;
import org.isoron.uhabits.views.RingView;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class ShowHabitFragment extends Fragment public class ShowHabitFragment extends Fragment
implements InterfaceUtils.OnSavedListener, HistoryEditorDialog.Listener, implements Spinner.OnItemSelectedListener, ModelObservable.Listener
Spinner.OnItemSelectedListener
{ {
@Nullable
protected ShowHabitActivity activity; protected ShowHabitActivity activity;
@Nullable
private Habit habit;
@Nullable @Nullable
private List<HabitDataView> dataViews; private List<HabitDataView> dataViews;
@Nullable
private HabitScoreView scoreView;
private int previousScoreInterval; private int previousScoreInterval;
private float todayScore; Habit habit;
private float lastMonthScore;
private float lastYearScore;
private int activeColor; float todayScore;
private int inactiveColor; float lastMonthScore;
float lastYearScore;
int activeColor;
int inactiveColor;
@Override private ShowHabitHelper helper;
public void onStart()
{
super.onStart();
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
@ -92,37 +74,32 @@ public class ShowHabitFragment extends Fragment
{ {
View view = inflater.inflate(R.layout.show_habit, container, false); View view = inflater.inflate(R.layout.show_habit, container, false);
activity = (ShowHabitActivity) getActivity(); activity = (ShowHabitActivity) getActivity();
helper = new ShowHabitHelper(this);
habit = activity.getHabit(); habit = activity.getHabit();
activeColor = ColorUtils.getColor(getContext(), habit.color); helper.updateColors();
inactiveColor = InterfaceUtils.getStyledColor(getContext(), R.attr.mediumContrastTextColor); helper.updateMainHeader(view);
updateHeader(view);
dataViews = new LinkedList<>();
Button btEditHistory = (Button) view.findViewById(R.id.btEditHistory);
Spinner sStrengthInterval = (Spinner) view.findViewById(R.id.sStrengthInterval);
scoreView = (HabitScoreView) view.findViewById(R.id.scoreView);
int defaultScoreInterval = InterfaceUtils.getDefaultScoreInterval(getContext()); int defaultScoreInterval = InterfaceUtils.getDefaultScoreInterval(getContext());
previousScoreInterval = defaultScoreInterval; previousScoreInterval = defaultScoreInterval;
setScoreBucketSize(defaultScoreInterval); setScoreBucketSize(defaultScoreInterval);
Spinner sStrengthInterval = (Spinner) view.findViewById(R.id.sStrengthInterval);
sStrengthInterval.setSelection(defaultScoreInterval); sStrengthInterval.setSelection(defaultScoreInterval);
sStrengthInterval.setOnItemSelectedListener(this); sStrengthInterval.setOnItemSelectedListener(this);
dataViews.add((HabitScoreView) view.findViewById(R.id.scoreView)); createDataViews(view);
dataViews.add((HabitHistoryView) view.findViewById(R.id.historyView)); helper.updateCardHeaders(view);
dataViews.add((HabitFrequencyView) view.findViewById(R.id.punchcardView));
dataViews.add((HabitStreakView) view.findViewById(R.id.streakView));
updateHeaders(view); bindButtontEditHistory(view);
setHasOptionsMenu(true);
for(HabitDataView dataView : dataViews) return view;
dataView.setHabit(habit); }
private void bindButtontEditHistory(View view)
{
Button btEditHistory = (Button) view.findViewById(R.id.btEditHistory);
btEditHistory.setOnClickListener(new View.OnClickListener() btEditHistory.setOnClickListener(new View.OnClickListener()
{ {
@Override @Override
@ -130,75 +107,21 @@ public class ShowHabitFragment extends Fragment
{ {
HistoryEditorDialog frag = new HistoryEditorDialog(); HistoryEditorDialog frag = new HistoryEditorDialog();
frag.setHabit(habit); frag.setHabit(habit);
frag.setListener(ShowHabitFragment.this);
frag.show(getFragmentManager(), "historyEditor"); frag.show(getFragmentManager(), "historyEditor");
} }
}); });
if(savedInstanceState != null)
{
EditHabitDialogFragment fragEdit = (EditHabitDialogFragment) getFragmentManager()
.findFragmentByTag("editHabit");
HistoryEditorDialog fragEditor = (HistoryEditorDialog) getFragmentManager()
.findFragmentByTag("historyEditor");
if(fragEdit != null) fragEdit.setOnSavedListener(this);
if(fragEditor != null) fragEditor.setListener(this);
}
setHasOptionsMenu(true);
return view;
} }
private void updateHeader(View view) private void createDataViews(View view)
{ {
if(habit == null) return; dataViews = new LinkedList<>();
dataViews.add((HabitScoreView) view.findViewById(R.id.scoreView));
TextView questionLabel = (TextView) view.findViewById(R.id.questionLabel); dataViews.add((HabitHistoryView) view.findViewById(R.id.historyView));
questionLabel.setTextColor(activeColor); dataViews.add((HabitFrequencyView) view.findViewById(R.id.punchcardView));
questionLabel.setText(habit.description); dataViews.add((HabitStreakView) view.findViewById(R.id.streakView));
TextView reminderLabel = (TextView) view.findViewById(R.id.reminderLabel);
if(habit.hasReminder())
reminderLabel.setText(DateUtils.formatTime(getActivity(), habit.reminderHour,
habit.reminderMin));
else
reminderLabel.setText(getResources().getString(R.string.reminder_off));
TextView frequencyLabel = (TextView) view.findViewById(R.id.frequencyLabel);
frequencyLabel.setText(getFreqText());
if(habit.description.isEmpty())
questionLabel.setVisibility(View.GONE);
}
private String getFreqText()
{
if(habit == null)
return "";
if(habit.freqNum.equals(habit.freqDen))
return getResources().getString(R.string.every_day);
if(habit.freqNum == 1)
{
if (habit.freqDen == 7)
return getResources().getString(R.string.every_week);
if (habit.freqDen % 7 == 0)
return getResources().getString(R.string.every_x_weeks, habit.freqDen / 7);
return getResources().getString(R.string.every_x_days, habit.freqDen);
}
String times_every = getResources().getString(R.string.times_every);
if(habit.freqNum == 1)
times_every = getResources().getString(R.string.time_every);
return String.format("%d %s %d %s", habit.freqNum, times_every, habit.freqDen, for(HabitDataView dataView : dataViews)
getResources().getString(R.string.days)); dataView.setHabit(habit);
} }
@Override @Override
@ -208,166 +131,114 @@ public class ShowHabitFragment extends Fragment
refreshData(); refreshData();
} }
private void updateScore(View view) @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{ {
if(habit == null) return; inflater.inflate(R.menu.show_habit_fragment, menu);
if(view == null) return;
float todayPercentage = todayScore / Score.MAX_VALUE;
float monthDiff = todayPercentage - (lastMonthScore / Score.MAX_VALUE);
float yearDiff = todayPercentage - (lastYearScore / Score.MAX_VALUE);
RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing);
int androidColor = ColorUtils.getColor(getActivity(), habit.color);
scoreRing.setColor(androidColor);
scoreRing.setPercentage(todayPercentage);
TextView scoreLabel = (TextView) view.findViewById(R.id.scoreLabel);
TextView monthDiffLabel = (TextView) view.findViewById(R.id.monthDiffLabel);
TextView yearDiffLabel = (TextView) view.findViewById(R.id.yearDiffLabel);
scoreLabel.setText(String.format("%.0f%%", todayPercentage * 100));
String minus = "\u2212";
monthDiffLabel.setText(String.format("%s%.0f%%", (monthDiff >= 0 ? "+" : minus),
Math.abs(monthDiff) * 100));
yearDiffLabel.setText(
String.format("%s%.0f%%", (yearDiff >= 0 ? "+" : minus), Math.abs(yearDiff) * 100));
monthDiffLabel.setTextColor(monthDiff >= 0 ? activeColor : inactiveColor);
yearDiffLabel.setTextColor(yearDiff >= 0 ? activeColor : inactiveColor);
} }
private void updateHeaders(View view) @Override
public boolean onOptionsItemSelected(MenuItem item)
{ {
updateColor(view, R.id.tvHistory); if (item.getItemId() == R.id.action_edit_habit)
updateColor(view, R.id.tvOverview); return showEditHabitDialog();
updateColor(view, R.id.tvStrength);
updateColor(view, R.id.tvStreaks); return false;
updateColor(view, R.id.tvWeekdayFreq);
updateColor(view, R.id.scoreLabel);
} }
private void updateColor(View view, int viewId) private boolean showEditHabitDialog()
{ {
if(habit == null || activity == null) return; if(habit == null) return false;
TextView textView = (TextView) view.findViewById(viewId); EditHabitDialogFragment frag = EditHabitDialogFragment.editSingleHabitFragment(habit.getId());
int androidColor = ColorUtils.getColor(activity, habit.color); frag.show(getFragmentManager(), "editHabit");
textView.setTextColor(androidColor); return true;
} }
@Override public void refreshData()
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{ {
inflater.inflate(R.menu.show_habit_fragment, menu); new RefreshTask().execute();
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{ {
if(habit == null) return false; if(parent.getId() == R.id.sStrengthInterval)
setScoreBucketSize(position);
switch (item.getItemId())
{
case R.id.action_edit_habit:
{
EditHabitDialogFragment
frag = EditHabitDialogFragment.editSingleHabitFragment(habit.getId());
frag.setOnSavedListener(this);
frag.show(getFragmentManager(), "editHabit");
return true;
}
}
return false;
} }
@Override private void setScoreBucketSize(int position)
public void onSaved(Command command, Object savedObject)
{ {
if(activity == null) return; if(getView() == null) return;
Habit h = (Habit) savedObject;
if (h == null) activity.executeCommand(command, null); HabitScoreView scoreView = (HabitScoreView) getView().findViewById(R.id.scoreView);
else activity.executeCommand(command, h.getId()); scoreView.setBucketSize(HabitScoreView.DEFAULT_BUCKET_SIZES[position]);
ReminderUtils.createReminderAlarms(activity); if(position != previousScoreInterval)
HabitBroadcastReceiver.sendRefreshBroadcast(getActivity()); refreshData();
activity.recreate(); InterfaceUtils.setDefaultScoreInterval(getContext(), position);
previousScoreInterval = position;
} }
@Override @Override
public void onHistoryEditorClosed() public void onNothingSelected(AdapterView<?> parent)
{ {
refreshData();
HabitBroadcastReceiver.sendRefreshBroadcast(getActivity());
} }
public void refreshData() @Override
public void onModelChange()
{ {
new BaseTask() refreshData();
activity.runOnUiThread(new Runnable()
{ {
@Override @Override
protected void doInBackground() public void run()
{ {
if(habit == null) return; helper.updateColors();
if(dataViews == null) return; helper.updateMainHeader(getView());
helper.updateCardHeaders(getView());
long today = DateUtils.getStartOfToday(); if(activity != null) activity.setupHabitActionBar();
long lastMonth = today - 30 * DateUtils.millisecondsInOneDay;
long lastYear = today - 365 * DateUtils.millisecondsInOneDay;
todayScore = (float) habit.scores.getTodayValue();
lastMonthScore = (float) habit.scores.getValue(lastMonth);
lastYearScore = (float) habit.scores.getValue(lastYear);
int count = 0;
for(HabitDataView view : dataViews)
{
view.refreshData();
publishProgress(count++);
}
} }
});
@Override
protected void onProgressUpdate(Integer... values)
{
updateScore(getView());
if(dataViews == null) return;
dataViews.get(values[0]).postInvalidate();
}
}.execute();
} }
@Override private class RefreshTask extends BaseTask
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{ {
if(parent.getId() == R.id.sStrengthInterval) @Override
setScoreBucketSize(position); protected void doInBackground()
} {
if(habit == null) return;
if(dataViews == null) return;
private void setScoreBucketSize(int position) long today = DateUtils.getStartOfToday();
{ long lastMonth = today - 30 * DateUtils.millisecondsInOneDay;
if(scoreView == null) return; long lastYear = today - 365 * DateUtils.millisecondsInOneDay;
scoreView.setBucketSize(HabitScoreView.DEFAULT_BUCKET_SIZES[position]); todayScore = (float) habit.scores.getTodayValue();
lastMonthScore = (float) habit.scores.getValue(lastMonth);
lastYearScore = (float) habit.scores.getValue(lastYear);
}
if(position != previousScoreInterval) @Override
protected void onPostExecute(Void aVoid)
{ {
refreshData(); helper.updateScore(getView());
HabitBroadcastReceiver.sendRefreshBroadcast(getActivity()); super.onPostExecute(aVoid);
} }
InterfaceUtils.setDefaultScoreInterval(getContext(), position);
previousScoreInterval = position;
} }
@Override @Override
public void onNothingSelected(AdapterView<?> parent) public void onStart()
{ {
super.onStart();
habit.observable.addListener(this);
}
@Override
public void onPause()
{
habit.observable.removeListener(this);
super.onPause();
} }
} }

@ -0,0 +1,139 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show;
import android.content.res.Resources;
import android.view.View;
import android.widget.TextView;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Score;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
import org.isoron.uhabits.views.RingView;
public class ShowHabitHelper
{
private ShowHabitFragment fragment;
public ShowHabitHelper(ShowHabitFragment fragment)
{
this.fragment = fragment;
}
String getFreqText()
{
if(fragment.habit == null) return "";
Resources resources = fragment.getResources();
Integer freqNum = fragment.habit.freqNum;
Integer freqDen = fragment.habit.freqDen;
if (freqNum.equals(freqDen)) return resources.getString(R.string.every_day);
if (freqNum == 1)
{
if (freqDen == 7) return resources.getString(R.string.every_week);
if (freqDen % 7 == 0) return resources.getString(R.string.every_x_weeks, freqDen / 7);
return resources.getString(R.string.every_x_days, freqDen);
}
String times_every = resources.getString(R.string.time_every);
return String.format("%d %s %d %s", freqNum, times_every, freqDen,
resources.getString(R.string.days));
}
void updateScore(View view)
{
if (fragment.habit == null) return;
if (view == null) return;
float todayPercentage = fragment.todayScore / Score.MAX_VALUE;
float monthDiff = todayPercentage - (fragment.lastMonthScore / Score.MAX_VALUE);
float yearDiff = todayPercentage - (fragment.lastYearScore / Score.MAX_VALUE);
RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing);
int androidColor = ColorUtils.getColor(fragment.getActivity(), fragment.habit.color);
scoreRing.setColor(androidColor);
scoreRing.setPercentage(todayPercentage);
TextView scoreLabel = (TextView) view.findViewById(R.id.scoreLabel);
TextView monthDiffLabel = (TextView) view.findViewById(R.id.monthDiffLabel);
TextView yearDiffLabel = (TextView) view.findViewById(R.id.yearDiffLabel);
scoreLabel.setText(String.format("%.0f%%", todayPercentage * 100));
String minus = "\u2212";
monthDiffLabel.setText(String.format("%s%.0f%%", (monthDiff >= 0 ? "+" : minus),
Math.abs(monthDiff) * 100));
yearDiffLabel.setText(
String.format("%s%.0f%%", (yearDiff >= 0 ? "+" : minus), Math.abs(yearDiff) * 100));
monthDiffLabel.setTextColor(monthDiff >= 0 ? fragment.activeColor : fragment.inactiveColor);
yearDiffLabel.setTextColor(yearDiff >= 0 ? fragment.activeColor : fragment.inactiveColor);
}
void updateMainHeader(View view)
{
if (fragment.habit == null) return;
TextView questionLabel = (TextView) view.findViewById(R.id.questionLabel);
questionLabel.setTextColor(fragment.activeColor);
questionLabel.setText(fragment.habit.description);
TextView reminderLabel = (TextView) view.findViewById(R.id.reminderLabel);
if (fragment.habit.hasReminder()) reminderLabel.setText(
DateUtils.formatTime(fragment.getActivity(), fragment.habit.reminderHour,
fragment.habit.reminderMin));
else reminderLabel.setText(fragment.getResources().getString(R.string.reminder_off));
TextView frequencyLabel = (TextView) view.findViewById(R.id.frequencyLabel);
frequencyLabel.setText(getFreqText());
if (fragment.habit.description.isEmpty()) questionLabel.setVisibility(View.GONE);
}
void updateCardHeaders(View view)
{
updateColor(view, R.id.tvHistory);
updateColor(view, R.id.tvOverview);
updateColor(view, R.id.tvStrength);
updateColor(view, R.id.tvStreaks);
updateColor(view, R.id.tvWeekdayFreq);
updateColor(view, R.id.scoreLabel);
}
void updateColor(View view, int viewId)
{
if(fragment.habit == null || fragment.activity == null) return;
TextView textView = (TextView) view.findViewById(viewId);
int androidColor = ColorUtils.getColor(fragment.activity, fragment.habit.color);
textView.setTextColor(androidColor);
}
void updateColors()
{
fragment.activeColor = ColorUtils.getColor(fragment.getContext(), fragment.habit.color);
fragment.inactiveColor = InterfaceUtils.getStyledColor(fragment.getContext(),
R.attr.mediumContrastTextColor);
}
}

@ -36,7 +36,6 @@ import android.util.TypedValue;
import org.isoron.uhabits.HabitsApplication; import org.isoron.uhabits.HabitsApplication;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.commands.Command;
import java.util.Locale; import java.util.Locale;
@ -55,11 +54,6 @@ public abstract class InterfaceUtils
InterfaceUtils.fixedTheme = fixedTheme; InterfaceUtils.fixedTheme = fixedTheme;
} }
public interface OnSavedListener
{
void onSaved(Command command, Object savedObject);
}
public static Typeface getFontAwesome(Context context) public static Typeface getFontAwesome(Context context)
{ {
if(fontAwesome == null) if(fontAwesome == null)

@ -26,6 +26,8 @@ import android.graphics.RectF;
import android.util.AttributeSet; import android.util.AttributeSet;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.models.ModelObservable;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.utils.ColorUtils; import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.DateUtils; import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.InterfaceUtils;
@ -38,9 +40,8 @@ import java.util.GregorianCalendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.Random; import java.util.Random;
public class HabitFrequencyView extends ScrollableDataView implements HabitDataView public class HabitFrequencyView extends ScrollableDataView implements HabitDataView, ModelObservable.Listener
{ {
private Paint pGrid; private Paint pGrid;
private float em; private float em;
private Habit habit; private Habit habit;
@ -173,10 +174,12 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
public void refreshData() public void refreshData()
{ {
if(isInEditMode()) if(isInEditMode()) generateRandomData();
generateRandomData();
else if(habit != null) else if(habit != null)
{
frequency = habit.repetitions.getWeekdayFrequency(); frequency = habit.repetitions.getWeekdayFrequency();
createColors();
}
postInvalidate(); postInvalidate();
} }
@ -297,4 +300,35 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
this.isBackgroundTransparent = isBackgroundTransparent; this.isBackgroundTransparent = isBackgroundTransparent;
createColors(); createColors();
} }
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.observable.addListener(this);
habit.checkmarks.observable.addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
habit.checkmarks.observable.removeListener(this);
habit.observable.removeListener(this);
super.onDetachedFromWindow();
}
@Override
public void onModelChange()
{
refreshData();
}
} }

@ -30,12 +30,13 @@ import android.view.HapticFeedbackConstants;
import android.view.MotionEvent; import android.view.MotionEvent;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.ModelObservable;
import org.isoron.uhabits.tasks.BaseTask; import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.tasks.ToggleRepetitionTask; import org.isoron.uhabits.tasks.ToggleRepetitionTask;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
@ -43,7 +44,7 @@ import java.util.GregorianCalendar;
import java.util.Random; import java.util.Random;
public class HabitHistoryView extends ScrollableDataView implements HabitDataView, public class HabitHistoryView extends ScrollableDataView implements HabitDataView,
ToggleRepetitionTask.Listener ToggleRepetitionTask.Listener, ModelObservable.Listener
{ {
private Habit habit; private Habit habit;
private int[] checkmarks; private int[] checkmarks;
@ -216,6 +217,7 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
{ {
if(habit == null) return; if(habit == null) return;
checkmarks = habit.checkmarks.getAllValues(); checkmarks = habit.checkmarks.getAllValues();
createColors();
} }
updateDate(); updateDate();
@ -409,4 +411,34 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
} }
}.execute(); }.execute();
} }
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.observable.addListener(this);
habit.checkmarks.observable.addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
habit.checkmarks.observable.removeListener(this);
habit.observable.removeListener(this);
super.onDetachedFromWindow();
}
@Override
public void onModelChange()
{
refreshData();
}
} }

@ -31,18 +31,21 @@ import android.support.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.ModelObservable;
import org.isoron.uhabits.models.Score;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.utils.ColorUtils; import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.DateUtils; import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.InterfaceUtils;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.Score;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Random; import java.util.Random;
public class HabitScoreView extends ScrollableDataView implements HabitDataView public class HabitScoreView extends ScrollableDataView
implements HabitDataView, ModelObservable.Listener
{ {
public static final PorterDuffXfermode XFERMODE_CLEAR = public static final PorterDuffXfermode XFERMODE_CLEAR =
new PorterDuffXfermode(PorterDuff.Mode.CLEAR); new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
@ -195,6 +198,7 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
{ {
if (habit == null) return; if (habit == null) return;
scores = habit.scores.getAllValues(bucketSize); scores = habit.scores.getAllValues(bucketSize);
createColors();
} }
postInvalidate(); postInvalidate();
@ -434,4 +438,34 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
return maxDayWidth; return maxDayWidth;
} }
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.observable.addListener(this);
habit.scores.observable.addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
habit.scores.observable.removeListener(this);
habit.observable.removeListener(this);
super.onDetachedFromWindow();
}
@Override
public void onModelChange()
{
refreshData();
}
} }

@ -28,6 +28,8 @@ import android.util.AttributeSet;
import android.view.View; import android.view.View;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.models.ModelObservable;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.utils.ColorUtils; import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.InterfaceUtils;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
@ -39,7 +41,7 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
public class HabitStreakView extends View implements HabitDataView public class HabitStreakView extends View implements HabitDataView, ModelObservable.Listener
{ {
private Habit habit; private Habit habit;
private Paint paint; private Paint paint;
@ -151,6 +153,7 @@ public class HabitStreakView extends View implements HabitDataView
{ {
if(habit == null) return; if(habit == null) return;
streaks = habit.streaks.getAll(maxStreakCount); streaks = habit.streaks.getAll(maxStreakCount);
createColors();
updateMaxMin(); updateMaxMin();
postInvalidate(); postInvalidate();
} }
@ -246,4 +249,35 @@ public class HabitStreakView extends View implements HabitDataView
this.isBackgroundTransparent = isBackgroundTransparent; this.isBackgroundTransparent = isBackgroundTransparent;
createColors(); createColors();
} }
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.observable.addListener(this);
habit.streaks.observable.addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
habit.streaks.observable.removeListener(this);
habit.observable.removeListener(this);
super.onDetachedFromWindow();
}
@Override
public void onModelChange()
{
refreshData();
}
} }

Loading…
Cancel
Save