X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fuk%2Fme%2Fnjae%2Fsunshine%2FForecastFragment.java;h=8b67a06f53b7dd5bcb0c5ea0fed9803c81f5018e;hb=HEAD;hp=9dafe147f712cb1f6b5e9af4fca26e5ee6070486;hpb=10265f8b4d2e1cb0f74f50ac7700aacad6bd2255;p=Sunshine.git diff --git a/app/src/main/java/uk/me/njae/sunshine/ForecastFragment.java b/app/src/main/java/uk/me/njae/sunshine/ForecastFragment.java index 9dafe14..8b67a06 100644 --- a/app/src/main/java/uk/me/njae/sunshine/ForecastFragment.java +++ b/app/src/main/java/uk/me/njae/sunshine/ForecastFragment.java @@ -2,11 +2,15 @@ package uk.me.njae.sunshine; import android.content.Intent; import android.content.SharedPreferences; +import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; -import android.util.Log; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v4.widget.SimpleCursorAdapter; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -14,21 +18,56 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.ListView; +import android.widget.TextView; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.ArrayList; +import java.util.Date; + +import uk.me.njae.sunshine.data.WeatherContract; +import uk.me.njae.sunshine.data.WeatherContract.LocationEntry; +import uk.me.njae.sunshine.data.WeatherContract.WeatherEntry; + +import static android.util.Log.e; /** * A placeholder fragment containing a simple view. */ -public class ForecastFragment extends Fragment { +public class ForecastFragment extends Fragment implements LoaderManager.LoaderCallbacks { private final String LOG_TAG = ForecastFragment.class.getSimpleName(); - private ArrayAdapter mForecastAdapter; + private SimpleCursorAdapter mForecastAdapter; + + private static final int FORECAST_LOADER = 0; + private String mLocation; + + // For the forecast view we're showing only a small subset of the stored data. + // Specify the columns we need. + private static final String[] FORECAST_COLUMNS = { + // In this case the id needs to be fully qualified with a table name, since + // the content provider joins the location & weather tables in the background + // (both have an _id column) + // On the one hand, that's annoying. On the other, you can search the weather table + // using the location set by the user, which is only in the Location table. + // So the convenience is worth it. + WeatherEntry.TABLE_NAME + "." + WeatherEntry._ID, + WeatherEntry.COLUMN_DATETEXT, + WeatherEntry.COLUMN_SHORT_DESC, + WeatherEntry.COLUMN_MAX_TEMP, + WeatherEntry.COLUMN_MIN_TEMP, + LocationEntry.COLUMN_LOCATION_SETTING + }; + + // These indices are tied to FORECAST_COLUMNS. If FORECAST_COLUMNS changes, these + // must change. + public static final int COL_WEATHER_ID = 0; + public static final int COL_WEATHER_DATE = 1; + public static final int COL_WEATHER_DESC = 2; + public static final int COL_WEATHER_MAX_TEMP = 3; + public static final int COL_WEATHER_MIN_TEMP = 4; + public static final int COL_LOCATION_SETTING = 5; public ForecastFragment() { } @@ -65,7 +104,7 @@ public class ForecastFragment extends Fragment { geoLocation = Uri.parse("geo:0,0?q=" + URLEncoder.encode(location, "UTF-8")); intent.setData(geoLocation); } catch (UnsupportedEncodingException e) { - Log.e(LOG_TAG, "Error ", e); + e(LOG_TAG, "Error ", e); } if (intent.resolveActivity(getActivity().getPackageManager()) != null) { startActivity(intent); @@ -75,44 +114,129 @@ public class ForecastFragment extends Fragment { return super.onOptionsItemSelected(item); } + @Override + public void onActivityCreated(Bundle savedInstanceState) { + getLoaderManager().initLoader(FORECAST_LOADER, null, this); + super.onActivityCreated(savedInstanceState); + } + private void updateWeather() { String location = Utility.getPreferredLocation(getActivity()); - new FetchWeatherTask(getActivity(), mForecastAdapter).execute(location); + new FetchWeatherTask(getActivity()).execute(location); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - mForecastAdapter = new ArrayAdapter( + // The SimpleCursorAdapter will take data from the database through the + // Loader and use it to populate the ListView it's attached to. + mForecastAdapter = new SimpleCursorAdapter( getActivity(), R.layout.list_item_forecast, - R.id.list_item_forecast_textview, - new ArrayList() // weekForecast + null, + // the column names to use to fill the textviews + new String[]{WeatherContract.WeatherEntry.COLUMN_DATETEXT, + WeatherContract.WeatherEntry.COLUMN_SHORT_DESC, + WeatherContract.WeatherEntry.COLUMN_MAX_TEMP, + WeatherContract.WeatherEntry.COLUMN_MIN_TEMP + }, + // the textviews to fill with the data pulled from the columns above + new int[]{R.id.list_item_date_textview, + R.id.list_item_forecast_textview, + R.id.list_item_high_textview, + R.id.list_item_low_textview + }, + 0 ); + mForecastAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() { + @Override + public boolean setViewValue(View view, Cursor cursor, int columnIndex) { + boolean isMetric = Utility.isMetric(getActivity()); + switch (columnIndex) { + case COL_WEATHER_MAX_TEMP: + case COL_WEATHER_MIN_TEMP: { + // we have to do some formatting and possibly a conversion + ((TextView) view).setText(Utility.formatTemperature( + cursor.getDouble(columnIndex), isMetric)); + return true; + } + case COL_WEATHER_DATE: { + String dateString = cursor.getString(columnIndex); + TextView dateView = (TextView) view; + dateView.setText(Utility.formatDate(dateString)); + return true; + } + } + return false; + } + }); + View rootView = inflater.inflate(R.layout.fragment_main, container, false); ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast); listView.setAdapter(mForecastAdapter); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView adapterView, View view, int position, long l) { - String forecast = mForecastAdapter.getItem(position); - Intent intent = new Intent(getActivity(), DetailActivity.class) - .putExtra(Intent.EXTRA_TEXT, forecast); - startActivity(intent); + Cursor cursor = mForecastAdapter.getCursor(); + if (cursor != null && cursor.moveToPosition(position)) { + Intent intent = new Intent(getActivity(), DetailActivity.class) + .putExtra(DetailActivity.DATE_KEY, cursor.getString(COL_WEATHER_DATE)); + startActivity(intent); + } } }); return rootView; } - public void onStart() { - super.onStart(); - updateWeather(); + @Override + public void onResume() { + super.onResume(); + if (mLocation != null && !mLocation.equals(Utility.getPreferredLocation(getActivity()))) { + getLoaderManager().restartLoader(FORECAST_LOADER, null, this); + } } + @Override + public Loader onCreateLoader(int id, Bundle args) { + // This is called when a new Loader needs to be created. This + // fragment only uses one loader, so we don't care about checking the id. + + // To only show current and future dates, get the String representation for today, + // and filter the query to return weather only for dates after or including today. + // Only return data after today. + String startDate = WeatherContract.getDbDateString(new Date()); + + // Sort order: Ascending, by date. + String sortOrder = WeatherEntry.COLUMN_DATETEXT + " ASC"; + + mLocation = Utility.getPreferredLocation(getActivity()); + Uri weatherForLocationUri = WeatherEntry.buildWeatherLocationWithStartDate( + mLocation, startDate); + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader( + getActivity(), + weatherForLocationUri, + FORECAST_COLUMNS, + null, + null, + sortOrder + ); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + mForecastAdapter.swapCursor(data); + } + + @Override + public void onLoaderReset(Loader loader) { + mForecastAdapter.swapCursor(null); + } }