package com.github.tibolte.agendacalendarview.calendar; import com.github.tibolte.agendacalendarview.CalendarManager; import com.github.tibolte.agendacalendarview.R; import com.github.tibolte.agendacalendarview.calendar.weekslist.WeekListView; import com.github.tibolte.agendacalendarview.calendar.weekslist.WeeksAdapter; import com.github.tibolte.agendacalendarview.models.CalendarEvent; import com.github.tibolte.agendacalendarview.models.IDayItem; import com.github.tibolte.agendacalendarview.models.IWeekItem; import com.github.tibolte.agendacalendarview.utils.BusProvider; import com.github.tibolte.agendacalendarview.utils.DateHelper; import com.github.tibolte.agendacalendarview.utils.Events; import android.content.Context; import android.support.v7.widget.LinearLayoutManager; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.LinearLayout; import android.widget.TextView; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.List; import java.util.Locale; /** * The calendar view is a freely scrolling view that allows the user to browse between days of the * year. */ public class CalendarView extends LinearLayout { private static final String LOG_TAG = CalendarView.class.getSimpleName(); /** * Top of the calendar view layout, the week days list */ private LinearLayout mDayNamesHeader; /** * Part of the calendar view layout always visible, the weeks list */ private WeekListView mListViewWeeks; /** * The adapter for the weeks list */ private WeeksAdapter mWeeksAdapter; /** * The current highlighted day in blue */ private IDayItem mSelectedDay; /** * The current row displayed at top of the list */ private int mCurrentListPosition; // region Constructors public CalendarView(Context context) { super(context); } public CalendarView(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.view_calendar, this, true); setOrientation(VERTICAL); } // endregion public IDayItem getSelectedDay() { return mSelectedDay; } public void setSelectedDay(IDayItem mSelectedDay) { this.mSelectedDay = mSelectedDay; } public WeekListView getListViewWeeks() { return mListViewWeeks; } // region Class - View @Override protected void onFinishInflate() { super.onFinishInflate(); mDayNamesHeader = (LinearLayout) findViewById(R.id.cal_day_names); mListViewWeeks = (WeekListView) findViewById(R.id.list_week); mListViewWeeks.setLayoutManager(new LinearLayoutManager(getContext())); mListViewWeeks.setHasFixedSize(true); mListViewWeeks.setItemAnimator(null); mListViewWeeks.setSnapEnabled(true); // display only two visible rows on the calendar view getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (getWidth() != 0 && getHeight() != 0) { collapseCalendarView(); getViewTreeObserver().removeGlobalOnLayoutListener(this); } } } ); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); BusProvider.getInstance().toObserverable() .subscribe(event -> { if (event instanceof Events.CalendarScrolledEvent) { expandCalendarView(); } else if (event instanceof Events.AgendaListViewTouchedEvent) { collapseCalendarView(); } else if (event instanceof Events.DayClickedEvent) { Events.DayClickedEvent clickedEvent = (Events.DayClickedEvent) event; updateSelectedDay(clickedEvent.getCalendar(), clickedEvent.getDay()); } }); } // endregion // region Public methods public void init(CalendarManager calendarManager, int dayTextColor, int currentDayTextColor, int pastDayTextColor) { Calendar today = calendarManager.getToday(); Locale locale = calendarManager.getLocale(); SimpleDateFormat weekDayFormatter = calendarManager.getWeekdayFormatter(); List<IWeekItem> weeks = calendarManager.getWeeks(); setUpHeader(today, weekDayFormatter, locale); setUpAdapter(today, weeks, dayTextColor, currentDayTextColor, pastDayTextColor); scrollToDate(today, weeks); } /** * Fired when the Agenda list view changes section. * * @param calendarEvent The event for the selected position in the agenda listview. */ public void scrollToDate(final CalendarEvent calendarEvent) { mListViewWeeks.post(()->scrollToPosition(updateSelectedDay(calendarEvent.getInstanceDay(), calendarEvent.getDayReference()))); } public void scrollToDate(Calendar today, List<IWeekItem> weeks) { Integer currentWeekIndex = null; for (int c = 0; c < weeks.size(); c++) { if (DateHelper.sameWeek(today, weeks.get(c))) { currentWeekIndex = c; break; } } if (currentWeekIndex != null) { final Integer finalCurrentWeekIndex = currentWeekIndex; mListViewWeeks.post(() -> scrollToPosition(finalCurrentWeekIndex)); } } public void setBackgroundColor(int color) { mListViewWeeks.setBackgroundColor(color); } // endregion // region Private methods private void scrollToPosition(int targetPosition) { LinearLayoutManager layoutManager = ((LinearLayoutManager) mListViewWeeks.getLayoutManager()); layoutManager.scrollToPosition(targetPosition); } private void updateItemAtPosition(int position) { WeeksAdapter weeksAdapter = (WeeksAdapter) mListViewWeeks.getAdapter(); weeksAdapter.notifyItemChanged(position); } /** * Creates a new adapter if necessary and sets up its parameters. */ private void setUpAdapter(Calendar today, List<IWeekItem> weeks, int dayTextColor, int currentDayTextColor, int pastDayTextColor) { if (mWeeksAdapter == null) { Log.d(LOG_TAG, "Setting adapter with today's calendar: " + today.toString()); mWeeksAdapter = new WeeksAdapter(getContext(), today, dayTextColor, currentDayTextColor, pastDayTextColor); mListViewWeeks.setAdapter(mWeeksAdapter); } mWeeksAdapter.updateWeeksItems(weeks); } private void setUpHeader(Calendar today, SimpleDateFormat weekDayFormatter, Locale locale) { int daysPerWeek = 7; String[] dayLabels = new String[daysPerWeek]; Calendar cal = Calendar.getInstance(CalendarManager.getInstance(getContext()).getLocale()); cal.setTime(today.getTime()); int firstDayOfWeek = cal.getFirstDayOfWeek(); for (int count = 0; count < 7; count++) { cal.set(Calendar.DAY_OF_WEEK, firstDayOfWeek + count); if (locale.getLanguage().equals("en")) { dayLabels[count] = weekDayFormatter.format(cal.getTime()).toUpperCase(locale); } else { dayLabels[count] = weekDayFormatter.format(cal.getTime()); } } for (int i = 0; i < mDayNamesHeader.getChildCount(); i++) { TextView txtDay = (TextView) mDayNamesHeader.getChildAt(i); txtDay.setText(dayLabels[i]); } } private void expandCalendarView() { ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); layoutParams.height = (int) (getResources().getDimension(R.dimen.calendar_header_height) + 5 * getResources().getDimension(R.dimen.day_cell_height)); setLayoutParams(layoutParams); } private void collapseCalendarView() { ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); layoutParams.height = (int) (getResources().getDimension(R.dimen.calendar_header_height) + 2 * getResources().getDimension(R.dimen.day_cell_height)); setLayoutParams(layoutParams); } /** * Update a selected cell day item. * * @param calendar The Calendar instance of the day selected. * @param dayItem The DayItem information held by the cell item. * @return The selected row of the weeks list, to be updated. */ private int updateSelectedDay(Calendar calendar, IDayItem dayItem) { Integer currentWeekIndex = null; // update highlighted/selected day if (!dayItem.equals(getSelectedDay())) { dayItem.setSelected(true); if (getSelectedDay() != null) { getSelectedDay().setSelected(false); } setSelectedDay(dayItem); } for (int c = 0; c < CalendarManager.getInstance().getWeeks().size(); c++) { if (DateHelper.sameWeek(calendar, CalendarManager.getInstance().getWeeks().get(c))) { currentWeekIndex = c; break; } } if (currentWeekIndex != null) { // highlighted day has changed, update the rows concerned if (currentWeekIndex != mCurrentListPosition) { updateItemAtPosition(mCurrentListPosition); } mCurrentListPosition = currentWeekIndex; updateItemAtPosition(currentWeekIndex); } return mCurrentListPosition; } // endregion }