package fr.paug.androidmakers.ui.view;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.support.annotation.NonNull;
import android.text.TextPaint;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import fr.paug.androidmakers.R;
import fr.paug.androidmakers.model.ScheduleSlot;
/**
* Created by stan on 18/03/2017.
*/
public class AgendaView extends ScrollView {
private static final long OFFSET_MS = DateUtils.HOUR_IN_MILLIS / 2;
private static int[] sBackgrounds = {
R.drawable.bg_box_blue_selector,
R.drawable.bg_box_red_selector,
R.drawable.bg_box_green_selector
};
private Calendar mCalendar = Calendar.getInstance();
private SparseArray<String> mTimeLabel = new SparseArray<>();
private int mTimeWidth;
private long mInitialTime;
private Paint mLinePaint;
private Paint mLabelBackgroundPaint;
private TextPaint mTextPaint;
private int mPadding;
public AgendaView(Context context) {
super(context);
init();
}
public AgendaView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AgendaView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public AgendaView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public void setAgenda(DaySchedule daySchedule, AgendaClickListener listener) {
long start = Long.MAX_VALUE;
long end = Long.MIN_VALUE;
List<RoomSchedule> agenda = daySchedule.getRoomSchedules();
for (int i = 0; i < agenda.size(); i++) {
List<Item> agendaPerTrack = agenda.get(i).getItems();
for (Item agendaItem : agendaPerTrack) {
start = Math.min(start, agendaItem.getStartTimestamp());
end = Math.max(end, agendaItem.getEndTimestamp());
}
}
removeAllViews();
if (end - start > DateUtils.DAY_IN_MILLIS) {
mInitialTime = 0;
return; // more than a day? It's a bug
}
Context context = getContext();
LinearLayout rootView = new LinearLayout(context);
rootView.setOrientation(LinearLayout.HORIZONTAL);
mInitialTime = start - OFFSET_MS;
// add all agenda items
for (int i = 0; i < agenda.size(); i++) {
RoomSchedule roomSchedule = agenda.get(i);
List<Item> agendaPerTrack = roomSchedule.getItems();
// for track 1
FrameLayout frameLayout = new FrameLayout(context);
for (Item agendaItem : agendaPerTrack) {
long startDiffWithBegin = agendaItem.getStartTimestamp() - mInitialTime;
long duration = agendaItem.getEndTimestamp() - agendaItem.getStartTimestamp();
TextView textView = new TextView(context);
textView.setText(agendaItem.getTitle());
textView.setTag(agendaItem.getSessionId());
textView.setTextColor(Color.WHITE);
textView.getPaint().setFakeBoldText(true);
textView.setBackgroundResource(
sBackgrounds[Math.abs(agendaItem.getRoomId()) % sBackgrounds.length]
);
textView.setOnClickListener(new ViewClickListener(listener, agendaItem));
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
getPxFromDurationMs(duration));
lp.topMargin = getPxFromDurationMs(startDiffWithBegin);
frameLayout.addView(textView, lp);
}
frameLayout.setLayoutParams(new LinearLayout.LayoutParams(0,
LinearLayout.LayoutParams.MATCH_PARENT, 1
));
frameLayout.setTag(roomSchedule.mTitle);
rootView.addView(frameLayout);
}
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT
);
if (getChildCount() == 0) {
lp.leftMargin = mTimeWidth;
}
addView(rootView, lp);
long now = System.currentTimeMillis();
if (start < now && now < end) {
scrollToSee(now - DateUtils.HOUR_IN_MILLIS);
}
}
public void refreshSessionsSelected(@NonNull AgendaSelector agendaSelector) {
if (getChildCount() != 1) {
return;
}
boolean hasSelected = agendaSelector.hasSelected();
ViewGroup rootView = (ViewGroup) getChildAt(0);
for (int i = 0; i < rootView.getChildCount(); i++) {
ViewGroup roomLayout = (ViewGroup) rootView.getChildAt(i);
for (int j = 0; j < roomLayout.getChildCount(); j++) {
TextView textView = (TextView) roomLayout.getChildAt(j);
Object tag = textView.getTag();
if (tag instanceof Integer) {
boolean isSelected = !hasSelected || agendaSelector.isSelected((Integer) tag);
textView.setAlpha(isSelected ? 1 : 0.6f);
}
}
}
}
@Override
public void draw(Canvas canvas) {
if (mInitialTime > 0) {
int y = 0;
long timestampFirstHour = getHourBeforeTimestamp(mInitialTime);
for (long timestamp = timestampFirstHour;
y < getScrollY() + getHeight(); timestamp += DateUtils.HOUR_IN_MILLIS) {
y = getPxFromDurationMs(timestamp - mInitialTime) + getPaddingTop();
String label = getTimeLabel(timestamp);
drawLineHour(canvas, y, label);
}
}
super.draw(canvas);
drawRoomName(canvas);
}
private void drawRoomName(Canvas canvas) {
if (getChildCount() != 1) {
return;
}
ViewGroup rootView = (ViewGroup) getChildAt(0);
float offsetY = getScrollY();
if(offsetY > 5) {
canvas.drawRect(mTimeWidth, offsetY,
getWidth(), offsetY + mTextPaint.getTextSize() + mPadding * 2,
mLabelBackgroundPaint);
}
int x = mTimeWidth;
int childCount = rootView.getChildCount();
int widthPerItem = (getWidth() - mTimeWidth) / childCount;
for (int i = 0; i < childCount; i++) {
View view = rootView.getChildAt(i);
Object tag = view.getTag();
if (tag instanceof String) {
String roomName = (String) tag;
float measureText = mTextPaint.measureText(roomName);
float xText = x + widthPerItem / 2 - measureText / 2f;
float yText = offsetY + mTextPaint.getTextSize() + mPadding;
canvas.drawText(roomName, xText, yText, mTextPaint);
}
x += widthPerItem;
}
}
private String getTimeLabel(long timestamp) {
int hash = Long.valueOf(timestamp).hashCode();
String label = mTimeLabel.get(hash);
if (label == null) {
mCalendar.setTimeInMillis(timestamp);
label = String.format(Locale.getDefault(), "%02d:00",
mCalendar.get(Calendar.HOUR_OF_DAY));
}
return label;
}
private void drawLineHour(Canvas canvas, int y, String label) {
canvas.drawLine(mTimeWidth, y, getWidth(), y, mLinePaint);
float measureText = mTextPaint.measureText(label);
canvas.drawText(label,
0, label.length(),
mTimeWidth / 2 - measureText / 2f,
y + (mTextPaint.getTextSize() - mTextPaint.descent()) / 2,
mTextPaint);
}
private long getHourBeforeTimestamp(long timestamp) {
Calendar instance = Calendar.getInstance();
instance.setTimeInMillis(timestamp);
instance.set(Calendar.MINUTE, 0);
instance.set(Calendar.SECOND, 0);
return instance.getTimeInMillis();
}
private int getPxFromDurationMs(long ms) {
float sp = 150.0f * ms / DateUtils.HOUR_IN_MILLIS;
return getPixelFromSp(sp);
}
private int getPixelFromSp(float sp) {
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
getResources().getDisplayMetrics()));
}
private void scrollToSee(long timestamp) {
final int pxFromDurationMs = getPxFromDurationMs(timestamp - mInitialTime);
post(new Runnable() {
@Override
public void run() {
setScrollY(pxFromDurationMs);
}
});
}
private void init() {
setWillNotDraw(false);
setFillViewport(true);
setClipChildren(false);
setClipToPadding(false);
mLinePaint = new Paint();
mLinePaint.setColor(Color.GRAY);
mLinePaint.setStrokeWidth(1f);
TypedValue a = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.windowBackground, a, true);
int labelBackgroundColor;
if (a.type >= TypedValue.TYPE_FIRST_COLOR_INT && a.type <= TypedValue.TYPE_LAST_COLOR_INT) {
// windowBackground is a color
labelBackgroundColor = Color.argb(240,
Color.red(a.data), Color.green(a.data), Color.blue(a.data));
} else {
labelBackgroundColor = Color.argb(240, 250, 250, 250);
}
mLabelBackgroundPaint = new Paint();
mLabelBackgroundPaint.setColor(labelBackgroundColor);
mLabelBackgroundPaint.setAntiAlias(true);
mTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(Color.DKGRAY);
mTextPaint.setTextSize(getPixelFromSp(14));
mTimeWidth = getPixelFromSp(50);
mPadding = getResources().getDimensionPixelSize(R.dimen.padding);
setPadding(0, mPadding, 0, mPadding);
}
public interface AgendaClickListener {
void onClick(Item agendaItem);
}
public interface AgendaSelector {
boolean isSelected(int sessionId);
boolean hasSelected();
}
public static class DaySchedule {
private final String mTitle;
@NonNull
private final List<RoomSchedule> mRoomSchedules;
public DaySchedule(String title, @NonNull List<RoomSchedule> roomSchedules) {
mTitle = title;
mRoomSchedules = roomSchedules;
}
public String getTitle() {
return mTitle;
}
@NonNull
public List<RoomSchedule> getRoomSchedules() {
return mRoomSchedules;
}
}
public static class RoomSchedule implements Comparable<RoomSchedule> {
private final int mRoomId;
private final String mTitle;
@NonNull
private final List<AgendaView.Item> mItems;
public RoomSchedule(int roomId, String title, @NonNull List<Item> items) {
mRoomId = roomId;
mTitle = title;
mItems = items;
}
public int getRoomId() {
return mRoomId;
}
public String getTitle() {
return mTitle;
}
@NonNull
public List<Item> getItems() {
return mItems;
}
@Override
public int compareTo(@NonNull RoomSchedule o) {
return mRoomId - o.mRoomId;
}
}
public static class Item {
private ScheduleSlot mScheduleSlot;
private String mTitle;
public Item(ScheduleSlot scheduleSlot, String title) {
mScheduleSlot = scheduleSlot;
mTitle = title;
}
public long getStartTimestamp() {
return mScheduleSlot.startDate;
}
public long getEndTimestamp() {
return mScheduleSlot.endDate;
}
public String getTitle() {
return mTitle;
}
public int getRoomId() {
return mScheduleSlot.room;
}
public int getSessionId() {
return mScheduleSlot.sessionId;
}
}
private static class ViewClickListener implements OnClickListener {
private AgendaClickListener mAgendaClickListener;
private Item mAgendaItem;
public ViewClickListener(AgendaClickListener agendaClickListener, Item agendaItem) {
mAgendaClickListener = agendaClickListener;
mAgendaItem = agendaItem;
}
@Override
public void onClick(View v) {
mAgendaClickListener.onClick(mAgendaItem);
}
}
}