package org.mtransit.android.ui.view; import java.util.ArrayList; import java.util.concurrent.TimeUnit; import org.mtransit.android.R; import org.mtransit.android.commons.MTLog; import org.mtransit.android.commons.SpanUtils; import org.mtransit.android.commons.StringUtils; import org.mtransit.android.commons.data.AppStatus; import org.mtransit.android.commons.data.AvailabilityPercent; import org.mtransit.android.commons.data.POI; import org.mtransit.android.commons.data.POIStatus; import org.mtransit.android.commons.data.RouteTripStop; import org.mtransit.android.commons.data.Schedule; import org.mtransit.android.data.POIManager; import android.content.Context; import android.graphics.PorterDuff; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import android.text.style.TextAppearanceSpan; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; public class POIStatusDetailViewController implements MTLog.Loggable { private static final String TAG = POIStatusDetailViewController.class.getSimpleName(); @Override public String getLogTag() { return TAG; } public static Integer getLayoutResId(POIManager poim) { if (poim != null) { switch (poim.getStatusType()) { case POI.ITEM_STATUS_TYPE_NONE: return null; case POI.ITEM_STATUS_TYPE_APP: return R.layout.layout_poi_detail_status_app; case POI.ITEM_STATUS_TYPE_SCHEDULE: return R.layout.layout_poi_detail_status_schedule; case POI.ITEM_STATUS_TYPE_AVAILABILITY_PERCENT: return R.layout.layout_poi_detail_status_availability_percent; } } MTLog.w(TAG, "getLayoutResId() > Unknow view type for poi %s!", poim); return null; } public static void initViewHolder(POIManager poim, View view) { switch (poim.getStatusType()) { case POI.ITEM_STATUS_TYPE_NONE: break; case POI.ITEM_STATUS_TYPE_APP: initAppStatusViewHolder(poim, view); break; case POI.ITEM_STATUS_TYPE_SCHEDULE: initScheduleViewHolder(poim, view); break; case POI.ITEM_STATUS_TYPE_AVAILABILITY_PERCENT: initAvailabilityPercentViewHolder(poim, view); break; default: MTLog.w(TAG, "initViewHolder() > Unknow view status type for poi %s!", poim); } } private static void initAppStatusViewHolder(POIManager poim, View view) { AppStatusViewHolder appStatusViewHolder = new AppStatusViewHolder(); initCommonStatusViewHolderHolder(appStatusViewHolder, view); appStatusViewHolder.textTv = (TextView) view.findViewById(R.id.textTv); view.setTag(appStatusViewHolder); } private static void initAvailabilityPercentViewHolder(POIManager poim, View view) { AvailabilityPercentStatusViewHolder availabilityPercentStatusViewHolder = new AvailabilityPercentStatusViewHolder(); initCommonStatusViewHolderHolder(availabilityPercentStatusViewHolder, view); availabilityPercentStatusViewHolder.textTv1 = (TextView) view.findViewById(R.id.progress_text1); availabilityPercentStatusViewHolder.textTv2 = (TextView) view.findViewById(R.id.progress_text2); availabilityPercentStatusViewHolder.progressBar = (ProgressBar) view.findViewById(R.id.progress_bar); if (poim != null) { availabilityPercentStatusViewHolder.progressBar.getProgressDrawable().setColorFilter(poim.getColor(view.getContext()), PorterDuff.Mode.SRC_IN); } view.setTag(availabilityPercentStatusViewHolder); } private static void initScheduleViewHolder(POIManager poim, View view) { ScheduleStatusViewHolder scheduleStatusViewHolder = new ScheduleStatusViewHolder(); initCommonStatusViewHolderHolder(scheduleStatusViewHolder, view); scheduleStatusViewHolder.nextDeparturesLL = (LinearLayout) view.findViewById(R.id.next_departures_layout); view.setTag(scheduleStatusViewHolder); } public static void updatePOIStatus(Context context, View view, POIStatus status, POIViewController.POIDataProvider dataProvider, POIManager optPOI) { if (view == null || view.getTag() == null || !(view.getTag() instanceof CommonStatusViewHolder)) { return; } CommonStatusViewHolder holder = (CommonStatusViewHolder) view.getTag(); updatePOIStatus(context, holder, status, dataProvider, optPOI); } private static void updatePOIStatus(Context context, CommonStatusViewHolder statusViewHolder, POIStatus status, POIViewController.POIDataProvider dataProvider, POIManager optPOI) { if (dataProvider == null || !dataProvider.isShowingStatus() || status == null || statusViewHolder == null) { if (statusViewHolder != null) { setStatusView(statusViewHolder, false); } return; } switch (status.getType()) { case POI.ITEM_STATUS_TYPE_NONE: setStatusView(statusViewHolder, false); break; case POI.ITEM_STATUS_TYPE_AVAILABILITY_PERCENT: updateAvailabilityPercentView(context, statusViewHolder, status); break; case POI.ITEM_STATUS_TYPE_SCHEDULE: updateScheduleView(context, statusViewHolder, status, dataProvider, optPOI); break; case POI.ITEM_STATUS_TYPE_APP: updateAppStatusView(context, statusViewHolder, status); break; default: MTLog.w(TAG, "Unexpected status type '%s'!", status.getType()); setStatusView(statusViewHolder, false); } } public static void updateView(Context context, View view, POIManager poim, POIViewController.POIDataProvider dataProvider) { if (view == null) { return; } if (view.getTag() == null || !(view.getTag() instanceof CommonStatusViewHolder)) { initViewHolder(poim, view); } CommonStatusViewHolder holder = (CommonStatusViewHolder) view.getTag(); updateView(context, holder, poim, dataProvider); } private static void updateView(Context context, CommonStatusViewHolder statusViewHolder, POIManager poim, POIViewController.POIDataProvider dataProvider) { if (dataProvider == null || !dataProvider.isShowingStatus() || poim == null || statusViewHolder == null) { if (statusViewHolder != null) { setStatusView(statusViewHolder, false); } return; } switch (poim.getStatusType()) { case POI.ITEM_STATUS_TYPE_NONE: setStatusView(statusViewHolder, false); break; case POI.ITEM_STATUS_TYPE_AVAILABILITY_PERCENT: updateAvailabilityPercentView(context, statusViewHolder, poim, dataProvider); break; case POI.ITEM_STATUS_TYPE_SCHEDULE: updateScheduleView(context, statusViewHolder, poim, dataProvider); break; case POI.ITEM_STATUS_TYPE_APP: updateAppStatusView(context, statusViewHolder, poim, dataProvider); break; default: MTLog.w(TAG, "Unexpected status type '%s'!", poim.getStatusType()); setStatusView(statusViewHolder, false); } } private static void updateAppStatusView(Context context, CommonStatusViewHolder statusViewHolder, POIManager poim, POIViewController.POIDataProvider dataProvider) { if (dataProvider != null && dataProvider.isShowingStatus() && poim != null && statusViewHolder instanceof AppStatusViewHolder) { poim.setStatusLoaderListener(dataProvider); updateAppStatusView(context, statusViewHolder, poim.getStatus(context)); } else { setStatusView(statusViewHolder, false); } } private static void updateAppStatusView(Context context, CommonStatusViewHolder statusViewHolder, POIStatus status) { AppStatusViewHolder appStatusViewHolder = (AppStatusViewHolder) statusViewHolder; if (status != null && status instanceof AppStatus) { AppStatus appStatus = (AppStatus) status; appStatusViewHolder.textTv.setText(appStatus.getStatusMsg(context)); appStatusViewHolder.textTv.setVisibility(View.VISIBLE); setStatusView(statusViewHolder, true); } else { setStatusView(statusViewHolder, false); } } private static void updateAvailabilityPercentView(Context context, CommonStatusViewHolder statusViewHolder, POIManager poim, POIViewController.POIDataProvider dataProvider) { if (dataProvider != null && dataProvider.isShowingStatus() && poim != null && statusViewHolder instanceof AvailabilityPercentStatusViewHolder) { poim.setStatusLoaderListener(dataProvider); updateAvailabilityPercentView(context, statusViewHolder, poim.getStatus(context)); } else { setStatusView(statusViewHolder, false); } } private static void updateAvailabilityPercentView(Context context, CommonStatusViewHolder statusViewHolder, POIStatus status) { AvailabilityPercentStatusViewHolder availabilityPercentStatusViewHolder = (AvailabilityPercentStatusViewHolder) statusViewHolder; if (status != null && status instanceof AvailabilityPercent) { AvailabilityPercent availabilityPercent = (AvailabilityPercent) status; if (!availabilityPercent.isStatusOK()) { availabilityPercentStatusViewHolder.textTv2.setVisibility(View.GONE); availabilityPercentStatusViewHolder.textTv1.setText(availabilityPercent.getStatusMsg(context)); availabilityPercentStatusViewHolder.textTv1.setVisibility(View.VISIBLE); } else { availabilityPercentStatusViewHolder.textTv1.setText(availabilityPercent.getValue1Text(context)); availabilityPercentStatusViewHolder.textTv1.setVisibility(View.VISIBLE); availabilityPercentStatusViewHolder.textTv2.setText(availabilityPercent.getValue2Text(context)); availabilityPercentStatusViewHolder.textTv2.setVisibility(View.VISIBLE); } availabilityPercentStatusViewHolder.progressBar.setIndeterminate(false); availabilityPercentStatusViewHolder.progressBar.setMax(availabilityPercent.getTotalValue()); availabilityPercentStatusViewHolder.progressBar.setProgress(availabilityPercent.getValue1()); availabilityPercentStatusViewHolder.progressBar.setVisibility(View.VISIBLE); setStatusView(statusViewHolder, true); } else { setStatusView(statusViewHolder, false); } } private static void updateScheduleView(Context context, CommonStatusViewHolder statusViewHolder, POIManager poim, POIViewController.POIDataProvider dataProvider) { if (dataProvider != null && dataProvider.isShowingStatus() && poim != null && statusViewHolder instanceof ScheduleStatusViewHolder) { poim.setStatusLoaderListener(dataProvider); updateScheduleView(context, statusViewHolder, poim.getStatus(context), dataProvider, poim); } else { setStatusView(statusViewHolder, false); } } private static void updateScheduleView(Context context, CommonStatusViewHolder statusViewHolder, POIStatus status, POIViewController.POIDataProvider dataProvider, POIManager optPOI) { ArrayList<Pair<CharSequence, CharSequence>> nextDeparturesList = null; if (dataProvider != null && status != null && status instanceof Schedule) { Schedule schedule = (Schedule) status; String defaultHeadSign = (optPOI != null && optPOI.poi != null && optPOI.poi instanceof RouteTripStop) ? ((RouteTripStop) optPOI.poi).getTrip() .getHeading(context) : null; nextDeparturesList = schedule.getScheduleList(context, dataProvider.getNowToTheMinute(), TimeUnit.HOURS.toMillis(1), TimeUnit.HOURS.toMillis(12), 10, 20, defaultHeadSign); } ScheduleStatusViewHolder scheduleStatusViewHolder = (ScheduleStatusViewHolder) statusViewHolder; LayoutInflater layoutInflater = LayoutInflater.from(context); scheduleStatusViewHolder.nextDeparturesLL.removeAllViews(); scheduleStatusViewHolder.nextDeparturesLL.addView(layoutInflater.inflate(R.layout.layout_poi_detail_status_schedule_space, scheduleStatusViewHolder.nextDeparturesLL, false)); SpannableStringBuilder baselineSSB = getScheduleSpace(context); if (nextDeparturesList != null) { for (Pair<CharSequence, CharSequence> nextDeparture : nextDeparturesList) { View view = layoutInflater.inflate(R.layout.layout_poi_detail_status_schedule_departure, scheduleStatusViewHolder.nextDeparturesLL, false); ((TextView) view.findViewById(R.id.next_departure_time_baseline)).setText(baselineSSB); ((TextView) view.findViewById(R.id.next_departure_time)).setText(nextDeparture.first); TextView headSignTv = (TextView) view.findViewById(R.id.next_departures_head_sign); if (TextUtils.isEmpty(nextDeparture.second)) { headSignTv.setText(null); headSignTv.setVisibility(View.INVISIBLE); } else { headSignTv.setText(nextDeparture.second); headSignTv.setVisibility(View.VISIBLE); } scheduleStatusViewHolder.nextDeparturesLL.addView(view); } } scheduleStatusViewHolder.nextDeparturesLL.setVisibility(View.VISIBLE); setStatusView(statusViewHolder, nextDeparturesList != null && nextDeparturesList.size() > 0); } private static final RelativeSizeSpan SCHEDULE_SPACE_SIZE = SpanUtils.getNew200PercentSizeSpan(); private static final StyleSpan SCHEDULE_SPACE_STYLE = SpanUtils.getNewBoldStyleSpan(); private static TextAppearanceSpan scheduleSpaceTextAppearance = null; private static TextAppearanceSpan getScheduleSpaceTextAppearance(Context context) { if (scheduleSpaceTextAppearance == null) { scheduleSpaceTextAppearance = SpanUtils.getNewLargeTextAppearance(context); } return scheduleSpaceTextAppearance; } private static SpannableStringBuilder baselineSSB; private static SpannableStringBuilder getScheduleSpace(Context context) { if (baselineSSB == null) { baselineSSB = SpanUtils.setAll(new SpannableStringBuilder(StringUtils.SPACE_STRING), // getScheduleSpaceTextAppearance(context), SCHEDULE_SPACE_STYLE, SCHEDULE_SPACE_SIZE); } return baselineSSB; } private static void setStatusView(CommonStatusViewHolder statusViewHolder, boolean loaded) { if (loaded) { setStatusAsLoaded(statusViewHolder); } else { setStatusAsLoading(statusViewHolder); } } private static void setStatusAsLoading(CommonStatusViewHolder statusViewHolder) { if (statusViewHolder.loadingV != null) { statusViewHolder.loadingV.setVisibility(View.VISIBLE); } } private static void setStatusAsLoaded(CommonStatusViewHolder statusViewHolder) { if (statusViewHolder.loadingV != null) { statusViewHolder.loadingV.setVisibility(View.GONE); } } private static void initCommonStatusViewHolderHolder(CommonStatusViewHolder holder, View view) { holder.statusV = view; } private static class CommonStatusViewHolder { @SuppressWarnings("unused") View statusV; View loadingV; } private static class AvailabilityPercentStatusViewHolder extends CommonStatusViewHolder { TextView textTv1; TextView textTv2; ProgressBar progressBar; } private static class AppStatusViewHolder extends CommonStatusViewHolder { TextView textTv; } private static class ScheduleStatusViewHolder extends CommonStatusViewHolder { LinearLayout nextDeparturesLL; } }