Integrate Glide to load weather art icons from an external source
This commit is contained in:
@@ -21,6 +21,7 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
compile 'com.github.bumptech.glide:glide:3.5.2'
|
||||||
compile 'com.android.support:appcompat-v7:21.0.2'
|
compile 'com.android.support:appcompat-v7:21.0.2'
|
||||||
compile 'com.android.support:support-annotations:22.0.0'
|
compile 'com.android.support:support-annotations:22.0.0'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
import com.example.android.sunshine.app.data.WeatherContract;
|
import com.example.android.sunshine.app.data.WeatherContract;
|
||||||
import com.example.android.sunshine.app.data.WeatherContract.WeatherEntry;
|
import com.example.android.sunshine.app.data.WeatherContract.WeatherEntry;
|
||||||
|
|
||||||
@@ -184,7 +185,11 @@ public class DetailFragment extends Fragment implements LoaderManager.LoaderCall
|
|||||||
int weatherId = data.getInt(COL_WEATHER_CONDITION_ID);
|
int weatherId = data.getInt(COL_WEATHER_CONDITION_ID);
|
||||||
|
|
||||||
// Use weather art image
|
// Use weather art image
|
||||||
mIconView.setImageResource(Utility.getArtResourceForWeatherCondition(weatherId));
|
Glide.with(this)
|
||||||
|
.load(Utility.getArtUrlForWeatherCondition(getActivity(), weatherId))
|
||||||
|
.error(Utility.getArtResourceForWeatherCondition(weatherId))
|
||||||
|
.crossFade()
|
||||||
|
.into(mIconView);
|
||||||
|
|
||||||
// Read date from cursor and update views for day of week and date
|
// Read date from cursor and update views for day of week and date
|
||||||
long date = data.getLong(COL_WEATHER_DATE);
|
long date = data.getLong(COL_WEATHER_DATE);
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ForecastAdapter} exposes a list of weather forecasts
|
* {@link ForecastAdapter} exposes a list of weather forecasts
|
||||||
* from a {@link Cursor} to a {@link android.widget.ListView}.
|
* from a {@link Cursor} to a {@link android.widget.ListView}.
|
||||||
@@ -91,21 +93,28 @@ public class ForecastAdapter extends CursorAdapter {
|
|||||||
|
|
||||||
int viewType = getItemViewType(cursor.getPosition());
|
int viewType = getItemViewType(cursor.getPosition());
|
||||||
int weatherId = cursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID);
|
int weatherId = cursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID);
|
||||||
|
int fallbackIconId;
|
||||||
switch (viewType) {
|
switch (viewType) {
|
||||||
case VIEW_TYPE_TODAY: {
|
case VIEW_TYPE_TODAY: {
|
||||||
// Get weather icon
|
// Get weather icon
|
||||||
viewHolder.iconView.setImageResource(Utility.getArtResourceForWeatherCondition(
|
fallbackIconId = Utility.getArtResourceForWeatherCondition(
|
||||||
weatherId));
|
weatherId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VIEW_TYPE_FUTURE_DAY: {
|
default: {
|
||||||
// Get weather icon
|
// Get weather icon
|
||||||
viewHolder.iconView.setImageResource(Utility.getIconResourceForWeatherCondition(
|
fallbackIconId = Utility.getIconResourceForWeatherCondition(
|
||||||
weatherId));
|
weatherId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Glide.with(mContext)
|
||||||
|
.load(Utility.getArtUrlForWeatherCondition(mContext, weatherId))
|
||||||
|
.error(fallbackIconId)
|
||||||
|
.crossFade()
|
||||||
|
.into(viewHolder.iconView);
|
||||||
|
|
||||||
// Read date from cursor
|
// Read date from cursor
|
||||||
long dateInMillis = cursor.getLong(ForecastFragment.COL_WEATHER_DATE);
|
long dateInMillis = cursor.getLong(ForecastFragment.COL_WEATHER_DATE);
|
||||||
// Find TextView and set formatted date on it
|
// Find TextView and set formatted date on it
|
||||||
|
|||||||
@@ -216,6 +216,43 @@ public class Utility {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to provide the art urls according to the weather condition id returned
|
||||||
|
* by the OpenWeatherMap call.
|
||||||
|
*
|
||||||
|
* @param context Context to use for retrieving the URL format
|
||||||
|
* @param weatherId from OpenWeatherMap API response
|
||||||
|
* @return url for the corresponding weather artwork. null if no relation is found.
|
||||||
|
*/
|
||||||
|
public static String getArtUrlForWeatherCondition(Context context, int weatherId) {
|
||||||
|
// Based on weather code data found at:
|
||||||
|
// http://bugs.openweathermap.org/projects/api/wiki/Weather_Condition_Codes
|
||||||
|
if (weatherId >= 200 && weatherId <= 232) {
|
||||||
|
return context.getString(R.string.format_art_url, "storm");
|
||||||
|
} else if (weatherId >= 300 && weatherId <= 321) {
|
||||||
|
return context.getString(R.string.format_art_url, "light_rain");
|
||||||
|
} else if (weatherId >= 500 && weatherId <= 504) {
|
||||||
|
return context.getString(R.string.format_art_url, "rain");
|
||||||
|
} else if (weatherId == 511) {
|
||||||
|
return context.getString(R.string.format_art_url, "snow");
|
||||||
|
} else if (weatherId >= 520 && weatherId <= 531) {
|
||||||
|
return context.getString(R.string.format_art_url, "rain");
|
||||||
|
} else if (weatherId >= 600 && weatherId <= 622) {
|
||||||
|
return context.getString(R.string.format_art_url, "snow");
|
||||||
|
} else if (weatherId >= 701 && weatherId <= 761) {
|
||||||
|
return context.getString(R.string.format_art_url, "fog");
|
||||||
|
} else if (weatherId == 761 || weatherId == 781) {
|
||||||
|
return context.getString(R.string.format_art_url, "storm");
|
||||||
|
} else if (weatherId == 800) {
|
||||||
|
return context.getString(R.string.format_art_url, "clear");
|
||||||
|
} else if (weatherId == 801) {
|
||||||
|
return context.getString(R.string.format_art_url, "light_clouds");
|
||||||
|
} else if (weatherId >= 802 && weatherId <= 804) {
|
||||||
|
return context.getString(R.string.format_art_url, "clouds");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to provide the art resource id according to the weather condition id returned
|
* Helper method to provide the art resource id according to the weather condition id returned
|
||||||
* by the OpenWeatherMap call.
|
* by the OpenWeatherMap call.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.example.android.sunshine.app.sync;
|
|||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.accounts.AccountManager;
|
import android.accounts.AccountManager;
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.AbstractThreadedSyncAdapter;
|
import android.content.AbstractThreadedSyncAdapter;
|
||||||
@@ -28,6 +29,7 @@ import android.support.v4.app.TaskStackBuilder;
|
|||||||
import android.text.format.Time;
|
import android.text.format.Time;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
import com.example.android.sunshine.app.MainActivity;
|
import com.example.android.sunshine.app.MainActivity;
|
||||||
import com.example.android.sunshine.app.R;
|
import com.example.android.sunshine.app.R;
|
||||||
import com.example.android.sunshine.app.Utility;
|
import com.example.android.sunshine.app.Utility;
|
||||||
@@ -46,6 +48,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
public class SunshineSyncAdapter extends AbstractThreadedSyncAdapter {
|
public class SunshineSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
public final String LOG_TAG = SunshineSyncAdapter.class.getSimpleName();
|
public final String LOG_TAG = SunshineSyncAdapter.class.getSimpleName();
|
||||||
@@ -377,8 +380,33 @@ public class SunshineSyncAdapter extends AbstractThreadedSyncAdapter {
|
|||||||
|
|
||||||
int iconId = Utility.getIconResourceForWeatherCondition(weatherId);
|
int iconId = Utility.getIconResourceForWeatherCondition(weatherId);
|
||||||
Resources resources = context.getResources();
|
Resources resources = context.getResources();
|
||||||
Bitmap largeIcon = BitmapFactory.decodeResource(resources,
|
int artResourceId = Utility.getArtResourceForWeatherCondition(weatherId);
|
||||||
Utility.getArtResourceForWeatherCondition(weatherId));
|
String artUrl = Utility.getArtUrlForWeatherCondition(context, weatherId);
|
||||||
|
|
||||||
|
// On Honeycomb and higher devices, we can retrieve the size of the large icon
|
||||||
|
// Prior to that, we use a fixed size
|
||||||
|
@SuppressLint("InlinedApi")
|
||||||
|
int largeIconWidth = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB
|
||||||
|
? resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_width)
|
||||||
|
: resources.getDimensionPixelSize(R.dimen.notification_large_icon_default);
|
||||||
|
@SuppressLint("InlinedApi")
|
||||||
|
int largeIconHeight = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB
|
||||||
|
? resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_height)
|
||||||
|
: resources.getDimensionPixelSize(R.dimen.notification_large_icon_default);
|
||||||
|
|
||||||
|
// Retrieve the large icon
|
||||||
|
Bitmap largeIcon;
|
||||||
|
try {
|
||||||
|
largeIcon = Glide.with(context)
|
||||||
|
.load(artUrl)
|
||||||
|
.asBitmap()
|
||||||
|
.error(artResourceId)
|
||||||
|
.fitCenter()
|
||||||
|
.into(largeIconWidth, largeIconHeight).get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
Log.e(LOG_TAG, "Error retrieving large icon from " + artUrl, e);
|
||||||
|
largeIcon = BitmapFactory.decodeResource(resources, artResourceId);
|
||||||
|
}
|
||||||
String title = context.getString(R.string.app_name);
|
String title = context.getString(R.string.app_name);
|
||||||
|
|
||||||
// Define the text of the forecast.
|
// Define the text of the forecast.
|
||||||
|
|||||||
@@ -83,7 +83,8 @@
|
|||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/detail_icon"
|
android:id="@+id/detail_icon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content"
|
||||||
|
android:adjustViewBounds="true" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/detail_forecast_textview"
|
android:id="@+id/detail_forecast_textview"
|
||||||
|
|||||||
@@ -111,7 +111,8 @@
|
|||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/detail_icon"
|
android:id="@+id/detail_icon"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content" />
|
android:layout_width="wrap_content"
|
||||||
|
android:adjustViewBounds="true" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:fontFamily="sans-serif-condensed"
|
android:fontFamily="sans-serif-condensed"
|
||||||
|
|||||||
@@ -31,7 +31,8 @@
|
|||||||
android:id="@+id/list_item_icon"
|
android:id="@+id/list_item_icon"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"
|
||||||
|
android:adjustViewBounds="true"/>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,8 @@
|
|||||||
android:id="@+id/list_item_icon"
|
android:id="@+id/list_item_icon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"/>
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:adjustViewBounds="true"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/list_item_forecast_textview"
|
android:id="@+id/list_item_forecast_textview"
|
||||||
|
|||||||
@@ -17,4 +17,6 @@
|
|||||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="notification_large_icon_default">48dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -81,6 +81,9 @@
|
|||||||
<string name="pref_units_imperial" translatable="false">imperial</string>
|
<string name="pref_units_imperial" translatable="false">imperial</string>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Format for retrieving art from an external source [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="format_art_url" translatable="false">https://raw.githubusercontent.com/udacity/Sunshine-Version-2/sunshine_master/app/src/main/res/drawable-xxhdpi/art_<xliff:g id="description">%s</xliff:g>.png</string>
|
||||||
|
|
||||||
<!-- Language-specific constants -->
|
<!-- Language-specific constants -->
|
||||||
<string name="today">Today</string>
|
<string name="today">Today</string>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user