mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Improve habit positioning and reordering
This commit is contained in:
@@ -87,6 +87,7 @@ public class ListHabitsFragment extends Fragment
|
|||||||
private boolean isShortToggleEnabled;
|
private boolean isShortToggleEnabled;
|
||||||
|
|
||||||
private HabitListLoader loader;
|
private HabitListLoader loader;
|
||||||
|
boolean showArchived;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
@@ -130,7 +131,7 @@ public class ListHabitsFragment extends Fragment
|
|||||||
((TextView) view.findViewById(R.id.tvStarEmpty)).setTypeface(fontawesome);
|
((TextView) view.findViewById(R.id.tvStarEmpty)).setTypeface(fontawesome);
|
||||||
llEmpty = view.findViewById(R.id.llEmpty);
|
llEmpty = view.findViewById(R.id.llEmpty);
|
||||||
|
|
||||||
loader.updateAllHabits();
|
loader.updateAllHabits(true);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
@@ -152,7 +153,7 @@ public class ListHabitsFragment extends Fragment
|
|||||||
Long timestamp = loader.getLastLoadTimestamp();
|
Long timestamp = loader.getLastLoadTimestamp();
|
||||||
|
|
||||||
if (timestamp != null && timestamp != DateHelper.getStartOfToday())
|
if (timestamp != null && timestamp != DateHelper.getStartOfToday())
|
||||||
loader.updateAllHabits();
|
loader.updateAllHabits(true);
|
||||||
|
|
||||||
updateEmptyMessage();
|
updateEmptyMessage();
|
||||||
updateHeader();
|
updateHeader();
|
||||||
@@ -199,7 +200,7 @@ public class ListHabitsFragment extends Fragment
|
|||||||
inflater.inflate(R.menu.list_habits_options, menu);
|
inflater.inflate(R.menu.list_habits_options, menu);
|
||||||
|
|
||||||
MenuItem showArchivedItem = menu.findItem(R.id.action_show_archived);
|
MenuItem showArchivedItem = menu.findItem(R.id.action_show_archived);
|
||||||
showArchivedItem.setChecked(Habit.isIncludeArchived());
|
showArchivedItem.setChecked(showArchived);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -230,8 +231,9 @@ public class ListHabitsFragment extends Fragment
|
|||||||
|
|
||||||
case R.id.action_show_archived:
|
case R.id.action_show_archived:
|
||||||
{
|
{
|
||||||
Habit.setIncludeArchived(!Habit.isIncludeArchived());
|
showArchived = !showArchived;
|
||||||
loader.updateAllHabits();
|
loader.setIncludeArchived(showArchived);
|
||||||
|
loader.updateAllHabits(true);
|
||||||
activity.invalidateOptionsMenu();
|
activity.invalidateOptionsMenu();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -279,7 +281,7 @@ public class ListHabitsFragment extends Fragment
|
|||||||
{
|
{
|
||||||
if (new Date().getTime() - lastLongClick < 1000) return;
|
if (new Date().getTime() - lastLongClick < 1000) return;
|
||||||
|
|
||||||
Habit habit = loader.positionToHabit.get(position);
|
Habit habit = loader.habitsList.get(position);
|
||||||
habitClickListener.onHabitClicked(habit);
|
habitClickListener.onHabitClicked(habit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,13 +349,9 @@ public class ListHabitsFragment extends Fragment
|
|||||||
@Override
|
@Override
|
||||||
public void drop(int from, int to)
|
public void drop(int from, int to)
|
||||||
{
|
{
|
||||||
Habit fromHabit = loader.positionToHabit.get(from);
|
loader.reorder(from, to);
|
||||||
Habit toHabit = loader.positionToHabit.get(to);
|
|
||||||
loader.positionToHabit.put(to, fromHabit);
|
|
||||||
loader.positionToHabit.put(from, toHabit);
|
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
|
loader.updateAllHabits(false);
|
||||||
Habit.reorder(from, to);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -389,7 +387,7 @@ public class ListHabitsFragment extends Fragment
|
|||||||
@Override
|
@Override
|
||||||
public Object getItem(int position)
|
public Object getItem(int position)
|
||||||
{
|
{
|
||||||
return loader.positionToHabit.get(position);
|
return loader.habitsList.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -401,7 +399,7 @@ public class ListHabitsFragment extends Fragment
|
|||||||
@Override
|
@Override
|
||||||
public View getView(int position, View view, ViewGroup parent)
|
public View getView(int position, View view, ViewGroup parent)
|
||||||
{
|
{
|
||||||
final Habit habit = loader.positionToHabit.get(position);
|
final Habit habit = loader.habitsList.get(position);
|
||||||
|
|
||||||
if (view == null ||
|
if (view == null ||
|
||||||
(Long) view.getTag(R.id.KEY_TIMESTAMP) != DateHelper.getStartOfToday())
|
(Long) view.getTag(R.id.KEY_TIMESTAMP) != DateHelper.getStartOfToday())
|
||||||
@@ -448,15 +446,16 @@ public class ListHabitsFragment extends Fragment
|
|||||||
private void updateCheckmarkButtons(Habit habit, LinearLayout llButtons)
|
private void updateCheckmarkButtons(Habit habit, LinearLayout llButtons)
|
||||||
{
|
{
|
||||||
int activeColor = getActiveColor(habit);
|
int activeColor = getActiveColor(habit);
|
||||||
|
|
||||||
int m = llButtons.getChildCount();
|
int m = llButtons.getChildCount();
|
||||||
int isChecked[] = loader.checkmarks.get(habit.getId());
|
Long habitId = habit.getId();
|
||||||
|
|
||||||
|
int isChecked[] = loader.checkmarks.get(habitId);
|
||||||
|
|
||||||
for (int i = 0; i < m; i++)
|
for (int i = 0; i < m; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
TextView tvCheck = (TextView) llButtons.getChildAt(i);
|
TextView tvCheck = (TextView) llButtons.getChildAt(i);
|
||||||
tvCheck.setTag(R.string.habit_key, habit.getId());
|
tvCheck.setTag(R.string.habit_key, habitId);
|
||||||
tvCheck.setTag(R.string.offset_key, i);
|
tvCheck.setTag(R.string.offset_key, i);
|
||||||
updateCheckmark(activeColor, tvCheck, isChecked[i]);
|
updateCheckmark(activeColor, tvCheck, isChecked[i]);
|
||||||
}
|
}
|
||||||
@@ -529,7 +528,7 @@ public class ListHabitsFragment extends Fragment
|
|||||||
|
|
||||||
public void onPostExecuteCommand(Long refreshKey)
|
public void onPostExecuteCommand(Long refreshKey)
|
||||||
{
|
{
|
||||||
if (refreshKey == null) loader.updateAllHabits();
|
if (refreshKey == null) loader.updateAllHabits(true);
|
||||||
else loader.updateHabit(refreshKey);
|
else loader.updateHabit(refreshKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.isoron.helpers.DateHelper;
|
|||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class HabitListLoader
|
public class HabitListLoader
|
||||||
{
|
{
|
||||||
@@ -44,10 +45,17 @@ public class HabitListLoader
|
|||||||
private Long lastLoadTimestamp;
|
private Long lastLoadTimestamp;
|
||||||
|
|
||||||
public HashMap<Long, Habit> habits;
|
public HashMap<Long, Habit> habits;
|
||||||
public HashMap<Integer, Habit> positionToHabit;
|
public List<Habit> habitsList;
|
||||||
public HashMap<Long, int[]> checkmarks;
|
public HashMap<Long, int[]> checkmarks;
|
||||||
public HashMap<Long, Integer> scores;
|
public HashMap<Long, Integer> scores;
|
||||||
|
|
||||||
|
boolean includeArchived;
|
||||||
|
|
||||||
|
public void setIncludeArchived(boolean includeArchived)
|
||||||
|
{
|
||||||
|
this.includeArchived = includeArchived;
|
||||||
|
}
|
||||||
|
|
||||||
public void setProgressBar(ProgressBar progressBar)
|
public void setProgressBar(ProgressBar progressBar)
|
||||||
{
|
{
|
||||||
this.progressBar = progressBar;
|
this.progressBar = progressBar;
|
||||||
@@ -71,58 +79,88 @@ public class HabitListLoader
|
|||||||
public HabitListLoader()
|
public HabitListLoader()
|
||||||
{
|
{
|
||||||
habits = new HashMap<>();
|
habits = new HashMap<>();
|
||||||
positionToHabit = new HashMap<>();
|
|
||||||
checkmarks = new HashMap<>();
|
checkmarks = new HashMap<>();
|
||||||
scores = new HashMap<>();
|
scores = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetData()
|
public void reorder(int from, int to)
|
||||||
{
|
{
|
||||||
habits.clear();
|
Habit fromHabit = habitsList.get(from);
|
||||||
positionToHabit.clear();
|
Habit toHabit = habitsList.get(to);
|
||||||
checkmarks.clear();
|
|
||||||
scores.clear();
|
habitsList.remove(from);
|
||||||
|
habitsList.add(to, fromHabit);
|
||||||
|
|
||||||
|
Habit.reorder(fromHabit, toHabit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAllHabits()
|
public void updateAllHabits(final boolean updateScoresAndCheckmarks)
|
||||||
{
|
{
|
||||||
if (currentFetchTask != null) currentFetchTask.cancel(true);
|
if (currentFetchTask != null) currentFetchTask.cancel(true);
|
||||||
|
|
||||||
currentFetchTask = new AsyncTask<Void, Integer, Void>()
|
currentFetchTask = new AsyncTask<Void, Integer, Void>()
|
||||||
{
|
{
|
||||||
|
public HashMap<Long, Habit> newHabits;
|
||||||
|
public HashMap<Long, int[]> newCheckmarks;
|
||||||
|
public HashMap<Long, Integer> newScores;
|
||||||
|
public List<Habit> newHabitList;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... params)
|
protected Void doInBackground(Void... params)
|
||||||
{
|
{
|
||||||
resetData();
|
newHabits = new HashMap<>();
|
||||||
|
newCheckmarks = new HashMap<>();
|
||||||
habits = Habit.getAll();
|
newScores = new HashMap<>();
|
||||||
|
newHabitList = Habit.getAll(includeArchived);
|
||||||
|
|
||||||
long dateTo = DateHelper.getStartOfDay(DateHelper.getLocalTime());
|
long dateTo = DateHelper.getStartOfDay(DateHelper.getLocalTime());
|
||||||
long dateFrom = dateTo - (checkmarkCount - 1) * DateHelper.millisecondsInOneDay;
|
long dateFrom = dateTo - (checkmarkCount - 1) * DateHelper.millisecondsInOneDay;
|
||||||
int[] empty = new int[checkmarkCount];
|
int[] empty = new int[checkmarkCount];
|
||||||
|
|
||||||
for (Habit h : habits.values())
|
for(Habit h : newHabitList)
|
||||||
{
|
{
|
||||||
scores.put(h.getId(), 0);
|
Long id = h.getId();
|
||||||
positionToHabit.put(h.position, h);
|
|
||||||
checkmarks.put(h.getId(), empty);
|
newHabits.put(id, h);
|
||||||
|
|
||||||
|
if(checkmarks.containsKey(id))
|
||||||
|
newCheckmarks.put(id, checkmarks.get(id));
|
||||||
|
else
|
||||||
|
newCheckmarks.put(id, empty);
|
||||||
|
|
||||||
|
if(scores.containsKey(id))
|
||||||
|
newScores.put(id, scores.get(id));
|
||||||
|
else
|
||||||
|
newScores.put(id, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commit();
|
||||||
|
|
||||||
|
if(!updateScoresAndCheckmarks) return null;
|
||||||
|
|
||||||
int current = 0;
|
int current = 0;
|
||||||
for (int i = 0; i < habits.size(); i++)
|
for (Habit h : newHabitList)
|
||||||
{
|
{
|
||||||
if (isCancelled()) return null;
|
if (isCancelled()) return null;
|
||||||
|
|
||||||
Habit h = positionToHabit.get(i);
|
Long id = h.getId();
|
||||||
scores.put(h.getId(), h.getScore());
|
newScores.put(id, h.getScore());
|
||||||
checkmarks.put(h.getId(), h.getCheckmarks(dateFrom, dateTo));
|
newCheckmarks.put(id, h.getCheckmarks(dateFrom, dateTo));
|
||||||
|
|
||||||
publishProgress(current++, habits.size());
|
publishProgress(current++, newHabits.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void commit()
|
||||||
|
{
|
||||||
|
habits = newHabits;
|
||||||
|
scores = newScores;
|
||||||
|
checkmarks = newCheckmarks;
|
||||||
|
habitsList = newHabitList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPreExecute()
|
protected void onPreExecute()
|
||||||
{
|
{
|
||||||
@@ -137,10 +175,7 @@ public class HabitListLoader
|
|||||||
progressBar.setMax(values[1]);
|
progressBar.setMax(values[1]);
|
||||||
progressBar.setProgress(values[0]);
|
progressBar.setProgress(values[0]);
|
||||||
|
|
||||||
if (lastLoadTimestamp == null)
|
if(listener != null) listener.onLoadFinished();
|
||||||
{
|
|
||||||
listener.onLoadFinished();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -151,6 +186,8 @@ public class HabitListLoader
|
|||||||
progressBar.setVisibility(View.INVISIBLE);
|
progressBar.setVisibility(View.INVISIBLE);
|
||||||
lastLoadTimestamp = DateHelper.getStartOfToday();
|
lastLoadTimestamp = DateHelper.getStartOfToday();
|
||||||
currentFetchTask = null;
|
currentFetchTask = null;
|
||||||
|
|
||||||
|
if(listener != null) listener.onLoadFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ import org.isoron.helpers.DateHelper;
|
|||||||
import org.isoron.uhabits.R;
|
import org.isoron.uhabits.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Table(name = "Habits")
|
@Table(name = "Habits")
|
||||||
@@ -48,8 +47,6 @@ public class Habit extends Model
|
|||||||
public static final int FULL_STAR_CUTOFF = 12973000;
|
public static final int FULL_STAR_CUTOFF = 12973000;
|
||||||
public static final int MAX_SCORE = 19259500;
|
public static final int MAX_SCORE = 19259500;
|
||||||
|
|
||||||
private static boolean includeArchived = false;
|
|
||||||
|
|
||||||
@Column(name = "name")
|
@Column(name = "name")
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
@@ -100,17 +97,10 @@ public class Habit extends Model
|
|||||||
return Habit.load(Habit.class, id);
|
return Habit.load(Habit.class, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HashMap<Long, Habit> getAll()
|
public static List<Habit> getAll(boolean includeArchive)
|
||||||
{
|
{
|
||||||
List<Habit> habits = select().execute();
|
if(includeArchive) return selectWithArchived().execute();
|
||||||
HashMap<Long, Habit> map = new HashMap<>();
|
else return select().execute();
|
||||||
|
|
||||||
for (Habit h : habits)
|
|
||||||
{
|
|
||||||
map.put(h.getId(), h);
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
@SuppressLint("DefaultLocale")
|
||||||
@@ -121,19 +111,12 @@ public class Habit extends Model
|
|||||||
|
|
||||||
protected static From select()
|
protected static From select()
|
||||||
{
|
{
|
||||||
if (includeArchived) return new Select().from(Habit.class).orderBy("position");
|
return new Select().from(Habit.class).where("archived = 0").orderBy("position");
|
||||||
else return new Select().from(Habit.class).where("archived = 0").orderBy("position");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setIncludeArchived(boolean includeArchived)
|
public static From selectWithArchived()
|
||||||
{
|
{
|
||||||
Habit.includeArchived = includeArchived;
|
return new Select().from(Habit.class).orderBy("position");
|
||||||
rebuildOrder();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isIncludeArchived()
|
|
||||||
{
|
|
||||||
return Habit.includeArchived;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getCount()
|
public static int getCount()
|
||||||
@@ -141,16 +124,6 @@ public class Habit extends Model
|
|||||||
return select().count();
|
return select().count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Habit getByPosition(int position)
|
|
||||||
{
|
|
||||||
return select().offset(position).executeSingle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static java.util.List<Habit> getHabits()
|
|
||||||
{
|
|
||||||
return select().execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static java.util.List<Habit> getHighlightedHabits()
|
public static java.util.List<Habit> getHighlightedHabits()
|
||||||
{
|
{
|
||||||
return select().where("highlight = 1")
|
return select().where("highlight = 1")
|
||||||
@@ -163,25 +136,30 @@ public class Habit extends Model
|
|||||||
return select().where("reminder_hour is not null").execute();
|
return select().where("reminder_hour is not null").execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void reorder(int from, int to)
|
public static void reorder(Habit from, Habit to)
|
||||||
{
|
{
|
||||||
if (from == to) return;
|
if(from == to) return;
|
||||||
|
|
||||||
Habit h = Habit.getByPosition(from);
|
if (to.position < from.position)
|
||||||
if (to < from) new Update(Habit.class).set("position = position + 1")
|
{
|
||||||
.where("position >= ? and position < ?", to, from)
|
new Update(Habit.class).set("position = position + 1")
|
||||||
|
.where("position >= ? and position < ?", to.position, from.position)
|
||||||
.execute();
|
.execute();
|
||||||
else new Update(Habit.class).set("position = position - 1")
|
}
|
||||||
.where("position > ? and position <= ?", from, to)
|
else
|
||||||
|
{
|
||||||
|
new Update(Habit.class).set("position = position - 1")
|
||||||
|
.where("position > ? and position <= ?", from.position, to.position)
|
||||||
.execute();
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
h.position = to;
|
from.position = to.position;
|
||||||
h.save();
|
from.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void rebuildOrder()
|
public static void rebuildOrder()
|
||||||
{
|
{
|
||||||
List<Habit> habits = select().execute();
|
List<Habit> habits = selectWithArchived().execute();
|
||||||
|
|
||||||
ActiveAndroid.beginTransaction();
|
ActiveAndroid.beginTransaction();
|
||||||
try
|
try
|
||||||
@@ -412,10 +390,7 @@ public class Habit extends Model
|
|||||||
public void archive()
|
public void archive()
|
||||||
{
|
{
|
||||||
archived = 1;
|
archived = 1;
|
||||||
position = 9999;
|
|
||||||
save();
|
save();
|
||||||
|
|
||||||
Habit.rebuildOrder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unarchive()
|
public void unarchive()
|
||||||
|
|||||||
Reference in New Issue
Block a user