/*
* 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.activities.habits.list.views;
import android.annotation.*;
import android.content.*;
import android.graphics.drawable.*;
import android.os.*;
import android.support.annotation.*;
import android.util.*;
import android.widget.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.utils.*;
import java.util.*;
import butterknife.*;
import static android.os.Build.VERSION.*;
import static android.os.Build.VERSION_CODES.*;
public class HabitCardView extends FrameLayout
implements ModelObservable.Listener
{
private static final String EDIT_MODE_HABITS[] = {
"Wake up early",
"Wash dishes",
"Exercise",
"Meditate",
"Play guitar",
"Wash clothes",
"Get a haircut"
};
@BindView(R.id.checkmarkPanel)
CheckmarkPanelView checkmarkPanel;
@BindView(R.id.innerFrame)
LinearLayout innerFrame;
@BindView(R.id.label)
TextView label;
@BindView(R.id.scoreRing)
RingView scoreRing;
private final Context context = getContext();
private StyledResources res;
@Nullable
private Habit habit;
private int dataOffset;
public HabitCardView(Context context)
{
super(context);
init();
}
public HabitCardView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
@Override
public void onModelChange()
{
new Handler(Looper.getMainLooper()).post(() -> refresh());
}
public void setCheckmarkCount(int checkmarkCount)
{
checkmarkPanel.setButtonCount(checkmarkCount);
}
public void setCheckmarkValues(int checkmarks[])
{
checkmarkPanel.setCheckmarkValues(checkmarks);
postInvalidate();
}
public void setController(Controller controller)
{
checkmarkPanel.setController(null);
if (controller == null) return;
checkmarkPanel.setController(controller);
}
public void setDataOffset(int dataOffset)
{
this.dataOffset = dataOffset;
checkmarkPanel.setDataOffset(dataOffset);
}
public void setHabit(@NonNull Habit habit)
{
if (this.habit != null) detachFromHabit();
this.habit = habit;
checkmarkPanel.setHabit(habit);
refresh();
attachToHabit();
postInvalidate();
}
public void setScore(int score)
{
float percentage = (float) score / Score.MAX_VALUE;
scoreRing.setPercentage(percentage);
scoreRing.setPrecision(1.0f / 16);
postInvalidate();
}
@Override
public void setSelected(boolean isSelected)
{
super.setSelected(isSelected);
updateBackground(isSelected);
}
public void triggerRipple(long timestamp)
{
long today = DateUtils.getStartOfToday();
long day = DateUtils.millisecondsInOneDay;
int offset = (int) ((today - timestamp) / day) - dataOffset;
CheckmarkButtonView button = checkmarkPanel.indexToButton(offset);
float y = button.getHeight() / 2.0f;
float x = checkmarkPanel.getX() + button.getX() + button.getWidth() / 2;
triggerRipple(x, y);
}
@Override
protected void onDetachedFromWindow()
{
if (habit != null) detachFromHabit();
super.onDetachedFromWindow();
}
private void attachToHabit()
{
if (habit != null) habit.getObservable().addListener(this);
}
private void detachFromHabit()
{
if (habit != null) habit.getObservable().removeListener(this);
}
private int getActiveColor(Habit habit)
{
int mediumContrastColor = res.getColor(R.attr.mediumContrastTextColor);
int activeColor = ColorUtils.getColor(context, habit.getColor());
if (habit.isArchived()) activeColor = mediumContrastColor;
return activeColor;
}
private void init()
{
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
res = new StyledResources(getContext());
inflate(context, R.layout.list_habits_card, this);
ButterKnife.bind(this);
innerFrame.setOnTouchListener((v, event) -> {
if (SDK_INT >= LOLLIPOP)
v.getBackground().setHotspot(event.getX(), event.getY());
return false;
});
if (isInEditMode()) initEditMode();
}
@SuppressLint("SetTextI18n")
private void initEditMode()
{
Random rand = new Random();
int color = ColorUtils.getAndroidTestColor(rand.nextInt(10));
int[] values = new int[5];
for (int i = 0; i < 5; i++) values[i] = rand.nextInt(3);
label.setText(EDIT_MODE_HABITS[rand.nextInt(EDIT_MODE_HABITS.length)]);
label.setTextColor(color);
scoreRing.setColor(color);
scoreRing.setPercentage(rand.nextFloat());
checkmarkPanel.setColor(color);
checkmarkPanel.setCheckmarkValues(values);
}
private void refresh()
{
int color = getActiveColor(habit);
label.setText(habit.getName());
label.setTextColor(color);
scoreRing.setColor(color);
checkmarkPanel.setColor(color);
postInvalidate();
}
private void triggerRipple(final float x, final float y)
{
final Drawable background = innerFrame.getBackground();
if (SDK_INT >= LOLLIPOP) background.setHotspot(x, y);
background.setState(new int[]{
android.R.attr.state_pressed, android.R.attr.state_enabled
});
new Handler().postDelayed(() -> background.setState(new int[]{}), 25);
}
private void updateBackground(boolean isSelected)
{
if (SDK_INT >= LOLLIPOP)
{
if (isSelected)
innerFrame.setBackgroundResource(R.drawable.selected_box);
else innerFrame.setBackgroundResource(R.drawable.ripple);
}
else
{
Drawable background;
if (isSelected)
background = res.getDrawable(R.attr.selectedBackground);
else background = res.getDrawable(R.attr.cardBackground);
innerFrame.setBackgroundDrawable(background);
}
}
public interface Controller extends CheckmarkPanelView.Controller {}
}