/*
* Copyright 2015. Appsi Mobile
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.appsimobile.appsii.module.appsiagenda;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.appsimobile.appsii.AnalyticsManager;
import com.appsimobile.appsii.ExpandCollapseDrawable;
import com.appsimobile.appsii.R;
import com.appsimobile.appsii.SidebarContext;
import com.appsimobile.util.TimeUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Created by nick on 03/11/14.
*/
class ExpandableAgendaAdapter extends AgendaAdapter<AgendaViewHolder>
implements HeaderViewHolder.ExpandListener {
static final int VIEW_TYPE_PX_HEADER = 0;
static final int VIEW_TYPE_HEADER = 1;
static final int VIEW_TYPE_AGENDA_ITEM = 2;
private final Context mContext;
private final Time mTime = new Time(Time.TIMEZONE_UTC);
final ArrayList<Object> mVisibleItems = new ArrayList<>();
private final ParallaxHeaderItem mHeaderView;
private ItemAgendaViewHolder.OnItemClickListener mOnAgendaItemClickListener;
private final Handler mHandler;
private View mParallaxView;
ExpandableAgendaAdapter(Context context) {
mContext = context;
mHeaderView = new ParallaxHeaderItem();
mVisibleItems.add(mHeaderView);
mHandler = new Handler();
setHasStableIds(true);
}
@Override
public AgendaViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
switch (viewType) {
case VIEW_TYPE_PX_HEADER:
return onCreateParallaxViewHolder(viewGroup);
case VIEW_TYPE_HEADER:
return newGroupViewHolder(viewGroup);
case VIEW_TYPE_AGENDA_ITEM:
return newChildViewHolder(viewGroup);
}
throw new IllegalArgumentException("Unknown viewType: " + viewType);
}
protected AgendaViewHolder onCreateParallaxViewHolder(ViewGroup parent) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View result = layoutInflater.inflate(R.layout.page_agenda_px_header, parent, false);
mParallaxView = result;
return new ParallaxHeaderViewHolder(result);
}
protected HeaderViewHolder newGroupViewHolder(ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View result =
inflater.inflate(R.layout.list_item_header_collapsible, parent, false);
Resources res = mContext.getResources();
int dp48 = (int) (res.getDisplayMetrics().density * 24);
Drawable drawable = new ExpandCollapseDrawable(res);
drawable.setBounds(0, 0, dp48, dp48);
((TextView) result).setCompoundDrawables(null, null, drawable, null);
return new HeaderViewHolder(result, this);
}
protected AgendaViewHolder newChildViewHolder(ViewGroup parent) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View result = layoutInflater.inflate(R.layout.list_item_agenda, parent, false);
return new ItemAgendaViewHolder(result, mOnAgendaItemClickListener);
}
@Override
public void onBindViewHolder(AgendaViewHolder agendaViewHolder, int position) {
Object item = mVisibleItems.get(position);
if (!agendaViewHolder.bind(item)) {
throw new IllegalStateException(
"Invalid holder for viewtype. position: " + position + " viewtype: " +
getItemViewType(position));
}
}
@Override
public int getItemViewType(int position) {
Object item = mVisibleItems.get(position);
if (item instanceof ParallaxHeaderItem) {
return VIEW_TYPE_PX_HEADER;
}
if (item instanceof HeaderItem) {
return VIEW_TYPE_HEADER;
}
if (item instanceof AgendaEvent) {
return VIEW_TYPE_AGENDA_ITEM;
}
throw new IllegalArgumentException("unknown item: " + item.getClass());
}
@Override
public long getItemId(int position) {
if (position == 0) return Long.MIN_VALUE;
Object item = mVisibleItems.get(position);
if (item instanceof HeaderItem) {
HeaderItem headerItem = (HeaderItem) item;
return -headerItem.mJulianDay;
}
AgendaEvent event = (AgendaEvent) item;
return event.id;
}
@Override
public int getItemCount() {
return mVisibleItems.size();
}
@Override
public void onCollapse(int position) {
HeaderItem item = (HeaderItem) mVisibleItems.get(position);
// track how many days ahead items are frequently collapsed
int today = TimeUtils.getJulianDay();
int daysAhead = item.mJulianDay - today;
SidebarContext.track(mContext, AnalyticsManager.ACTION_COLLAPSE_ITEM,
AnalyticsManager.CATEGORY_AGENDA, "day: " + daysAhead);
removeItemRange(position + 1, item.mEvents.size());
}
@Override
public void onExpand(int position) {
HeaderItem item = (HeaderItem) mVisibleItems.get(position);
// track how many days ahead items are frequently expanded
int today = TimeUtils.getJulianDay();
int daysAhead = item.mJulianDay - today;
SidebarContext.track(mContext, AnalyticsManager.ACTION_EXPAND_ITEM,
AnalyticsManager.CATEGORY_AGENDA, "day: " + daysAhead);
List<AgendaEvent> events = item.mEvents;
mVisibleItems.addAll(position + 1, events);
notifyItemRangeInserted(position + 1, events.size());
notifyDataSetChanged();
}
private void removeItemRange(int start, int count) {
for (int i = start + count - 1; i >= start; i--) {
mVisibleItems.remove(i);
}
notifyDataSetChanged();
notifyItemRangeRemoved(start, count);
}
@Override
public void setOnAgendaItemClickListener(
ItemAgendaViewHolder.OnItemClickListener onItemClickListener) {
mOnAgendaItemClickListener = onItemClickListener;
}
@Override
public float getHeaderScrollPercentage() {
if (mParallaxView == null) return 1f;
if (!mParallaxView.isShown()) return 1f;
float top = mParallaxView.getTop();
if (top > 0) top = 0;
return top / mParallaxView.getHeight();
}
@Override
public boolean getTimeAtPosition(Time time, int position) {
if (position >= mVisibleItems.size()) return false;
Object item = mVisibleItems.get(position);
if (item instanceof ParallaxHeaderItem) {
return getTimeAtPosition(time, position + 1);
} else if (item instanceof HeaderItem) {
HeaderItem headerItem = (HeaderItem) item;
time.setJulianDay(headerItem.mJulianDay);
return true;
} else {
return getTimeAtPosition(time, position - 1);
}
}
@Override
public int positionOfDate(int year, int month, int day) {
mTime.set(day, month, year);
long millis = mTime.normalize(true);
// time is in utc, so no offset needed.
int requestedJulianDay = Time.getJulianDay(millis, 0);
return positionOfJulianDay(requestedJulianDay);
}
@Override
public int positionOfJulianDay(int julianDay) {
int N = mVisibleItems.size();
for (int i = 0; i < N; i++) {
Object o = mVisibleItems.get(i);
if (o instanceof HeaderItem) {
HeaderItem item = (HeaderItem) o;
if (item.mJulianDay >= julianDay) {
return i;
}
}
}
return -1;
}
@Override
public int setAgendaEvents(List<AgendaEvent> data) {
int lastGroupDay = 0;
int today = TimeUtils.getJulianDay();
HeaderItem item = null;
List<HeaderItem> headers = new ArrayList<>();
int oldCount = getItemCount();
int todayPosition = -1;
for (int i = 0; i < data.size(); i++) {
AgendaEvent e = data.get(i);
if (e.startDay != lastGroupDay) {
lastGroupDay = e.startDay;
item = new HeaderItem();
if (e.startDay == today) {
item.mTitle = mContext.getString(R.string.today);
} else if (e.startDay == today + 1) {
item.mTitle = mContext.getString(R.string.tomorrow);
} else {
boolean showDayOnly = e.startDay < today + 7 && e.startDay > today;
if (showDayOnly) {
item.mTitle = DateUtils.formatDateTime(mContext, e.startMillis,
DateUtils.FORMAT_SHOW_WEEKDAY);
} else {
item.mTitle = DateUtils.formatDateTime(mContext, e.startMillis,
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY |
DateUtils.FORMAT_ABBREV_WEEKDAY);
}
}
if (todayPosition == -1 && e.startDay >= today) {
todayPosition = headers.size();
}
item.mEvents = new ArrayList<>();
item.mJulianDay = e.startDay;
headers.add(item);
}
if (item != null) {
item.mEvents.add(e);
}
}
int count = headers.size();
if (oldCount <= 1 && todayPosition != -1) {
count = Math.min(count, todayPosition + 3);
for (int i = todayPosition; i < count; i++) {
headers.get(i).mExpanded = true;
}
}
setItems(headers);
return todayPosition;
}
public void setItems(List<HeaderItem> items) {
mVisibleItems.clear();
for (HeaderItem item : items) {
mVisibleItems.add(item);
if (item.mExpanded) {
mVisibleItems.addAll(item.mEvents);
}
}
mVisibleItems.add(0, mHeaderView);
notifyDataSetChanged();
}
@Override
public boolean hasWeekNumberAtPosition(int position) {
return false;
}
@Override
int getJulianDayAtPosition(int position) {
return 0;
}
@Override
public void focusPosition(int agendaPosition) {
if (agendaPosition != -1) {
expand(agendaPosition);
}
}
@Override
public void clear() {
int count = mVisibleItems.size();
removeItemRange(1, count - 1);
}
public void expand(int position) {
HeaderItem item = (HeaderItem) mVisibleItems.get(position);
if (!item.mExpanded) {
item.mExpanded = true;
onExpand(position);
}
}
public static class ParallaxHeaderViewHolder extends AgendaViewHolder {
public ParallaxHeaderViewHolder(View itemView) {
super(itemView);
}
@Override
public boolean bind(Object object) {
return true;
}
}
}