/*
* Android Weather Notification.
* Copyright (C) 2010 Denis Nelubin aka Gelin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* http://gelin.ru
* mailto:den@gelin.ru
*/
package ru.gelin.android.weather.notification.skin.impl;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.view.View;
import ru.gelin.android.weather.*;
import ru.gelin.android.weather.TemperatureUnit;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import static ru.gelin.android.weather.notification.skin.impl.ResourceIdFactory.STRING;
/**
* Utility to layout weather values.
*/
public abstract class AbstractWeatherLayout {
static final String URL_TEMPLATE = "<a href=\"%s\">%s</a>";
static final int MAIN_ICON = 48;
static final int FORECAST_ICON = 16;
static final int NO_CHANGE_COLOR = 0;
/** Current context */
private final Context context;
private final ResourceIdFactory ids;
/**
* Creates the utility for specified context.
*/
protected AbstractWeatherLayout(Context context) {
this.context = context;
this.ids = ResourceIdFactory.getInstance(context);
}
protected Context getContext() {
return this.context;
}
protected ResourceIdFactory getIds() {
return this.ids;
}
/**
* Retreives "id/<name>" resource ID.
*/
protected int id(String name) {
return getIds().id(name);
}
/**
* Retreives "string/<name>" resource ID.
*/
protected int string(String name) {
return getIds().id(STRING, name);
}
/**
* Lays out the weather values on a view.
*/
public void bind(Weather weather) {
if (weather.isEmpty()) {
emptyViews();
} else {
bindViews(weather);
}
}
void bindViews(Weather weather) {
WeatherFormatter formatter = getWeatherFormatter(getContext(), weather);
bindUpdateTime(weather.getQueryTime());
setText(id("location"), weather.getLocation().getText(), getTextColor());
if (weather.getConditions().size() <= 0) {
return;
}
WeatherCondition currentCondition = weather.getConditions().get(0);
setIcon(id("condition_icon"), formatter.getWeatherConditionFormat().getDrawable(currentCondition), getMainIconSize());
setText(id("condition"), formatter.getWeatherConditionFormat().getText(currentCondition), getTextColor());
bindWindHumidity(currentCondition, formatter);
TemperatureType tempType = formatter.getStyler().getTempType();
Temperature tempC = currentCondition.getTemperature(TemperatureUnit.C);
Temperature tempF = currentCondition.getTemperature(TemperatureUnit.F);
TemperatureUnit mainUnit = tempType.getTemperatureUnit();
Temperature mainTemp = currentCondition.getTemperature(mainUnit);
setVisibility(id("temp"), View.VISIBLE);
setText(id("current_temp"),
formatter.getTemperatureFormat().format(mainTemp.getCurrent(), tempType), getTextColor());
switch(tempType) { //TODO: remove multiple appearance of this switch
case C: case F:
setVisibility(id("current_temp_alt"), View.GONE);
break;
case CF:
setText(id("current_temp_alt"),
formatter.getTemperatureFormat().format(tempF.getCurrent(), TemperatureType.F), getTextColor());
setVisibility(id("current_temp_alt"), View.VISIBLE);
break;
case FC:
setText(id("current_temp_alt"),
formatter.getTemperatureFormat().format(tempC.getCurrent(), TemperatureType.C), getTextColor());
setVisibility(id("current_temp_alt"), View.VISIBLE);
break;
}
setText(id("high_temp"),
formatter.getTemperatureFormat().format(mainTemp.getHigh()), getTextColor());
setText(id("low_temp"),
formatter.getTemperatureFormat().format(mainTemp.getLow()), getTextColor());
bindForecasts(weather, formatter);
bindForecastUrl(weather);
}
protected void bindUpdateTime(Date update) {
if (update.getTime() == 0) {
setText(id("update_time"), "", NO_CHANGE_COLOR);
} else if (isDate(update)) {
setText(id("update_time"),
getContext().getString(string("update_date_format"), update), getTextColor());
} else {
setText(id("update_time"),
getContext().getString(string("update_time_format"), update), getTextColor());
}
}
protected void bindWindHumidity(WeatherCondition currentCondition, WeatherFormatter formatter) {
WindUnit windUnit = formatter.getStyler().getWindUnit();
Wind wind = currentCondition.getWind(windUnit.getWindSpeedUnit());
setText(id("wind"), formatter.getWindFormat().format(wind), getTextColor());
Humidity humidity = currentCondition.getHumidity();
setText(id("humidity"), formatter.getHumidityFormat().format(humidity), getTextColor());
}
protected void bindForecasts(Weather weather, WeatherFormatter formatter) {
setVisibility(id("forecasts"), View.VISIBLE);
bindForecast(weather, formatter, 1,
id("forecast_1"),
id("forecast_condition_icon_1"),
id("forecast_day_1"),
id("forecast_condition_1"),
id("forecast_high_temp_1"), id("forecast_low_temp_1"));
bindForecast(weather, formatter, 2,
id("forecast_2"),
id("forecast_condition_icon_2"),
id("forecast_day_2"),
id("forecast_condition_2"),
id("forecast_high_temp_2"), id("forecast_low_temp_2"));
bindForecast(weather, formatter, 3,
id("forecast_3"),
id("forecast_condition_icon_3"),
id("forecast_day_3"),
id("forecast_condition_3"),
id("forecast_high_temp_3"), id("forecast_low_temp_3"));
}
void bindForecast(Weather weather,
WeatherFormatter formatter,
int i,
int groupId, int iconId, int dayId, int conditionId,
int highTempId, int lowTempId) {
if (weather.getConditions().size() > i) {
setVisibility(groupId, View.VISIBLE);
WeatherCondition forecastCondition = weather.getConditions().get(i);
Date tomorrow = addDays(weather.getTime(), i);
setIcon(iconId, formatter.getWeatherConditionFormat().getDrawable(forecastCondition), getForecastIconSize());
setText(dayId, getContext().getString(string("forecast_day_format"), tomorrow), getTextColor());
setText(conditionId, formatter.getWeatherConditionFormat().getText(forecastCondition), getTextColor());
Temperature forecastTemp = forecastCondition.getTemperature(
formatter.getStyler().getTempType().getTemperatureUnit());
setText(highTempId, formatter.getTemperatureFormat().format(forecastTemp.getHigh()), getTextColor());
setText(lowTempId, formatter.getTemperatureFormat().format(forecastTemp.getLow()), getTextColor());
} else {
setVisibility(groupId, View.GONE);
}
}
void bindForecastUrl(Weather weather) {
if (weather.getForecastURL() == null) {
setVisibility(id("forecast_url"), View.INVISIBLE);
return;
}
setVisibility(id("forecast_url"), View.VISIBLE);
URL url = weather.getForecastURL();
String link = String.format(URL_TEMPLATE, url.toString(), url.getHost());
setMovementMethod(id("forecast_url"), LinkMovementMethod.getInstance());
setText(id("forecast_url"), Html.fromHtml(link), NO_CHANGE_COLOR);
}
void emptyViews() {
setText(id("update_time"), "", NO_CHANGE_COLOR);
setText(id("location"), "", NO_CHANGE_COLOR);
setText(id("condition"), getContext().getString(string("unknown_weather")), getTextColor());
setText(id("humidity"), "", NO_CHANGE_COLOR);
setText(id("wind"), "", NO_CHANGE_COLOR);
setText(id("wind_humidity_text"), "", NO_CHANGE_COLOR);
setVisibility(id("temp"), View.INVISIBLE);
setVisibility(id("forecasts"), View.GONE);
setVisibility(id("forecasts_text"), View.GONE);
setVisibility(id("forecast_url"), View.INVISIBLE);
}
protected abstract void setText(int viewId, CharSequence text, int color);
protected abstract void setIcon(int viewId, Drawable drawable, int level);
protected abstract void setVisibility(int viewId, int visibility);
protected abstract void setMovementMethod(int viewId, MovementMethod method);
Date addDays(Date date, int days) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_YEAR, days);
return calendar.getTime();
}
/**
* Returns true if the provided date has zero (0:00:00) time.
*/
boolean isDate(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar.get(Calendar.HOUR) == 0 &&
calendar.get(Calendar.MINUTE) == 0 &&
calendar.get(Calendar.SECOND) == 0 &&
calendar.get(Calendar.MILLISECOND) == 0;
}
/**
* Returns the text color to be set on all text views.
* This color is passed to #setText() calls.
*/
protected abstract int getTextColor();
/**
* Returns size of the main condition icon. In dp.
*/
protected int getMainIconSize() {
return MAIN_ICON;
}
/**
* Returns size of the forecast condition icon. In dp.
*/
protected int getForecastIconSize() {
return FORECAST_ICON;
}
protected WeatherFormatter getWeatherFormatter(Context context, Weather weather) {
return new WeatherFormatter(context, weather);
}
}