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

Create weather app #67

Merged
merged 2 commits into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 25 additions & 0 deletions WeatherApp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Weather App
- An application provides user with the weather forecast of the current day.

### Technology Used
1. Android
2. Java
3. Gradle

### Requirements
1. Android Version 5.0 and above
2. CompileSdkVersion 31
3. MinSdkVersion 21
4. targetSdkVersion 31
5. Androidx

### Usage
- Step1: Type in the city you want to see the weather forecast.
- Step2: Click the search button.

### Resources
1. Images from [Pinterest](https://www.pinterest.com/)
2. Icons from [Flaticon](https://www.flaticon.com/)
3. API from [Open Weather Map](https://openweathermap.org/api)
4. [Android Developer](https://developer.android.com/)
5. [Stack Overflow](https://stackoverflow.com/)
15 changes: 15 additions & 0 deletions WeatherApp/Weather App/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
1 change: 1 addition & 0 deletions WeatherApp/Weather App/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
41 changes: 41 additions & 0 deletions WeatherApp/Weather App/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
plugins {
id 'com.android.application'
}

android {
compileSdk 31

defaultConfig {
applicationId "com.example.weatherapp"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

dependencies {

implementation 'com.android.volley:volley:1.2.1'
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
testImplementation 'junit:junit:'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
21 changes: 21 additions & 0 deletions WeatherApp/Weather App/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.example.weatherapp;

import android.content.Context;

import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.example.weatherapp", appContext.getPackageName());
}
}
24 changes: 24 additions & 0 deletions WeatherApp/Weather App/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.weatherapp">

<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.WeatherApp">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package com.example.weatherapp;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.Cache;
import com.android.volley.Network;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.BasicNetwork;
import com.android.volley.toolbox.DiskBasedCache;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.JsonObjectRequest;

import org.json.JSONException;
import org.json.JSONObject;

import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.TimeZone;

public class MainActivity extends AppCompatActivity {
String APIKEY_ = "c22541c8c24aef3809ab3e168f7b1d7e";

ImageButton search;
EditText city;
TextView location;
TextView temperature;
TextView displayWeather;
TextView currentDate;
TextView currentTime;
TextView feels;
ImageView background;
TextView humid;
TextView wind;
TextView sunRise;
TextView sunSet;

// uses this value to set back ground based on the current time
LocalTime myTime;

@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// sets views
city = (EditText) findViewById(R.id.searchLocation);
search = (ImageButton) findViewById(R.id.searchButton);
location = (TextView) findViewById(R.id.location);
temperature = (TextView) findViewById(R.id.temperature);
displayWeather = (TextView) findViewById(R.id.weather);
feels = (TextView) findViewById(R.id.feel);
background = (ImageView) findViewById(R.id.bg);
currentDate = (TextView) findViewById(R.id.currentDate);
currentTime = (TextView) findViewById(R.id.currentTime);
humid = (TextView) findViewById(R.id.humid);
wind = (TextView) findViewById(R.id.wind);
sunRise = (TextView) findViewById(R.id.dawn);
sunSet = (TextView) findViewById(R.id.dusk);

// gets current time
myTime = LocalTime.now();
setBackground(myTime.getHour(), background);

search.setOnClickListener(view -> {
// hides soft keyboard
hideSoftKeyboard(MainActivity.this);

// if user did not provide a city name, show toast to announce
if(city.getText().toString().equals("")){
Toast.makeText(getApplicationContext(), "Please provide a city name!!!", Toast.LENGTH_SHORT).show();
} else {
// calls function requesting API
getData(city.getText().toString());
city.setText(""); // resets value of edit text
}
});
}

@RequiresApi(api = Build.VERSION_CODES.O)
private void getData(String city) {
String apiUrl = "https://api.openweathermap.org/data/2.5/weather?q=" + city + "&appid=" + APIKEY_;
// creates request queue
RequestQueue mRequestQueue;
// instantiates the cache
Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024);
// setups the network to use the HTTPURLConnection client
Network network = new BasicNetwork(new HurlStack());
// instantiates the request queue
mRequestQueue = new RequestQueue(cache, network);
// starts the queue
mRequestQueue.start();

@SuppressLint("SetTextI18n") JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.GET, apiUrl, null, response -> {
try {
// gets JSON objects
JSONObject mainWeather = response.getJSONObject("main");
JSONObject weather = response.getJSONArray("weather").getJSONObject(0);
JSONObject windInfo = response.getJSONObject("wind");
JSONObject sunInfo = response.getJSONObject("sys");

// converts unix time to date
Date dateInfo = new Date(response.getLong("dt")*1000);
Date sunRiseD = new Date(sunInfo.getLong("sunrise") * 1000);
Date sunSetD = new Date(sunInfo.getLong("sunset") * 1000);
int timezone = response.getInt("timezone");

// formats output
@SuppressLint("SimpleDateFormat") SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, dd MMM yyyy");
dateFormat.setTimeZone(TimeZone.getTimeZone(ZoneOffset.ofTotalSeconds(timezone)));
@SuppressLint("SimpleDateFormat") SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm a");
timeFormat.setTimeZone(TimeZone.getTimeZone(ZoneOffset.ofTotalSeconds(timezone)));

String dateStr = dateFormat.format(dateInfo);
String timeStr = timeFormat.format(dateInfo);
String sunRiseStr = timeFormat.format(sunRiseD);
String sunSetStr = timeFormat.format(sunSetD);

// converts °K to °C
int tempC = (int) (Math.round(mainWeather.getDouble("temp") - 273.15));
int feelTemp = (int)(Math.round(mainWeather.getDouble("feels_like") - 273.15));

// gets weather information
int humidity = mainWeather.getInt("humidity");
double windSpeed = windInfo.getDouble("speed");

// sets content for xml views
setBackground(Integer.parseInt(timeStr.substring(0,2)), background);
currentDate.setText(dateStr);
currentTime.setText(timeStr);
temperature.setText(tempC + "°");
location.setText(city.toUpperCase());
displayWeather.setText(weather.getString("main"));
feels.setText("Feels like: " + feelTemp + "°C");
humid.setText(humidity + "%");
wind.setText(windSpeed + "m/s");
sunRise.setText(sunRiseStr);
sunSet.setText(sunSetStr);

} catch (JSONException e) {
e.printStackTrace();
}
},
error -> {
error.printStackTrace();
// displays error
Toast.makeText(getApplicationContext(), "Invalid city!!!", Toast.LENGTH_SHORT).show();
VolleyLog.e("Error: ", error.toString());
VolleyLog.e("Error: ", error.getLocalizedMessage());
});

// Add the request to the RequestQueue
mRequestQueue.add(jsObjRequest);
}

// gets time and changes img src based on time
@SuppressLint("UseCompatLoadingForDrawables")
void setBackground(int hour, ImageView imgV){
Drawable src = getDrawable(R.drawable.night_);
displayWeather.setTextColor(Color.parseColor("#ffffff"));

if(hour >= 4 && hour < 7 ) {
src = getDrawable(R.drawable.dawn_);
displayWeather.setTextColor(Color.parseColor("#000000"));
} else if(hour >=7 && hour < 16){
src = getDrawable(R.drawable.day_);
} else if(hour >= 16 && hour < 19 ){
src = getDrawable(R.drawable.dusk_);
displayWeather.setTextColor(Color.parseColor("#000000"));
}
imgV.setBackground(src);
}

// hides soft keyboard when search btn is clicked
public static void hideSoftKeyboard(Activity activity) {
InputMethodManager inputMethodManager =
(InputMethodManager) activity.getSystemService(
Activity.INPUT_METHOD_SERVICE);
if(inputMethodManager.isAcceptingText()){
inputMethodManager.hideSoftInputFromWindow(
activity.getCurrentFocus().getWindowToken(),
0
);
}
}
}






Loading