Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Playground #206

Open
wants to merge 27 commits into
base: student
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bed7256
Change constraint to a frame layout and add a ScrollView around the T…
Sargarepa Jan 17, 2019
1ed3d20
Add weather list
Sargarepa Jan 17, 2019
32d5b4c
Create AsyncTask to perform network requests
Sargarepa Jan 24, 2019
3b6562c
Add menu and refresh button
Sargarepa Jan 29, 2019
f8e9b0f
Add loading polish
Sargarepa Jan 30, 2019
5f4df17
Add recyclerview and wire it up
Sargarepa Feb 6, 2019
895f03c
Add click handling to recyclerview
Sargarepa Feb 7, 2019
c096ba4
Add detail activity and up button functionality
Sargarepa May 20, 2019
7c2579d
Send string and populate detail activity textview with it
Sargarepa May 20, 2019
a70c168
Add location menu item to Main Activity and share menu item to Detail…
Sargarepa May 20, 2019
674f558
Replace FetchWeatherTask with AsyncTaskLoader
Sargarepa May 24, 2019
a26a28d
Add settings activity and navigation to it
Sargarepa May 29, 2019
f602afe
Populate settings fragment
Sargarepa May 29, 2019
6866dc0
Make values in MainActivity update based on preferences
Sargarepa May 29, 2019
8fd5881
Add Contract and DbHelper class for weather data
Sargarepa Jun 4, 2019
a5c5475
Change database schema to not accept NULL values for certain Columns …
Sargarepa Jun 4, 2019
4d0dc69
Add a UNIQUE constraint on the date column to replace on conflict
Sargarepa Jun 4, 2019
84b91ff
Make uriMatcher and define query method in WeatherContentProvider class
Sargarepa Jun 26, 2019
80f2080
Define bulkInsert method in WeatherContentProvider for inserting mult…
Sargarepa Jun 26, 2019
381deaf
Define delete method in WeatherContentProvider class for deleting all…
Sargarepa Jun 26, 2019
6c74bab
Replace AsyncTaskLoader with CursorLoader and modify RecyclerViewAdap…
Sargarepa Jun 27, 2019
bbdb817
Display additional data in DetailsActivity using CursorLoader
Sargarepa Jun 27, 2019
f04c29e
Create class for weather syncing and an IntentService class which exe…
Sargarepa Jul 22, 2019
db31d8f
Optimize the synchronization process by calling it only once when the…
Sargarepa Jul 23, 2019
897b064
Add a FirebaseJobDispatcher service to sync weather data in the backg…
Sargarepa Jul 23, 2019
4d28360
Notify the user about the weather daily with a notification
Sargarepa Jul 23, 2019
c22b7f9
Make UI prettier :) and acommodate ForecastAdapter for changes made i…
Sargarepa Jul 29, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions S01.01-Exercise-CreateLayout/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ android {
defaultConfig {
applicationId "com.example.android.sunshine"
minSdkVersion 14
targetSdkVersion 25
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
Expand All @@ -22,9 +22,6 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'

// TODO (10) Remove this dependency as we won't be needing it for the project until later
implementation 'com.android.support.constraint:constraint-layout:1.1.3'

// Instrumentation dependencies use androidTestImplementation
// (as opposed to testImplementation for local unit tests run in the JVM)
androidTestImplementation 'junit:junit:4.12'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,20 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--TODO (1) Change the ConstraintLayout to a FrameLayout-->
<!--TODO (7) Remove the line that declares the id, we don't need it-->
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">

<!--TODO (8) Wrap the TextView in a ScrollView-->
<!--TODO (9) Set the ScrollView width to match_parent and the height to wrap_content-->
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_weather_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:textSize="20sp"/>
</ScrollView>

<!--TODO (2) Change the TextView's android:id attribute to tv_weather_data-->
<!--TODO (3) Give the TextView 16dp of padding-->
<!--TODO (4) Set the text size to 20sp-->
<!--TODO (5) Remove all attributes with the word constraint in them-->
<!--TODO (6) Remove the default text from the TextView-->
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="@+id/activity_main"
app:layout_constraintLeft_toLeftOf="@+id/activity_main"
app:layout_constraintRight_toRightOf="@+id/activity_main"
app:layout_constraintTop_toTopOf="@+id/activity_main" />
</android.support.constraint.ConstraintLayout>
</FrameLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,36 @@

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
import com.example.android.sunshine.utilities.SunshineWeatherUtils;

// TODO (1) Create a field to store the weather display TextView
public class MainActivity extends AppCompatActivity {

TextView weatherDisplay;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_forecast);

// TODO (2) Use findViewById to get a reference to the weather display TextView

// TODO (3) Create an array of Strings that contain fake weather data

// TODO (4) Append each String from the fake weather data array to the TextView
weatherDisplay = (TextView) findViewById(R.id.tv_weather_data);
String[] dummyWeatherData = {
"Today, May 17 - Clear - 17°C / 15°C",
"Tomorrow - Cloudy - 19°C / 15°C",
"Thursday - Rainy- 30°C / 11°C",
"Friday - Thunderstorms - 21°C / 9°C",
"Saturday - Thunderstorms - 16°C / 7°C",
"Sunday - Rainy - 16°C / 8°C",
"Monday - Partly Cloudy - 15°C / 10°C",
"Tue, May 24 - Meatballs - 16°C / 18°C",
"Wed, May 25 - Cloudy - 19°C / 15°C",
"Thu, May 26 - Stormy - 30°C / 11°C",
"Fri, May 27 - Hurricane - 21°C / 9°C",
"Sat, May 28 - Meteors - 16°C / 7°C",
"Sun, May 29 - Apocalypse - 16°C / 8°C",
"Mon, May 30 - Post Apocalypse - 15°C / 10°C",
};
for (String data : dummyWeatherData) {
weatherDisplay.append(data + "\n\n\n");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.sunshine">

<!--TODO (2) Add the INTERNET permission-->
<uses-permission android:name="android.permission.INTERNET"/>

<application
android:allowBackup="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@
*/
package com.example.android.sunshine;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.example.android.sunshine.data.SunshinePreferences;
import com.example.android.sunshine.utilities.NetworkUtils;

import java.io.IOException;
import java.net.URL;

public class MainActivity extends AppCompatActivity {

private TextView mWeatherTextView;
Expand All @@ -34,45 +41,42 @@ protected void onCreate(Bundle savedInstanceState) {
*/
mWeatherTextView = (TextView) findViewById(R.id.tv_weather_data);

// TODO (4) Delete the dummy weather data. You will be getting REAL data from the Internet in this lesson.
/*
* This String array contains dummy weather data. Later in the course, we're going to get
* real weather data. For now, we want to get something on the screen as quickly as
* possible, so we'll display this dummy data.
*/
String[] dummyWeatherData = {
"Today, May 17 - Clear - 17°C / 15°C",
"Tomorrow - Cloudy - 19°C / 15°C",
"Thursday - Rainy- 30°C / 11°C",
"Friday - Thunderstorms - 21°C / 9°C",
"Saturday - Thunderstorms - 16°C / 7°C",
"Sunday - Rainy - 16°C / 8°C",
"Monday - Partly Cloudy - 15°C / 10°C",
"Tue, May 24 - Meatballs - 16°C / 18°C",
"Wed, May 25 - Cloudy - 19°C / 15°C",
"Thu, May 26 - Stormy - 30°C / 11°C",
"Fri, May 27 - Hurricane - 21°C / 9°C",
"Sat, May 28 - Meteors - 16°C / 7°C",
"Sun, May 29 - Apocalypse - 16°C / 8°C",
"Mon, May 30 - Post Apocalypse - 15°C / 10°C",
};

// TODO (3) Delete the for loop that populates the TextView with dummy data
/*
* Iterate through the array and append the Strings to the TextView. The reason why we add
* the "\n\n\n" after the String is to give visual separation between each String in the
* TextView. Later, we'll learn about a better way to display lists of data.
*/
for (String dummyWeatherDay : dummyWeatherData) {
mWeatherTextView.append(dummyWeatherDay + "\n\n\n");
}

// TODO (9) Call loadWeatherData to perform the network request to get the weather
loadWeatherData();
}

// TODO (8) Create a method that will get the user's preferred location and execute your new AsyncTask and call it loadWeatherData
public void loadWeatherData() {
new FetchWeatherTask().execute(NetworkUtils.buildUrl(SunshinePreferences.getPreferredWeatherLocation(this)));
}
public class FetchWeatherTask extends AsyncTask<URL, Void, String> {
@Override
protected String doInBackground(URL... urls) {
URL searchURL = urls[0];
String weatherDataSearchResults = null;
try {
weatherDataSearchResults = NetworkUtils.getResponseFromHttpUrl(searchURL);
} catch (IOException e) {
e.printStackTrace();
}
return weatherDataSearchResults;
}

// TODO (5) Create a class that extends AsyncTask to perform network requests
// TODO (6) Override the doInBackground method to perform your network requests
// TODO (7) Override the onPostExecute method to display the results of the network request
@Override
protected void onPostExecute(String weatherDataSearchResults) {
if (weatherDataSearchResults != null && !weatherDataSearchResults.equals("")) {
mWeatherTextView.setText(weatherDataSearchResults);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
*/
package com.example.android.sunshine.utilities;

import android.net.Uri;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Scanner;

Expand Down Expand Up @@ -65,8 +68,20 @@ public final class NetworkUtils {
* @return The URL to use to query the weather server.
*/
public static URL buildUrl(String locationQuery) {
// TODO (1) Fix this method to return the URL used to query Open Weather Map's API
return null;
Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, locationQuery)
.appendQueryParameter(UNITS_PARAM, units)
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(DAYS_PARAM, String.valueOf(numDays))
.build();

URL url = null;
try {
url = new URL(builtUri.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
}
return url;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

import com.example.android.sunshine.data.SunshinePreferences;
Expand Down Expand Up @@ -97,12 +99,21 @@ protected void onPostExecute(String[] weatherData) {
}
}

// TODO (2) Create a menu resource in res/menu/ called forecast.xml
// TODO (3) Add one item to the menu with an ID of action_refresh
// TODO (4) Set the title of the menu item to "Refresh" using strings.xml

// TODO (5) Override onCreateOptionsMenu to inflate the menu for this Activity
// TODO (6) Return true to display the menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.forecast, menu);
return true;
}


// TODO (7) Override onOptionsItemSelected to handle clicks on the refresh button
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int menuItemThatWasSelected = item.getItemId();
if (menuItemThatWasSelected == R.id.action_refresh) {
mWeatherTextView.setText("");
loadWeatherData();
}
return super.onOptionsItemSelected(item);
}
}
10 changes: 10 additions & 0 deletions S02.02-Exercise-Menus/app/src/main/res/menu/forecast.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:title="@string/action_refresh"
android:id="@+id/action_refresh"
android:orderInCategory="1"
app:showAsAction="ifRoom"
/>
</menu>
3 changes: 1 addition & 2 deletions S02.02-Exercise-Menus/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@
<!--or something similar.-->
<string name="app_name">Sunshine</string>

<!--TODO (1) Add a string for the title of the refresh button, "Refresh"-->

<string name="action_refresh">Refresh</string>

<!-- - - - - - - - - - - - - -->
<!--Used by SunshineDateUtils-->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.example.android.sunshine.data.SunshinePreferences;
Expand All @@ -33,10 +35,8 @@ public class MainActivity extends AppCompatActivity {

private TextView mWeatherTextView;

// TODO (6) Add a TextView variable for the error message display

// TODO (16) Add a ProgressBar variable to show and hide the progress bar

private TextView mErrorMessageDisplay;
private ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand All @@ -48,10 +48,8 @@ protected void onCreate(Bundle savedInstanceState) {
*/
mWeatherTextView = (TextView) findViewById(R.id.tv_weather_data);

// TODO (7) Find the TextView for the error message using findViewById

// TODO (17) Find the ProgressBar using findViewById

mErrorMessageDisplay = (TextView) findViewById(R.id.tv_error_message);
mProgressBar = (ProgressBar) findViewById(R.id.pb_loading_data);
/* Once all of our views are setup, we can load the weather data. */
loadWeatherData();
}
Expand All @@ -61,18 +59,27 @@ protected void onCreate(Bundle savedInstanceState) {
* background method to get the weather data in the background.
*/
private void loadWeatherData() {
// TODO (20) Call showWeatherDataView before executing the AsyncTask
showWeatherDataView();
String location = SunshinePreferences.getPreferredWeatherLocation(this);
new FetchWeatherTask().execute(location);
}

// TODO (8) Create a method called showWeatherDataView that will hide the error message and show the weather data
private void showWeatherDataView() {
mErrorMessageDisplay.setVisibility(View.INVISIBLE);
mWeatherTextView.setVisibility(View.VISIBLE);
}
private void showErrorMessage() {
mErrorMessageDisplay.setVisibility(View.VISIBLE);
mWeatherTextView.setVisibility(View.INVISIBLE);
}
public class FetchWeatherTask extends AsyncTask<String, Void, String[]> {

// TODO (9) Create a method called showErrorMessage that will hide the weather data and show the error message

public class FetchWeatherTask extends AsyncTask<String, Void, String[]> {

// TODO (18) Within your AsyncTask, override the method onPreExecute and show the loading indicator
@Override
protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE);
}

@Override
protected String[] doInBackground(String... params) {
Expand Down Expand Up @@ -102,10 +109,9 @@ protected String[] doInBackground(String... params) {

@Override
protected void onPostExecute(String[] weatherData) {
// TODO (19) As soon as the data is finished loading, hide the loading indicator

mProgressBar.setVisibility(View.INVISIBLE);
if (weatherData != null) {
// TODO (11) If the weather data was not null, make sure the data view is visible
showWeatherDataView();
/*
* Iterate through the array and append the Strings to the TextView. The reason why we add
* the "\n\n\n" after the String is to give visual separation between each String in the
Expand All @@ -114,8 +120,9 @@ protected void onPostExecute(String[] weatherData) {
for (String weatherString : weatherData) {
mWeatherTextView.append((weatherString) + "\n\n\n");
}
} else {
showErrorMessage();
}
// TODO (10) If the weather data was null, show the error message

}
}
Expand Down
Loading