From d037e72bf8d369a4284e237456af46ec00005aa6 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Mon, 10 Nov 2014 17:04:32 +0000 Subject: [PATCH] Finished lesson 4 --- .../uk/me/njae/sunshine/DetailActivity.java | 182 ++++++++++++++---- .../uk/me/njae/sunshine/ForecastFragment.java | 49 ++++- .../uk/me/njae/sunshine/SettingsActivity.java | 22 +++ .../java/uk/me/njae/sunshine/Utility.java | 3 - app/src/main/res/layout/fragment_detail.xml | 59 ++++-- 5 files changed, 253 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/uk/me/njae/sunshine/DetailActivity.java b/app/src/main/java/uk/me/njae/sunshine/DetailActivity.java index 8303134..0614eb1 100644 --- a/app/src/main/java/uk/me/njae/sunshine/DetailActivity.java +++ b/app/src/main/java/uk/me/njae/sunshine/DetailActivity.java @@ -1,11 +1,13 @@ 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.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.ShareActionProvider; @@ -18,8 +20,8 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; +import uk.me.njae.sunshine.data.WeatherContract; +import uk.me.njae.sunshine.data.WeatherContract.WeatherEntry; // import android.widget.ShareActionProvider; @@ -28,6 +30,9 @@ public class DetailActivity extends ActionBarActivity { private final String LOG_TAG = DetailActivity.class.getSimpleName(); private ShareActionProvider mShareActionProvider; + public static final String DATE_KEY = "forecast_date"; + private static final String LOCATION_KEY = "location"; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -69,28 +74,52 @@ public class DetailActivity extends ActionBarActivity { /** * A placeholder fragment containing a simple view. */ - public static class DetailFragment extends Fragment { + public static class DetailFragment extends Fragment implements LoaderManager.LoaderCallbacks { private static final String LOG_TAG = DetailFragment.class.getSimpleName(); private static final String FORECAST_SHARE_HASHTAG = " #SunshineApp"; - private String mForecastStr; + + public static final String DATE_KEY = "forecast_date"; + + private ShareActionProvider mShareActionProvider; + private String mLocation; + private String mForecast; + + private static final int DETAIL_LOADER = 0; + + private static final String[] FORECAST_COLUMNS = { + WeatherEntry.TABLE_NAME + "." + WeatherEntry._ID, + WeatherEntry.COLUMN_DATETEXT, + WeatherEntry.COLUMN_SHORT_DESC, + WeatherEntry.COLUMN_MAX_TEMP, + WeatherEntry.COLUMN_MIN_TEMP, + }; public DetailFragment() { setHasOptionsMenu(true); } + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putString(LOCATION_KEY, mLocation); + super.onSaveInstanceState(outState); + } + + @Override + public void onResume() { + super.onResume(); + if (mLocation != null && + !mLocation.equals(Utility.getPreferredLocation(getActivity()))) { + getLoaderManager().restartLoader(DETAIL_LOADER, null, this); + } + } + + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Intent intent = getActivity().getIntent(); - View rootView = inflater.inflate(R.layout.fragment_detail, container, false); - if (intent != null && intent.hasExtra(Intent.EXTRA_TEXT)) { - mForecastStr = intent.getStringExtra(Intent.EXTRA_TEXT); - ((TextView) rootView.findViewById(R.id.detail_text)) - .setText(mForecastStr); - } - return rootView; + return inflater.inflate(R.layout.fragment_detail, container, false); } @Override @@ -118,35 +147,114 @@ public class DetailActivity extends ActionBarActivity { Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); shareIntent.setType("text/plain"); - shareIntent.putExtra(Intent.EXTRA_TEXT, - mForecastStr + FORECAST_SHARE_HASHTAG); + shareIntent.putExtra(Intent.EXTRA_TEXT, mForecast + FORECAST_SHARE_HASHTAG); return shareIntent; } + @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - if (id == R.id.action_show_location) { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); - String location = preferences.getString(getString(R.string.pref_location_key), - getString(R.string.pref_location_default)); - Intent intent = new Intent(Intent.ACTION_VIEW); - Uri geoLocation; - try { - geoLocation = Uri.parse("geo:0,0?q=" + URLEncoder.encode(location, "UTF-8")); - intent.setData(geoLocation); - } catch (UnsupportedEncodingException e) { - Log.e(LOG_TAG, "Error ", e); - } - if (intent.resolveActivity(getActivity().getPackageManager()) != null) { - startActivity(intent); - } + public void onActivityCreated(Bundle savedInstanceState) { + getLoaderManager().initLoader(DETAIL_LOADER, null, this); + if (savedInstanceState != null) { + mLocation = savedInstanceState.getString(LOCATION_KEY); + } + super.onActivityCreated(savedInstanceState); + } + @Override + public Loader onCreateLoader(int id, Bundle args) { + Log.v(LOG_TAG, "In onCreateLoader"); + Intent intent = getActivity().getIntent(); + if (intent == null || !intent.hasExtra(DATE_KEY)) { + return null; + } + String forecastDate = intent.getStringExtra(DATE_KEY); + + // Sort order: Ascending, by date. + String sortOrder = WeatherContract.WeatherEntry.COLUMN_DATETEXT + " ASC"; + + mLocation = Utility.getPreferredLocation(getActivity()); + Uri weatherForLocationUri = WeatherContract.WeatherEntry.buildWeatherLocationWithDate( + mLocation, forecastDate); + Log.v(LOG_TAG, weatherForLocationUri.toString()); + + // 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) { + Log.v(LOG_TAG, "In onLoadFinished"); + if (!data.moveToFirst()) { return; } + + String dateString = Utility.formatDate( + data.getString(data.getColumnIndex(WeatherEntry.COLUMN_DATETEXT))); + ((TextView) getView().findViewById(R.id.detail_date_textview)) + .setText(dateString); + + String weatherDescription = + data.getString(data.getColumnIndex(WeatherEntry.COLUMN_SHORT_DESC)); + ((TextView) getView().findViewById(R.id.detail_forecast_textview)) + .setText(weatherDescription); + + boolean isMetric = Utility.isMetric(getActivity()); + + String high = Utility.formatTemperature( + data.getDouble(data.getColumnIndex(WeatherEntry.COLUMN_MAX_TEMP)), isMetric); + ((TextView) getView().findViewById(R.id.detail_high_textview)).setText(high); + + String low = Utility.formatTemperature( + data.getDouble(data.getColumnIndex(WeatherEntry.COLUMN_MIN_TEMP)), isMetric); + ((TextView) getView().findViewById(R.id.detail_low_textview)).setText(low); + + // We still need this for the share intent + mForecast = String.format("%s - %s - %s/%s", dateString, weatherDescription, high, low); + + Log.v(LOG_TAG, "Forecast String: " + mForecast); + + // If onCreateOptionsMenu has already happened, we need to update the share intent now. + if (mShareActionProvider != null) { + mShareActionProvider.setShareIntent(createShareForecastIntent()); } - return super.onOptionsItemSelected(item); } + + @Override + public void onLoaderReset(Loader loader) { } + + + +// @Override +// public boolean onOptionsItemSelected(MenuItem item) { +// // Handle action bar item clicks here. The action bar will +// // automatically handle clicks on the Home/Up button, so long +// // as you specify a parent activity in AndroidManifest.xml. +// int id = item.getItemId(); +// if (id == R.id.action_show_location) { +// SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); +// String location = preferences.getString(getString(R.string.pref_location_key), +// getString(R.string.pref_location_default)); +// Intent intent = new Intent(Intent.ACTION_VIEW); +// Uri geoLocation; +// try { +// geoLocation = Uri.parse("geo:0,0?q=" + URLEncoder.encode(location, "UTF-8")); +// intent.setData(geoLocation); +// } catch (UnsupportedEncodingException e) { +// Log.e(LOG_TAG, "Error ", e); +// } +// if (intent.resolveActivity(getActivity().getPackageManager()) != null) { +// startActivity(intent); +// } +// +// } +// return super.onOptionsItemSelected(item); +// } } } 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 d78c705..8b67a06 100644 --- a/app/src/main/java/uk/me/njae/sunshine/ForecastFragment.java +++ b/app/src/main/java/uk/me/njae/sunshine/ForecastFragment.java @@ -11,7 +11,6 @@ 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.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -20,6 +19,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ListView; +import android.widget.TextView; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; @@ -29,6 +29,8 @@ 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. */ @@ -102,7 +104,7 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa 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); @@ -147,27 +149,56 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa 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, "placeholder"); - 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 diff --git a/app/src/main/java/uk/me/njae/sunshine/SettingsActivity.java b/app/src/main/java/uk/me/njae/sunshine/SettingsActivity.java index 4fe29fb..9078058 100644 --- a/app/src/main/java/uk/me/njae/sunshine/SettingsActivity.java +++ b/app/src/main/java/uk/me/njae/sunshine/SettingsActivity.java @@ -6,6 +6,8 @@ import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceManager; +import uk.me.njae.sunshine.data.WeatherContract; + /** * A {@link PreferenceActivity} that presents a set of application settings. *

@@ -17,6 +19,10 @@ import android.preference.PreferenceManager; public class SettingsActivity extends PreferenceActivity implements Preference.OnPreferenceChangeListener { + // since we use the preference change initially to populate the summary + // field, we'll ignore that change at start of the activity + boolean mBindingPreference; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -36,6 +42,8 @@ public class SettingsActivity extends PreferenceActivity * is changed.) */ private void bindPreferenceSummaryToValue(Preference preference) { + mBindingPreference = true; + // Set the listener to watch for value changes. preference.setOnPreferenceChangeListener(this); @@ -45,12 +53,26 @@ public class SettingsActivity extends PreferenceActivity PreferenceManager .getDefaultSharedPreferences(preference.getContext()) .getString(preference.getKey(), "")); + + mBindingPreference = false; } @Override public boolean onPreferenceChange(Preference preference, Object value) { String stringValue = value.toString().trim(); + // are we starting the preference activity? + if ( !mBindingPreference ) { + if (preference.getKey().equals(getString(R.string.pref_location_key))) { + FetchWeatherTask weatherTask = new FetchWeatherTask(this); + String location = value.toString(); + weatherTask.execute(location); + } else { + // notify code that weather may be impacted + getContentResolver().notifyChange(WeatherContract.WeatherEntry.CONTENT_URI, null); + } + } + if (preference instanceof ListPreference) { // For list preferences, look up the correct display value in // the preference's 'entries' list (since they have separate labels/values). diff --git a/app/src/main/java/uk/me/njae/sunshine/Utility.java b/app/src/main/java/uk/me/njae/sunshine/Utility.java index 64ddc0a..04f2fde 100644 --- a/app/src/main/java/uk/me/njae/sunshine/Utility.java +++ b/app/src/main/java/uk/me/njae/sunshine/Utility.java @@ -18,7 +18,6 @@ package uk.me.njae.sunshine; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import android.util.Log; import java.text.DateFormat; import java.util.Date; @@ -36,8 +35,6 @@ public class Utility { public static boolean isMetric(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - Log.v(LOG_TAG, "Units set to " + prefs.getString(context.getString(R.string.pref_units_key), - context.getString(R.string.pref_units_metric))); return prefs.getString(context.getString(R.string.pref_units_key), context.getString(R.string.pref_units_metric)) .equals(context.getString(R.string.pref_units_metric)); diff --git a/app/src/main/res/layout/fragment_detail.xml b/app/src/main/res/layout/fragment_detail.xml index 4b4625a..f61a522 100644 --- a/app/src/main/res/layout/fragment_detail.xml +++ b/app/src/main/res/layout/fragment_detail.xml @@ -1,16 +1,49 @@ - + + - - + + + + + + + + + + + + + + + android:layout_height="match_parent" + android:id="@+id/detail_low_textview" /> + + + + + - -- 2.34.1