/** * Copyright (c) 2012 Todoroo Inc * * See the file "LICENSE" for the full license governing this code. */ package com.todoroo.astrid.ui; import java.util.ArrayList; import java.util.Date; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; import android.widget.ToggleButton; import com.timsu.astrid.R; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.ui.AstridTimePicker.TimePickerEnabledChangedListener; import com.todoroo.astrid.ui.CalendarView.OnSelectedDateListener; public class DateAndTimePicker extends LinearLayout { public interface OnDateChangedListener { public void onDateChanged(); } private static final int SHORTCUT_PADDING = 8; private ArrayList<UrgencyValue> urgencyValues; private class UrgencyValue { public String label; public int setting; public long dueDate; public UrgencyValue(String label, int setting) { this.label = label; this.setting = setting; dueDate = Task.createDueDate(setting, 0); } @Override public String toString() { return label; } } private final CalendarView calendarView; private final AstridTimePicker timePicker; private final LinearLayout dateShortcuts; private OnDateChangedListener listener; private final boolean useShortcuts; private UrgencyValue todayUrgency; public DateAndTimePicker(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); useShortcuts = Preferences.getBoolean(R.string.p_use_date_shortcuts, true); inflater.inflate(useShortcuts ? R.layout.date_time_picker : R.layout.date_time_picker_no_shortcuts, this, true); calendarView = (CalendarView) findViewById(R.id.calendar); timePicker = (AstridTimePicker) findViewById(R.id.time_picker); if (useShortcuts) dateShortcuts = (LinearLayout) findViewById(R.id.date_shortcuts); else { findViewById(R.id.date_shortcuts).setVisibility(View.GONE); dateShortcuts = (LinearLayout) timePicker.findViewById(R.id.date_shortcuts); } setUpListeners(); constructShortcutList(context, attrs); } public void initializeWithDate(long dateValue) { Date date = new Date(dateValue); Date forCalendar; if (dateValue> 0) forCalendar = getDateForCalendar(date); else forCalendar = date; calendarView.setCalendarDate(forCalendar); if (Task.hasDueTime(dateValue)) { timePicker.setHours(date.getHours()); timePicker.setMinutes(date.getMinutes()); timePicker.setHasTime(true); } else { timePicker.setHours(18); timePicker.setMinutes(0); timePicker.setHasTime(false); } updateShortcutView(forCalendar); } private Date getDateForCalendar(Date date) { Date forCalendar = new Date(date.getTime() / 1000L * 1000L); forCalendar.setHours(12); forCalendar.setMinutes(0); forCalendar.setSeconds(0); return forCalendar; } private void setUpListeners() { calendarView.setOnSelectedDateListener(new OnSelectedDateListener() { @Override public void onSelectedDate(Date date) { updateShortcutView(date); otherCallbacks(); } }); timePicker.setTimePickerEnabledChangedListener(new TimePickerEnabledChangedListener() { @Override public void timePickerEnabledChanged(boolean hasTime) { if (hasTime) { forceDateSelected(); } } }); } private void forceDateSelected() { ToggleButton none = (ToggleButton) dateShortcuts.getChildAt(dateShortcuts.getChildCount() - 1); if (none.isChecked()) { Date date = new Date(todayUrgency.dueDate); calendarView.setCalendarDate(date); calendarView.invalidate(); if (todayUrgency.setting == Task.URGENCY_NONE) timePicker.forceNoTime(); updateShortcutView(date); otherCallbacks(); } } private void constructShortcutList(Context context, AttributeSet attrs) { int arrayResource = R.array.TEA_urgency; TypedArray t = context.obtainStyledAttributes(attrs, R.styleable.DateAndTimePicker); for (int i = 0; i < t.getIndexCount(); i++) { int attr = t.getIndex(i); switch(attr) { case R.styleable.DateAndTimePicker_shortcutLabels: arrayResource = t.getResourceId(attr, R.array.TEA_urgency); } } String[] labels = context.getResources().getStringArray(arrayResource); urgencyValues = new ArrayList<UrgencyValue>(); todayUrgency = new UrgencyValue(labels[2], Task.URGENCY_TODAY); if (useShortcuts) { urgencyValues.add(todayUrgency); urgencyValues.add(new UrgencyValue(labels[3], Task.URGENCY_TOMORROW)); urgencyValues.add(new UrgencyValue(labels[5], Task.URGENCY_NEXT_WEEK)); urgencyValues.add(new UrgencyValue(labels[7], Task.URGENCY_NEXT_MONTH)); } urgencyValues.add(new UrgencyValue(labels[0], Task.URGENCY_NONE)); Resources r = context.getResources(); DisplayMetrics metrics = r.getDisplayMetrics(); TypedValue onColor = new TypedValue(); context.getTheme().resolveAttribute(R.attr.asThemeTextColor, onColor, false); int onColorValue = r.getColor(onColor.data); int offColorValue = r.getColor(android.R.color.transparent); int borderColorValue = r.getColor(android.R.color.transparent); int cornerRadius = (int) (5 * r.getDisplayMetrics().density); int strokeWidth = (int) (1 * r.getDisplayMetrics().density); for (int i = 0; i < urgencyValues.size(); i++) { LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, (int) ((useShortcuts ? 42 : 38) * metrics.density), 0); UrgencyValue uv = urgencyValues.get(i); ToggleButton tb = new ToggleButton(context); String label = uv.label; tb.setTextOff(label); tb.setTextOn(label); tb.setTag(uv); if (i == 0) { if (useShortcuts) tb.setBackgroundDrawable(CustomBorderDrawable.customButton(cornerRadius, cornerRadius, cornerRadius, cornerRadius, onColorValue, offColorValue, borderColorValue, strokeWidth)); else tb.setBackgroundDrawable(CustomBorderDrawable.customButton(cornerRadius, cornerRadius, cornerRadius, cornerRadius, onColorValue, offColorValue, borderColorValue, strokeWidth)); } else if (i == urgencyValues.size() - 2) { lp.topMargin = (int) (-1 * metrics.density); tb.setBackgroundDrawable(CustomBorderDrawable.customButton(cornerRadius, cornerRadius, cornerRadius, cornerRadius, onColorValue, offColorValue, borderColorValue, strokeWidth)); } else if (i == urgencyValues.size() - 1) { lp.topMargin = (int) (5 * metrics.density); tb.setBackgroundDrawable(CustomBorderDrawable.customButton(cornerRadius, cornerRadius, cornerRadius, cornerRadius, onColorValue, offColorValue, borderColorValue, strokeWidth)); } else { lp.topMargin = (int) (-1 * metrics.density); tb.setBackgroundDrawable(CustomBorderDrawable.customButton(cornerRadius, cornerRadius, cornerRadius, cornerRadius, onColorValue, offColorValue, borderColorValue, strokeWidth)); } int verticalPadding = (int) (SHORTCUT_PADDING * metrics.density); tb.setPadding(0, verticalPadding, 0, verticalPadding); tb.setLayoutParams(lp); tb.setGravity(Gravity.CENTER); tb.setTextSize(18); tb.setTextColor(context.getResources().getColorStateList(R.color.task_edit_toggle_button_text)); tb.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { UrgencyValue value = (UrgencyValue) v.getTag(); Date date = new Date(value.dueDate); calendarView.setCalendarDate(date); calendarView.invalidate(); if (value.setting == Task.URGENCY_NONE) timePicker.forceNoTime(); updateShortcutView(date); otherCallbacks(); } }); dateShortcuts.addView(tb); } } private void updateShortcutView(Date date) { for (int i = 0; i < dateShortcuts.getChildCount(); i++) { View child = dateShortcuts.getChildAt(i); if (child instanceof ToggleButton) { ToggleButton tb = (ToggleButton) child; UrgencyValue uv = (UrgencyValue) tb.getTag(); if (uv != null) { if (uv.dueDate == date.getTime()) { tb.setChecked(true); } else { tb.setChecked(false); } } } } } private void otherCallbacks() { if (listener != null) listener.onDateChanged(); } public long constructDueDate() { Date calendarDate = new Date(calendarView.getCalendarDate().getTime()); if (timePicker.hasTime() && calendarDate.getTime() > 0) { calendarDate.setHours(timePicker.getHours()); calendarDate.setMinutes(timePicker.getMinutes()); calendarDate.setSeconds(1); } else { calendarDate.setSeconds(0); } return calendarDate.getTime(); } public boolean hasTime() { return timePicker.hasTime(); } public void setOnDateChangedListener(OnDateChangedListener listener) { this.listener = listener; } public boolean isAfterNow() { long dueDate = constructDueDate(); return dueDate > DateUtilities.now(); } public String getDisplayString(Context context, boolean useNewline, boolean hideYear) { long dueDate = constructDueDate(); return getDisplayString(context, dueDate, useNewline, hideYear, false); } public static String getDisplayString(Context context, long forDate) { return getDisplayString(context, forDate, false, false, false); } public static String getDisplayString(Context context, long forDate, boolean useNewline, boolean hideYear, boolean hideTime) { StringBuilder displayString = new StringBuilder(); Date d = new Date(forDate); if (d.getTime() > 0) { if (hideYear) displayString.append(DateUtilities.getDateStringHideYear(context, d)); else displayString.append(DateUtilities.getDateString(context, d)); if (Task.hasDueTime(forDate) && !hideTime) { displayString.append(useNewline ? "\n" : ", "); //$NON-NLS-1$ //$NON-NLS-2$ displayString.append(DateUtilities.getTimeString(context, d)); } } return displayString.toString(); } }