mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
@@ -40,7 +40,7 @@ public class BundleSavedState extends View.BaseSavedState
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
final Bundle bundle;
|
public final Bundle bundle;
|
||||||
|
|
||||||
public BundleSavedState(Parcelable superState, Bundle bundle)
|
public BundleSavedState(Parcelable superState, Bundle bundle)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ public abstract class ScrollableChart extends View
|
|||||||
|
|
||||||
private int dataOffset;
|
private int dataOffset;
|
||||||
|
|
||||||
private int scrollerBucketSize;
|
private int scrollerBucketSize = 1;
|
||||||
|
|
||||||
|
private int direction = 1;
|
||||||
|
|
||||||
private GestureDetector detector;
|
private GestureDetector detector;
|
||||||
|
|
||||||
@@ -41,6 +43,10 @@ public abstract class ScrollableChart extends View
|
|||||||
|
|
||||||
private ValueAnimator scrollAnimator;
|
private ValueAnimator scrollAnimator;
|
||||||
|
|
||||||
|
private ScrollController scrollController;
|
||||||
|
|
||||||
|
private int maxDataOffset = 10000;
|
||||||
|
|
||||||
public ScrollableChart(Context context)
|
public ScrollableChart(Context context)
|
||||||
{
|
{
|
||||||
super(context);
|
super(context);
|
||||||
@@ -64,8 +70,7 @@ public abstract class ScrollableChart extends View
|
|||||||
if (!scroller.isFinished())
|
if (!scroller.isFinished())
|
||||||
{
|
{
|
||||||
scroller.computeScrollOffset();
|
scroller.computeScrollOffset();
|
||||||
dataOffset = Math.max(0, scroller.getCurrX() / scrollerBucketSize);
|
updateDataOffset();
|
||||||
postInvalidate();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -86,19 +91,44 @@ public abstract class ScrollableChart extends View
|
|||||||
float velocityY)
|
float velocityY)
|
||||||
{
|
{
|
||||||
scroller.fling(scroller.getCurrX(), scroller.getCurrY(),
|
scroller.fling(scroller.getCurrX(), scroller.getCurrY(),
|
||||||
(int) velocityX / 2, 0, 0, 100000, 0, 0);
|
direction * ((int) velocityX) / 2, 0, 0, getMaxX(), 0, 0);
|
||||||
invalidate();
|
invalidate();
|
||||||
|
|
||||||
scrollAnimator.setDuration(scroller.getDuration());
|
scrollAnimator.setDuration(scroller.getDuration());
|
||||||
scrollAnimator.start();
|
scrollAnimator.start();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private int getMaxX()
|
||||||
public void onLongPress(MotionEvent e)
|
|
||||||
{
|
{
|
||||||
|
return maxDataOffset * scrollerBucketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRestoreInstanceState(Parcelable state)
|
||||||
|
{
|
||||||
|
BundleSavedState bss = (BundleSavedState) state;
|
||||||
|
int x = bss.bundle.getInt("x");
|
||||||
|
int y = bss.bundle.getInt("y");
|
||||||
|
direction = bss.bundle.getInt("direction");
|
||||||
|
dataOffset = bss.bundle.getInt("dataOffset");
|
||||||
|
maxDataOffset = bss.bundle.getInt("maxDataOffset");
|
||||||
|
scroller.startScroll(0, 0, x, y, 0);
|
||||||
|
scroller.computeScrollOffset();
|
||||||
|
super.onRestoreInstanceState(bss.getSuperState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Parcelable onSaveInstanceState()
|
||||||
|
{
|
||||||
|
Parcelable superState = super.onSaveInstanceState();
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt("x", scroller.getCurrX());
|
||||||
|
bundle.putInt("y", scroller.getCurrY());
|
||||||
|
bundle.putInt("dataOffset", dataOffset);
|
||||||
|
bundle.putInt("direction", direction);
|
||||||
|
bundle.putInt("maxDataOffset", maxDataOffset);
|
||||||
|
return new BundleSavedState(superState, bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -112,12 +142,14 @@ public abstract class ScrollableChart extends View
|
|||||||
if (parent != null) parent.requestDisallowInterceptTouchEvent(true);
|
if (parent != null) parent.requestDisallowInterceptTouchEvent(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
scroller.startScroll(scroller.getCurrX(), scroller.getCurrY(),
|
|
||||||
(int) -dx, (int) dy, 0);
|
|
||||||
scroller.computeScrollOffset();
|
|
||||||
dataOffset = Math.max(0, scroller.getCurrX() / scrollerBucketSize);
|
|
||||||
postInvalidate();
|
|
||||||
|
|
||||||
|
dx = - direction * dx;
|
||||||
|
dx = Math.min(dx, getMaxX() - scroller.getCurrX());
|
||||||
|
scroller.startScroll(scroller.getCurrX(), scroller.getCurrY(), (int) dx,
|
||||||
|
(int) dy, 0);
|
||||||
|
|
||||||
|
scroller.computeScrollOffset();
|
||||||
|
updateDataOffset();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,39 +171,62 @@ public abstract class ScrollableChart extends View
|
|||||||
return detector.onTouchEvent(event);
|
return detector.onTouchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDirection(int direction)
|
||||||
|
{
|
||||||
|
if (direction != 1 && direction != -1)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
this.direction = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLongPress(MotionEvent e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxDataOffset(int maxDataOffset)
|
||||||
|
{
|
||||||
|
this.maxDataOffset = maxDataOffset;
|
||||||
|
this.dataOffset = Math.min(dataOffset, maxDataOffset);
|
||||||
|
scrollController.onDataOffsetChanged(this.dataOffset);
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScrollController(ScrollController scrollController)
|
||||||
|
{
|
||||||
|
this.scrollController = scrollController;
|
||||||
|
}
|
||||||
|
|
||||||
public void setScrollerBucketSize(int scrollerBucketSize)
|
public void setScrollerBucketSize(int scrollerBucketSize)
|
||||||
{
|
{
|
||||||
this.scrollerBucketSize = scrollerBucketSize;
|
this.scrollerBucketSize = scrollerBucketSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRestoreInstanceState(Parcelable state)
|
|
||||||
{
|
|
||||||
BundleSavedState bss = (BundleSavedState) state;
|
|
||||||
int x = bss.bundle.getInt("x");
|
|
||||||
int y = bss.bundle.getInt("y");
|
|
||||||
dataOffset = bss.bundle.getInt("dataOffset");
|
|
||||||
scroller.startScroll(0, 0, x, y, 0);
|
|
||||||
scroller.computeScrollOffset();
|
|
||||||
super.onRestoreInstanceState(bss.getSuperState());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Parcelable onSaveInstanceState()
|
|
||||||
{
|
|
||||||
Parcelable superState = super.onSaveInstanceState();
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putInt("x", scroller.getCurrX());
|
|
||||||
bundle.putInt("y", scroller.getCurrY());
|
|
||||||
bundle.putInt("dataOffset", dataOffset);
|
|
||||||
return new BundleSavedState(superState, bundle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init(Context context)
|
private void init(Context context)
|
||||||
{
|
{
|
||||||
detector = new GestureDetector(context, this);
|
detector = new GestureDetector(context, this);
|
||||||
scroller = new Scroller(context, null, true);
|
scroller = new Scroller(context, null, true);
|
||||||
scrollAnimator = ValueAnimator.ofFloat(0, 1);
|
scrollAnimator = ValueAnimator.ofFloat(0, 1);
|
||||||
scrollAnimator.addUpdateListener(this);
|
scrollAnimator.addUpdateListener(this);
|
||||||
|
scrollController = new ScrollController() {};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDataOffset()
|
||||||
|
{
|
||||||
|
int newDataOffset = scroller.getCurrX() / scrollerBucketSize;
|
||||||
|
newDataOffset = Math.max(0, newDataOffset);
|
||||||
|
newDataOffset = Math.min(maxDataOffset, newDataOffset);
|
||||||
|
|
||||||
|
if (newDataOffset != dataOffset)
|
||||||
|
{
|
||||||
|
dataOffset = newDataOffset;
|
||||||
|
scrollController.onDataOffsetChanged(dataOffset);
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ScrollController
|
||||||
|
{
|
||||||
|
default void onDataOffsetChanged(int newDataOffset) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.widget.*;
|
|||||||
|
|
||||||
import org.isoron.uhabits.R;
|
import org.isoron.uhabits.R;
|
||||||
import org.isoron.uhabits.activities.*;
|
import org.isoron.uhabits.activities.*;
|
||||||
|
import org.isoron.uhabits.activities.common.views.*;
|
||||||
import org.isoron.uhabits.activities.habits.list.controllers.*;
|
import org.isoron.uhabits.activities.habits.list.controllers.*;
|
||||||
import org.isoron.uhabits.activities.habits.list.model.*;
|
import org.isoron.uhabits.activities.habits.list.model.*;
|
||||||
import org.isoron.uhabits.activities.habits.list.views.*;
|
import org.isoron.uhabits.activities.habits.list.views.*;
|
||||||
@@ -43,7 +44,7 @@ import butterknife.*;
|
|||||||
public class ListHabitsRootView extends BaseRootView
|
public class ListHabitsRootView extends BaseRootView
|
||||||
implements ModelObservable.Listener, TaskRunner.Listener
|
implements ModelObservable.Listener, TaskRunner.Listener
|
||||||
{
|
{
|
||||||
public static final int MAX_CHECKMARK_COUNT = 21;
|
public static final int MAX_CHECKMARK_COUNT = 60;
|
||||||
|
|
||||||
@BindView(R.id.listView)
|
@BindView(R.id.listView)
|
||||||
HabitCardListView listView;
|
HabitCardListView listView;
|
||||||
@@ -132,6 +133,13 @@ public class ListHabitsRootView extends BaseRootView
|
|||||||
listController.setSelectionListener(menu);
|
listController.setSelectionListener(menu);
|
||||||
listView.setController(listController);
|
listView.setController(listController);
|
||||||
menu.setListController(listController);
|
menu.setListController(listController);
|
||||||
|
header.setScrollController(new ScrollableChart.ScrollController() {
|
||||||
|
@Override
|
||||||
|
public void onDataOffsetChanged(int newDataOffset)
|
||||||
|
{
|
||||||
|
listView.setDataOffset(newDataOffset);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -156,6 +164,7 @@ public class ListHabitsRootView extends BaseRootView
|
|||||||
{
|
{
|
||||||
int count = getCheckmarkCount();
|
int count = getCheckmarkCount();
|
||||||
header.setButtonCount(count);
|
header.setButtonCount(count);
|
||||||
|
header.setMaxDataOffset(Math.max(MAX_CHECKMARK_COUNT - count, 0));
|
||||||
listView.setCheckmarkCount(count);
|
listView.setCheckmarkCount(count);
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,6 +178,20 @@ public class HabitCardListAdapter
|
|||||||
listView.bindCardView(holder, habit, score, checkmarks, selected);
|
listView.bindCardView(holder, habit, score, checkmarks, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewAttachedToWindow(@Nullable HabitCardViewHolder holder)
|
||||||
|
{
|
||||||
|
if (listView == null) return;
|
||||||
|
listView.attachCardView(holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewDetachedFromWindow(@Nullable HabitCardViewHolder holder)
|
||||||
|
{
|
||||||
|
if (listView == null) return;
|
||||||
|
listView.detachCardView(holder);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HabitCardViewHolder onCreateViewHolder(ViewGroup parent,
|
public HabitCardViewHolder onCreateViewHolder(ViewGroup parent,
|
||||||
int viewType)
|
int viewType)
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ public class CheckmarkPanelView extends LinearLayout implements Preferences.List
|
|||||||
@NonNull
|
@NonNull
|
||||||
private Habit habit;
|
private Habit habit;
|
||||||
|
|
||||||
|
private int dataOffset;
|
||||||
|
|
||||||
public CheckmarkPanelView(Context context)
|
public CheckmarkPanelView(Context context)
|
||||||
{
|
{
|
||||||
super(context);
|
super(context);
|
||||||
@@ -75,19 +77,23 @@ public class CheckmarkPanelView extends LinearLayout implements Preferences.List
|
|||||||
return (CheckmarkButtonView) getChildAt(position);
|
return (CheckmarkButtonView) getChildAt(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCheckmarkValues(int[] checkmarkValues)
|
public void setButtonCount(int newButtonCount)
|
||||||
{
|
{
|
||||||
this.checkmarkValues = checkmarkValues;
|
if(nButtons != newButtonCount)
|
||||||
|
|
||||||
if (this.nButtons != checkmarkValues.length)
|
|
||||||
{
|
{
|
||||||
this.nButtons = checkmarkValues.length;
|
nButtons = newButtonCount;
|
||||||
addCheckmarkButtons();
|
addCheckmarkButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupCheckmarkButtons();
|
setupCheckmarkButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCheckmarkValues(int[] checkmarkValues)
|
||||||
|
{
|
||||||
|
this.checkmarkValues = checkmarkValues;
|
||||||
|
setupCheckmarkButtons();
|
||||||
|
}
|
||||||
|
|
||||||
public void setColor(int color)
|
public void setColor(int color)
|
||||||
{
|
{
|
||||||
this.color = color;
|
this.color = color;
|
||||||
@@ -100,6 +106,12 @@ public class CheckmarkPanelView extends LinearLayout implements Preferences.List
|
|||||||
setupCheckmarkButtons();
|
setupCheckmarkButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDataOffset(int dataOffset)
|
||||||
|
{
|
||||||
|
this.dataOffset = dataOffset;
|
||||||
|
setupCheckmarkButtons();
|
||||||
|
}
|
||||||
|
|
||||||
public void setHabit(@NonNull Habit habit)
|
public void setHabit(@NonNull Habit habit)
|
||||||
{
|
{
|
||||||
this.habit = habit;
|
this.habit = habit;
|
||||||
@@ -170,11 +182,13 @@ public class CheckmarkPanelView extends LinearLayout implements Preferences.List
|
|||||||
{
|
{
|
||||||
long timestamp = DateUtils.getStartOfToday();
|
long timestamp = DateUtils.getStartOfToday();
|
||||||
long day = DateUtils.millisecondsInOneDay;
|
long day = DateUtils.millisecondsInOneDay;
|
||||||
|
timestamp -= day * dataOffset;
|
||||||
|
|
||||||
for (int i = 0; i < nButtons; i++)
|
for (int i = 0; i < nButtons; i++)
|
||||||
{
|
{
|
||||||
CheckmarkButtonView buttonView = indexToButton(i);
|
CheckmarkButtonView buttonView = indexToButton(i);
|
||||||
buttonView.setValue(checkmarkValues[i]);
|
if(i + dataOffset >= checkmarkValues.length) break;
|
||||||
|
buttonView.setValue(checkmarkValues[i + dataOffset]);
|
||||||
buttonView.setColor(color);
|
buttonView.setColor(color);
|
||||||
setupButtonControllers(timestamp, buttonView);
|
setupButtonControllers(timestamp, buttonView);
|
||||||
timestamp -= day;
|
timestamp -= day;
|
||||||
|
|||||||
@@ -20,15 +20,17 @@
|
|||||||
package org.isoron.uhabits.activities.habits.list.views;
|
package org.isoron.uhabits.activities.habits.list.views;
|
||||||
|
|
||||||
import android.content.*;
|
import android.content.*;
|
||||||
|
import android.os.*;
|
||||||
import android.support.annotation.*;
|
import android.support.annotation.*;
|
||||||
import android.support.v7.widget.*;
|
import android.support.v7.widget.*;
|
||||||
import android.support.v7.widget.helper.*;
|
import android.support.v7.widget.helper.*;
|
||||||
import android.util.*;
|
import android.util.*;
|
||||||
import android.view.*;
|
import android.view.*;
|
||||||
|
|
||||||
import org.isoron.uhabits.models.*;
|
import org.isoron.uhabits.activities.common.views.*;
|
||||||
import org.isoron.uhabits.activities.habits.list.controllers.*;
|
import org.isoron.uhabits.activities.habits.list.controllers.*;
|
||||||
import org.isoron.uhabits.activities.habits.list.model.*;
|
import org.isoron.uhabits.activities.habits.list.model.*;
|
||||||
|
import org.isoron.uhabits.models.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -44,6 +46,10 @@ public class HabitCardListView extends RecyclerView
|
|||||||
|
|
||||||
private int checkmarkCount;
|
private int checkmarkCount;
|
||||||
|
|
||||||
|
private int dataOffset;
|
||||||
|
|
||||||
|
private LinkedList<HabitCardViewHolder> attachedHolders;
|
||||||
|
|
||||||
public HabitCardListView(Context context, AttributeSet attrs)
|
public HabitCardListView(Context context, AttributeSet attrs)
|
||||||
{
|
{
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
@@ -54,6 +60,13 @@ public class HabitCardListView extends RecyclerView
|
|||||||
TouchHelperCallback callback = new TouchHelperCallback();
|
TouchHelperCallback callback = new TouchHelperCallback();
|
||||||
touchHelper = new ItemTouchHelper(callback);
|
touchHelper = new ItemTouchHelper(callback);
|
||||||
touchHelper.attachToRecyclerView(this);
|
touchHelper.attachToRecyclerView(this);
|
||||||
|
|
||||||
|
attachedHolders = new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attachCardView(HabitCardViewHolder holder)
|
||||||
|
{
|
||||||
|
attachedHolders.add(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,13 +88,12 @@ public class HabitCardListView extends RecyclerView
|
|||||||
int[] checkmarks,
|
int[] checkmarks,
|
||||||
boolean selected)
|
boolean selected)
|
||||||
{
|
{
|
||||||
int visibleCheckmarks[] =
|
|
||||||
Arrays.copyOfRange(checkmarks, 0, checkmarkCount);
|
|
||||||
|
|
||||||
HabitCardView cardView = (HabitCardView) holder.itemView;
|
HabitCardView cardView = (HabitCardView) holder.itemView;
|
||||||
cardView.setHabit(habit);
|
cardView.setHabit(habit);
|
||||||
cardView.setSelected(selected);
|
cardView.setSelected(selected);
|
||||||
cardView.setCheckmarkValues(visibleCheckmarks);
|
cardView.setCheckmarkValues(checkmarks);
|
||||||
|
cardView.setCheckmarkCount(checkmarkCount);
|
||||||
|
cardView.setDataOffset(dataOffset);
|
||||||
cardView.setScore(score);
|
cardView.setScore(score);
|
||||||
if (controller != null) setupCardViewController(holder);
|
if (controller != null) setupCardViewController(holder);
|
||||||
return cardView;
|
return cardView;
|
||||||
@@ -92,6 +104,11 @@ public class HabitCardListView extends RecyclerView
|
|||||||
return new HabitCardView(getContext());
|
return new HabitCardView(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void detachCardView(HabitCardViewHolder holder)
|
||||||
|
{
|
||||||
|
attachedHolders.remove(holder);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAdapter(RecyclerView.Adapter adapter)
|
public void setAdapter(RecyclerView.Adapter adapter)
|
||||||
{
|
{
|
||||||
@@ -109,6 +126,16 @@ public class HabitCardListView extends RecyclerView
|
|||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDataOffset(int dataOffset)
|
||||||
|
{
|
||||||
|
this.dataOffset = dataOffset;
|
||||||
|
for (HabitCardViewHolder holder : attachedHolders)
|
||||||
|
{
|
||||||
|
HabitCardView cardView = (HabitCardView) holder.itemView;
|
||||||
|
cardView.setDataOffset(dataOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAttachedToWindow()
|
protected void onAttachedToWindow()
|
||||||
{
|
{
|
||||||
@@ -123,6 +150,23 @@ public class HabitCardListView extends RecyclerView
|
|||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestoreInstanceState(Parcelable state)
|
||||||
|
{
|
||||||
|
BundleSavedState bss = (BundleSavedState) state;
|
||||||
|
dataOffset = bss.bundle.getInt("dataOffset");
|
||||||
|
super.onRestoreInstanceState(bss.getSuperState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Parcelable onSaveInstanceState()
|
||||||
|
{
|
||||||
|
Parcelable superState = super.onSaveInstanceState();
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt("dataOffset", dataOffset);
|
||||||
|
return new BundleSavedState(superState, bundle);
|
||||||
|
}
|
||||||
|
|
||||||
protected void setupCardViewController(@NonNull HabitCardViewHolder holder)
|
protected void setupCardViewController(@NonNull HabitCardViewHolder holder)
|
||||||
{
|
{
|
||||||
HabitCardView cardView = (HabitCardView) holder.itemView;
|
HabitCardView cardView = (HabitCardView) holder.itemView;
|
||||||
@@ -168,7 +212,7 @@ public class HabitCardListView extends RecyclerView
|
|||||||
{
|
{
|
||||||
int position = holder.getAdapterPosition();
|
int position = holder.getAdapterPosition();
|
||||||
if (controller != null) controller.onItemLongClick(position);
|
if (controller != null) controller.onItemLongClick(position);
|
||||||
if(adapter.isSortable()) touchHelper.startDrag(holder);
|
if (adapter.isSortable()) touchHelper.startDrag(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ public class HabitCardView extends FrameLayout
|
|||||||
@Nullable
|
@Nullable
|
||||||
private Habit habit;
|
private Habit habit;
|
||||||
|
|
||||||
|
private int dataOffset;
|
||||||
|
|
||||||
public HabitCardView(Context context)
|
public HabitCardView(Context context)
|
||||||
{
|
{
|
||||||
super(context);
|
super(context);
|
||||||
@@ -90,6 +92,11 @@ public class HabitCardView extends FrameLayout
|
|||||||
new Handler(Looper.getMainLooper()).post(() -> refresh());
|
new Handler(Looper.getMainLooper()).post(() -> refresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCheckmarkCount(int checkmarkCount)
|
||||||
|
{
|
||||||
|
checkmarkPanel.setButtonCount(checkmarkCount);
|
||||||
|
}
|
||||||
|
|
||||||
public void setCheckmarkValues(int checkmarks[])
|
public void setCheckmarkValues(int checkmarks[])
|
||||||
{
|
{
|
||||||
checkmarkPanel.setCheckmarkValues(checkmarks);
|
checkmarkPanel.setCheckmarkValues(checkmarks);
|
||||||
@@ -103,6 +110,12 @@ public class HabitCardView extends FrameLayout
|
|||||||
checkmarkPanel.setController(controller);
|
checkmarkPanel.setController(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDataOffset(int dataOffset)
|
||||||
|
{
|
||||||
|
this.dataOffset = dataOffset;
|
||||||
|
checkmarkPanel.setDataOffset(dataOffset);
|
||||||
|
}
|
||||||
|
|
||||||
public void setHabit(@NonNull Habit habit)
|
public void setHabit(@NonNull Habit habit)
|
||||||
{
|
{
|
||||||
if (this.habit != null) detachFromHabit();
|
if (this.habit != null) detachFromHabit();
|
||||||
@@ -134,7 +147,7 @@ public class HabitCardView extends FrameLayout
|
|||||||
{
|
{
|
||||||
long today = DateUtils.getStartOfToday();
|
long today = DateUtils.getStartOfToday();
|
||||||
long day = DateUtils.millisecondsInOneDay;
|
long day = DateUtils.millisecondsInOneDay;
|
||||||
int offset = (int) ((today - timestamp) / day);
|
int offset = (int) ((today - timestamp) / day) - dataOffset;
|
||||||
CheckmarkButtonView button = checkmarkPanel.indexToButton(offset);
|
CheckmarkButtonView button = checkmarkPanel.indexToButton(offset);
|
||||||
|
|
||||||
float y = button.getHeight() / 2.0f;
|
float y = button.getHeight() / 2.0f;
|
||||||
|
|||||||
@@ -20,22 +20,23 @@
|
|||||||
package org.isoron.uhabits.activities.habits.list.views;
|
package org.isoron.uhabits.activities.habits.list.views;
|
||||||
|
|
||||||
import android.content.*;
|
import android.content.*;
|
||||||
|
import android.content.res.*;
|
||||||
|
import android.graphics.*;
|
||||||
import android.support.annotation.*;
|
import android.support.annotation.*;
|
||||||
|
import android.text.*;
|
||||||
import android.util.*;
|
import android.util.*;
|
||||||
import android.view.*;
|
|
||||||
import android.widget.*;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.*;
|
import org.isoron.uhabits.*;
|
||||||
|
import org.isoron.uhabits.activities.common.views.*;
|
||||||
import org.isoron.uhabits.activities.habits.list.*;
|
import org.isoron.uhabits.activities.habits.list.*;
|
||||||
import org.isoron.uhabits.preferences.*;
|
import org.isoron.uhabits.preferences.*;
|
||||||
import org.isoron.uhabits.utils.*;
|
import org.isoron.uhabits.utils.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class HeaderView extends LinearLayout
|
public class HeaderView extends ScrollableChart
|
||||||
implements Preferences.Listener, MidnightTimer.MidnightListener
|
implements Preferences.Listener, MidnightTimer.MidnightListener
|
||||||
{
|
{
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
private int buttonCount;
|
private int buttonCount;
|
||||||
|
|
||||||
@@ -45,10 +46,15 @@ public class HeaderView extends LinearLayout
|
|||||||
@Nullable
|
@Nullable
|
||||||
private MidnightTimer midnightTimer;
|
private MidnightTimer midnightTimer;
|
||||||
|
|
||||||
|
private final TextPaint paint;
|
||||||
|
|
||||||
|
private RectF rect;
|
||||||
|
|
||||||
|
private int maxDataOffset;
|
||||||
|
|
||||||
public HeaderView(Context context, AttributeSet attrs)
|
public HeaderView(Context context, AttributeSet attrs)
|
||||||
{
|
{
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
this.context = context;
|
|
||||||
|
|
||||||
if (isInEditMode())
|
if (isInEditMode())
|
||||||
{
|
{
|
||||||
@@ -67,24 +73,40 @@ public class HeaderView extends LinearLayout
|
|||||||
ListHabitsActivity activity = (ListHabitsActivity) context;
|
ListHabitsActivity activity = (ListHabitsActivity) context;
|
||||||
midnightTimer = activity.getListHabitsComponent().getMidnightTimer();
|
midnightTimer = activity.getListHabitsComponent().getMidnightTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Resources res = context.getResources();
|
||||||
|
setScrollerBucketSize((int) res.getDimension(R.dimen.checkmarkWidth));
|
||||||
|
setDirection(shouldReverseCheckmarks() ? 1 : -1);
|
||||||
|
|
||||||
|
StyledResources sr = new StyledResources(context);
|
||||||
|
paint = new TextPaint();
|
||||||
|
paint.setColor(Color.BLACK);
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
paint.setTextSize(getResources().getDimension(R.dimen.tinyTextSize));
|
||||||
|
paint.setTextAlign(Paint.Align.CENTER);
|
||||||
|
paint.setTypeface(Typeface.DEFAULT_BOLD);
|
||||||
|
paint.setColor(sr.getColor(R.attr.mediumContrastTextColor));
|
||||||
|
|
||||||
|
rect = new RectF();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void atMidnight()
|
public void atMidnight()
|
||||||
{
|
{
|
||||||
post(() -> createButtons());
|
post(() -> invalidate());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCheckmarkOrderChanged()
|
public void onCheckmarkOrderChanged()
|
||||||
{
|
{
|
||||||
createButtons();
|
setDirection(shouldReverseCheckmarks() ? 1 : -1);
|
||||||
|
postInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setButtonCount(int buttonCount)
|
public void setButtonCount(int buttonCount)
|
||||||
{
|
{
|
||||||
this.buttonCount = buttonCount;
|
this.buttonCount = buttonCount;
|
||||||
createButtons();
|
postInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -103,23 +125,45 @@ public class HeaderView extends LinearLayout
|
|||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createButtons()
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||||
{
|
{
|
||||||
removeAllViews();
|
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
int height = (int) getContext()
|
||||||
|
.getResources()
|
||||||
|
.getDimension(R.dimen.checkmarkHeight);
|
||||||
|
setMeasuredDimension(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas)
|
||||||
|
{
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
GregorianCalendar day = DateUtils.getStartOfTodayCalendar();
|
GregorianCalendar day = DateUtils.getStartOfTodayCalendar();
|
||||||
|
Resources res = getContext().getResources();
|
||||||
|
float width = res.getDimension(R.dimen.checkmarkWidth);
|
||||||
|
float height = res.getDimension(R.dimen.checkmarkHeight);
|
||||||
|
boolean reverse = shouldReverseCheckmarks();
|
||||||
|
|
||||||
|
day.add(GregorianCalendar.DAY_OF_MONTH, -getDataOffset());
|
||||||
|
float em = paint.measureText("m");
|
||||||
|
|
||||||
for (int i = 0; i < buttonCount; i++)
|
for (int i = 0; i < buttonCount; i++)
|
||||||
addView(
|
|
||||||
inflate(context, R.layout.list_habits_header_checkmark, null));
|
|
||||||
|
|
||||||
for (int i = 0; i < getChildCount(); i++)
|
|
||||||
{
|
{
|
||||||
int position = i;
|
rect.set(0, 0, width, height);
|
||||||
if (shouldReverseCheckmarks()) position = getChildCount() - i - 1;
|
rect.offset(canvas.getWidth(), 0);
|
||||||
|
if(reverse) rect.offset(- (i + 1) * width, 0);
|
||||||
|
else rect.offset((i - buttonCount) * width, 0);
|
||||||
|
|
||||||
View button = getChildAt(position);
|
String text = DateUtils.formatHeaderDate(day).toUpperCase();
|
||||||
TextView label = (TextView) button.findViewById(R.id.tvCheck);
|
String[] lines = text.split("\n");
|
||||||
label.setText(DateUtils.formatHeaderDate(day));
|
|
||||||
|
int y1 = (int)(rect.centerY() - 0.25 * em);
|
||||||
|
int y2 = (int)(rect.centerY() + 1.25 * em);
|
||||||
|
|
||||||
|
canvas.drawText(lines[0], rect.centerX(), y1, paint);
|
||||||
|
canvas.drawText(lines[1], rect.centerX(), y2, paint);
|
||||||
day.add(GregorianCalendar.DAY_OF_MONTH, -1);
|
day.add(GregorianCalendar.DAY_OF_MONTH, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user