/* * 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.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.annotation.StyleRes; import android.text.Layout; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; import android.text.style.TextAppearanceSpan; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; /** * A simple drawable that can render the start time of an event * Created by Nick on 24/09/14. */ public class EventTimeDrawable extends Drawable { public static final int AMPM_NONE = 0; public static final int AMPM_AM = 1; public static final int AMPM_PM = 2; static final SimpleDateFormat sMonthFormat = new SimpleDateFormat("MMM", Locale.getDefault()); static final Date sFormatDate = new Date(); static final Calendar sFormatCalendar = Calendar.getInstance(); private static TextPaint sPaint; private final Context mContext; final SpannableStringBuilder mTimeBuilder; SpannableStringBuilder mAmPmBuilder; /** * The hour to display in the drawable */ private int mHour; /** * The minute to display in the drawable */ private int mMinutes; private int mAmpm; private Layout mTimeLayout; private Layout mAmpmLayout; private final Object mHourSpan; private final Object mMinuteSpan; @StyleRes private final int mAmpmStyle; private int mAlpha = 255; private ColorFilter mColorFilter; private int mMonth; private int mDay; private boolean mAllDay; public EventTimeDrawable(Context context, @StyleRes int hourStyle, @StyleRes int minuteStyle, @StyleRes int amPmStyle) { if (sPaint == null) { sPaint = new TextPaint(); sPaint.setAntiAlias(true); } mContext = context; mAmpmStyle = amPmStyle; mTimeBuilder = new SpannableStringBuilder(); mHourSpan = new TextAppearanceSpan(mContext, hourStyle); mMinuteSpan = new TextAppearanceSpan(mContext, minuteStyle); } public void setTime(boolean allDay, int day, int month, int hour, int minutes, int ampm) { mAllDay = allDay; mDay = day; mMonth = month; mHour = hour; mMinutes = minutes; mAmpm = ampm; updateLayout(); } private void updateLayout() { Rect bounds = getBounds(); if (bounds.width() <= 0) return; if (mAllDay) { updateLayoutAllDay(); return; } // clear the entire layout mTimeBuilder.clear(); // append the hour and set it's style mTimeBuilder.append(String.valueOf(mHour)); mTimeBuilder.setSpan(mHourSpan, 0, mTimeBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // append the minutes and set it's style // first remember the current start position int start = mTimeBuilder.length(); String minutes = String.valueOf(mMinutes); // when the string is only 1 digit in length prefix it with // a 0. This makes '5' -> '05' if (minutes.length() < 2) { minutes = "0" + minutes; } mTimeBuilder.append(minutes); mTimeBuilder.setSpan(mMinuteSpan, start, mTimeBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mTimeLayout = new StaticLayout(mTimeBuilder, sPaint, bounds.width(), Layout.Alignment.ALIGN_CENTER, 1, 0, true); if (mAmpm == AMPM_NONE) { mAmpmLayout = null; } else { if (mAmPmBuilder == null) { mAmPmBuilder = new SpannableStringBuilder(); } mAmPmBuilder.clear(); mAmPmBuilder.append(mAmpm == AMPM_AM ? "am" : "pm"); mAmPmBuilder.setSpan(new TextAppearanceSpan(mContext, mAmpmStyle), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mAmpmLayout = new StaticLayout(mAmPmBuilder, sPaint, bounds.width(), Layout.Alignment.ALIGN_CENTER, 1, 0, true); } } private void updateLayoutAllDay() { Rect bounds = getBounds(); // clear the entire layout mTimeBuilder.clear(); // append the hour and set it's style mTimeBuilder.append(String.valueOf(mDay)); mTimeBuilder.setSpan(mHourSpan, 0, mTimeBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mTimeLayout = new StaticLayout(mTimeBuilder, sPaint, bounds.width(), Layout.Alignment.ALIGN_CENTER, 1, 0, true); // this builder may be null to make sure it is only used when needed // so check if it is null and create it if needed. if (mAmPmBuilder == null) { mAmPmBuilder = new SpannableStringBuilder(); } mAmPmBuilder.clear(); sFormatCalendar.set(Calendar.MONTH, mMonth); sFormatDate.setTime(sFormatCalendar.getTimeInMillis()); mAmPmBuilder.append(sMonthFormat.format(sFormatDate)); mAmPmBuilder.setSpan(new TextAppearanceSpan(mContext, mAmpmStyle), 0, mAmPmBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mAmpmLayout = new StaticLayout(mAmPmBuilder, sPaint, bounds.width(), Layout.Alignment.ALIGN_CENTER, 1, 0, true); } @Override public void draw(Canvas canvas) { if (mAmpmLayout == null && mTimeLayout == null) return; sPaint.setAlpha(mAlpha); sPaint.setColorFilter(mColorFilter); Rect bounds = getBounds(); sPaint.setColor(0x18000000); canvas.drawCircle(bounds.centerX(), bounds.centerY(), bounds.width() / 2, sPaint); if (mAmpmLayout == null) { // simply center the time layout int h = mTimeLayout.getHeight(); int top = (bounds.height() - h) / 2; canvas.translate(0, top); mTimeLayout.draw(canvas); // translate back to restore the state of the canvas canvas.translate(0, -top); } else { int h = mTimeLayout.getHeight(); int top = ((bounds.height() - h) / 5) * 2; canvas.translate(0, top); mTimeLayout.draw(canvas); canvas.translate(0, -top); int ampmHeight = mAmpmLayout.getHeight(); canvas.translate(0, bounds.height()); canvas.translate(0, -ampmHeight); // add 1/3rd of the height of the am/pm text as margin canvas.translate(0, -ampmHeight / 3); mAmpmLayout.draw(canvas); // translate back and restore the state of the canvas canvas.translate(0, ampmHeight / 3); canvas.translate(0, ampmHeight); canvas.translate(0, -bounds.height()); } } @Override public void setBounds(Rect bounds) { super.setBounds(bounds); updateLayout(); Callback callback = getCallback(); if (callback != null) { callback.invalidateDrawable(this); } } @Override public void setAlpha(int alpha) { mAlpha = alpha; } @Override public void setColorFilter(ColorFilter cf) { mColorFilter = cf; } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } }