diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..4c96378b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+/src/main/res/raw/config.properties
+
+*.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
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000..0e40fe8f
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+
+# Default ignored files
+/workspace.xml
\ No newline at end of file
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 00000000..74fa738b
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+Daresay Weather
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 00000000..88ea3aa1
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 00000000..79ee123c
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 00000000..5cd135a0
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..85226533
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.8
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 00000000..7f68460d
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..94a25f7f
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index b3fe3b4f..0ee7a56a 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,20 @@
+So, a bit overworked, but it was such good fun!
+
+To run, add file config.properties with key and api-key below in res/raw and compile.
+
+api-key=62fc...
+
+Started with a tab ambition but time ran out, so it's just one fragment in a tab control. However, it's prepared for more....
+
+Enjoy!
+
+
+
+
+---
+
+
+----
# Work sample - Application developer
## Assignment
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 00000000..f8a72110
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1,31 @@
+/build
+/src/main/res/raw/config.properties
+
+
+# Built application files
+/*/build/
+
+# Crashlytics configuations
+com_crashlytics_export_strings.xml
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Gradle generated files
+.gradle/
+
+# Signing files
+.signing/
+
+# User-specific configurations
+.idea/libraries/
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/.name
+.idea/compiler.xml
+.idea/copyright/profiles_settings.xml
+.idea/encodings.xml
+.idea/misc.xml
+.idea/modules.xml
+.idea/scopes/scope_settings.xml
+*.iml
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 00000000..7e3176d4
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,52 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+ compileSdkVersion 29
+ buildToolsVersion "29.0.3"
+
+ defaultConfig {
+ applicationId "se.bynumbers.daresayweather"
+ minSdkVersion 26
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ vectorDrawables.useSupportLibrary = true
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ compileOptions {
+ kotlinOptions { jvmTarget = "1.8" }
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ //This version might not be correct,
+ implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0'
+
+ implementation 'com.android.volley:volley:1.1.1'
+ implementation 'com.google.code.gson:gson:2.8.6'
+
+
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.drawerlayout:drawerlayout:1.0.0'
+ implementation 'com.google.android.gms:play-services-location:17.0.0'
+
+ implementation 'androidx.core:core-ktx:1.2.0'
+ implementation 'com.google.android.material:material:1.1.0'
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+
+ implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 00000000..f1b42451
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -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
diff --git a/app/src/androidTest/java/se/bynumbers/sampleweather/ExampleInstrumentedTest.kt b/app/src/androidTest/java/se/bynumbers/sampleweather/ExampleInstrumentedTest.kt
new file mode 100644
index 00000000..155d1e61
--- /dev/null
+++ b/app/src/androidTest/java/se/bynumbers/sampleweather/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package se.bynumbers.sampleweather
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("se.bynumbers.myapplication", appContext.packageName)
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..c54f151b
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/MainActivity.kt b/app/src/main/java/se/bynumbers/daresayweather/MainActivity.kt
new file mode 100644
index 00000000..09a06483
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/MainActivity.kt
@@ -0,0 +1,57 @@
+package se.bynumbers.daresayweather
+
+import android.Manifest
+import android.content.DialogInterface
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.viewpager.widget.ViewPager
+import com.google.android.material.tabs.TabLayout
+import kotlinx.serialization.json.Json.Default.context
+import se.bynumbers.daresayweather.ui.main.SectionsPagerAdapter
+import se.bynumbers.daresayweather.util.HttpHelper
+import se.bynumbers.daresayweather.R
+
+
+class MainActivity : AppCompatActivity() {
+ private val TAG = "MainActivity"
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ val sectionsPagerAdapter =
+ SectionsPagerAdapter(
+ this,
+ supportFragmentManager
+ )
+ val viewPager: ViewPager = findViewById(R.id.view_pager)
+ viewPager.adapter = sectionsPagerAdapter
+ val tabs: TabLayout = findViewById(R.id.tabs)
+ tabs.setupWithViewPager(viewPager)
+
+
+ /* val fab: FloatingActionButton = findViewById(R.id.fab)
+
+ fab.setOnClickListener { view ->
+ Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
+ .setAction("Action", null).show()
+ }
+
+ */
+
+ }
+
+
+ override fun onStop() {
+ super.onStop()
+ HttpHelper.getInstance(applicationContext).cancelAll()
+ }
+ private fun toast(msg : String){
+ Toast.makeText(this@MainActivity, msg, Toast.LENGTH_SHORT).show()
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/model/CurrentWeather.kt b/app/src/main/java/se/bynumbers/daresayweather/model/CurrentWeather.kt
new file mode 100644
index 00000000..e1400e07
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/model/CurrentWeather.kt
@@ -0,0 +1,66 @@
+package se.bynumbers.daresayweather.model
+
+import android.app.Application
+import android.content.Context
+import android.util.Log
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.android.volley.Response
+import com.android.volley.VolleyError
+import com.google.gson.Gson
+import com.google.gson.JsonObject
+import kotlinx.serialization.json.Json
+import se.bynumbers.daresayweather.util.WeatherDataHelper
+
+import java.lang.reflect.Array
+
+
+data class Coord (
+ var lon : Double = 0.0,
+ var lat : Double = 0.0
+)
+
+class Weather (
+ var id : Int = 0,
+ var main: String? = null,
+ var description: String? = null,
+ var icon: String? = null
+)
+
+
+class Wind (
+ var speed : Double = 0.0,
+ var deg : Int = 0
+)
+data class Clouds (
+ var all : Int = 0
+)
+
+data class Sys (
+ var type : Int = 0,
+ var id : Int = 0,
+ var message : Double = 0.0,
+ var country: String? = null,
+ var sunrise : Int = 0,
+ var sunset : Int = 0,
+ var pod: String? = null
+)
+
+data class CurrentWeather (
+ var coord: Coord? = null,
+ var weather: String? = null,
+ var base: String? = null,
+ var main: Main? = null,
+ var visibility : Int = 0,
+ var wind: Wind? = null,
+ var clouds: Clouds? = null,
+ var dt : Int = 0,
+ var sys: Sys? = null,
+ var timezone : Int = 0,
+ var id : Int = 0,
+ var name: String? = null,
+ var cod : Int = 0
+)
+
diff --git a/app/src/main/java/se/bynumbers/daresayweather/model/Forecast.kt b/app/src/main/java/se/bynumbers/daresayweather/model/Forecast.kt
new file mode 100644
index 00000000..435bf7d2
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/model/Forecast.kt
@@ -0,0 +1,57 @@
+package se.bynumbers.daresayweather.model
+import kotlinx.serialization.*
+
+@Serializable
+class Main(
+ var sea_level: Double = 0.0,
+ var grnd_level : Double = 0.0,
+ var temp_kf : Double = 0.0,
+ var temp : Double = 0.0,
+ var feels_like : Double = 0.0,
+ var temp_min : Double = 0.0,
+ var temp_max : Double = 0.0,
+ var pressure : Int = 0,
+ var humidity : Int = 0
+
+)
+
+
+class Rain (
+ @SerialName("3h")
+ var threeh : Double = 0.0
+)
+
+class Snow
+{
+ @SerialName("3h")
+ var threeh = 0.0
+}
+
+class List(
+ var dt : Int = 0,
+ var main : Main? = null,
+ var weather : List? = null,
+ var clouds : Clouds? = null,
+ var wind : Wind? = null,
+ var sys : Sys? = null,
+ var dt_txt : String? = null,
+ var rain : Rain? = null,
+ var snow : Snow? = null
+)
+
+
+
+data class City(
+ var id: Int = 0,
+ var name : String? = null,
+ var coord : Coord? = null,
+ var country : String? = null
+)
+
+class Forecast(
+ var cod : String? = null,
+ var message : Double = 0.0,
+ var cnt : Int = 0,
+ var list : List,
+ var city: City? = null
+)
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/model/LocationData.kt b/app/src/main/java/se/bynumbers/daresayweather/model/LocationData.kt
new file mode 100644
index 00000000..f84686eb
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/model/LocationData.kt
@@ -0,0 +1,106 @@
+package se.bynumbers.daresayweather.model
+
+import android.Manifest
+import android.annotation.SuppressLint
+import android.app.Application
+import android.content.Context
+import android.content.pm.PackageManager
+import android.location.Location
+import android.util.Log
+import android.widget.Toast
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.ViewModel
+import com.google.android.gms.location.LocationCallback
+import com.google.android.gms.location.LocationRequest
+import com.google.android.gms.location.LocationResult
+import com.google.android.gms.location.LocationServices
+import se.bynumbers.daresayweather.util.PermissionStatusListener
+import se.bynumbers.daresayweather.R
+
+data class LocationData(
+ val longitude: Double,
+ val latitude: Double
+)
+class LocationLiveData(context: Context) : LiveData() {
+ private val TAG = "LocationLiveData"
+ var _context = context
+ private var fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
+ companion object {
+
+ val locationRequest: LocationRequest = LocationRequest.create().apply {
+ interval = 10000
+ fastestInterval = 5000
+ priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
+ }
+ }
+ private val locationCallback = object : LocationCallback() {
+ override fun onLocationResult(locationResult: LocationResult?) {
+ locationResult ?: return
+ for (location in locationResult.locations) {
+ setLocationData(location)
+ }
+ }
+ }
+ override fun onInactive() {
+ super.onInactive()
+ fusedLocationClient.removeLocationUpdates(locationCallback)
+ }
+
+ override fun onActive() {
+ super.onActive()
+ fusedLocationClient.lastLocation
+ .addOnSuccessListener { location: Location? ->
+ location?.also {
+ setLocationData(it)
+ }
+ }
+ .addOnFailureListener { error ->
+ Log.e(TAG, "Could not get last location: ${error.message}")
+ }
+ startLocationUpdates()
+
+ }
+
+
+ private fun startLocationUpdates() {
+ if(checkLocationPermission()) {
+ Log.i(TAG, "Start location updates ")
+ fusedLocationClient.requestLocationUpdates(
+ locationRequest,
+ locationCallback,
+ null
+ )
+ } else {
+ Toast.makeText(_context, R.string.no_location_check, Toast.LENGTH_SHORT).show()
+ }
+ }
+ private fun setLocationData(location: Location) {
+ Log.i(TAG, "Setting location: ${location.longitude}, ${location.latitude}")
+ value = LocationData(
+ longitude = location.longitude,
+ latitude = location.latitude
+ )
+ }
+ private fun checkLocationPermission(): Boolean {
+ return ContextCompat.checkSelfPermission(
+ _context,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
+ _context,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED
+ }
+
+}
+class LocationListener(application : Application) : AndroidViewModel(application) {
+
+ private var locationData = LocationLiveData(application)
+
+ fun getLocationData() = locationData
+
+ val locationPermissionStatusLiveData = PermissionStatusListener(application.applicationContext,
+ Manifest.permission.ACCESS_FINE_LOCATION)
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/ui/main/CurrentWeatherFragment.kt b/app/src/main/java/se/bynumbers/daresayweather/ui/main/CurrentWeatherFragment.kt
new file mode 100644
index 00000000..5f3f5fd2
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/ui/main/CurrentWeatherFragment.kt
@@ -0,0 +1,263 @@
+package se.bynumbers.daresayweather.ui.main
+
+import android.Manifest
+import android.app.Activity
+import android.graphics.drawable.Drawable
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.*
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import kotlinx.android.synthetic.main.fragment_current_weather.*
+
+import se.bynumbers.daresayweather.model.LocationListener
+import se.bynumbers.daresayweather.util.DateTimeHelper
+import se.bynumbers.daresayweather.util.LocationHelper
+import se.bynumbers.daresayweather.util.PermissionStatus
+import se.bynumbers.daresayweather.util.ResourceHelper
+import se.bynumbers.daresayweather.R
+
+
+/**
+ * A placeholder fragment containing a simple view.
+ */
+class CurrentWeatherFragment : Fragment() {
+
+ private lateinit var pageViewModel: PageCurrentWeatherViewModel
+ private lateinit var locationDataListener : LocationListener
+ private lateinit var currentWeatherViewModel : CurrentWeatherViewModel
+ private var alertDialog: AlertDialog? = null
+ private val TAG = "CurrentWeatherFragment"
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ locationDataListener = ViewModelProvider(this).get(LocationListener::class.java)
+ pageViewModel = ViewModelProvider(this).get(PageCurrentWeatherViewModel::class.java)
+ currentWeatherViewModel = ViewModelProvider(this).get(CurrentWeatherViewModel::class.java)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val root = inflater.inflate(R.layout.fragment_current_weather, container, false)
+ val statusTextView = root.findViewById(R.id.status_label)
+ val currentTextView = root.findViewById(R.id.current_label)
+ var mainImageView = root.findViewById(R.id.main_weather_image)
+ val temperatureView = root.findViewById(R.id.temperature_label)
+ val unitSwitch = root.findViewById(R.id.unit_switch)
+ val locationSwitch = root.findViewById(R.id.location_switch)
+ val btnRetry = root.findViewById(R.id.btn_retry)
+
+ btnRetry.setVisibility(View.INVISIBLE)
+ mainImageView.setImageDrawable(requireContext().getDrawable(R.drawable.wi_na))
+ temperatureView.text = ""
+ statusTextView.text = getString(R.string.no_location_check)
+ btnRetry.setOnClickListener {
+ if(LocationHelper.checkLocationPermission(requireContext())){
+
+ startLocationUpdates()
+ updateLocationUI(true)
+ }
+
+ }
+ locationSwitch.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { _, isChecked ->
+ if (isChecked) {
+ if(askForLocationPermission(requireActivity())==1) {
+ startLocationUpdates()
+ }
+ } else {
+ stopLocationUpdates()
+ }
+ })
+ unitSwitch.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { _, isChecked ->
+ ResourceHelper.setFahrenheit(isChecked, requireContext())
+ var currentTemp : String = temperatureView.text.toString()
+ if(isChecked){
+ currentTemp = ResourceHelper.toFahrenheit(currentTemp)
+ } else {
+ currentTemp = ResourceHelper.toCelsius(currentTemp)
+ }
+ temperatureView.text = "$currentTemp ${ResourceHelper.getFahrenheitOrCelsius(requireContext())}"
+
+ })
+
+ //TODO: Refactor and probably not needed
+ locationDataListener.locationPermissionStatusLiveData.observe(this.viewLifecycleOwner, Observer {
+ if(it is PermissionStatus.Denied) {
+ Log.d(TAG,"Show location permission dialog")
+ if(askForLocationPermission(requireActivity())==1){
+ startLocationUpdates()
+ }
+
+ } else {
+
+ }
+
+ Log.d(TAG,"Permission status is $it")
+ })
+
+
+
+
+
+ pageViewModel.weatherImage.observe(this.viewLifecycleOwner, Observer {
+ mainImageView.setImageDrawable(it)
+ })
+ pageViewModel.text.observe(this.viewLifecycleOwner, Observer {
+ statusTextView.text = it
+ })
+ pageViewModel.current_label.observe(this.viewLifecycleOwner, Observer {
+ currentTextView.text = it
+ })
+ pageViewModel.temperature.observe(this.viewLifecycleOwner, Observer {
+ temperatureView.text = "$it ${ResourceHelper.getFahrenheitOrCelsius(requireContext())}"
+ })
+ /* pageViewModel.degreeLabel.observe(this.viewLifecycleOwner, Observer {
+ degreeView.setImageDrawable(it)
+ })
+
+ */
+ return root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val locationEnabled = LocationHelper.checkLocationPermission(requireContext())
+ updateLocationUI(locationEnabled)
+ updateBackground()
+ startLocationUpdates()
+ }
+
+ fun askForLocationPermission(activity: Activity) : Int {
+ if (alertDialog?.isShowing == true) {
+ return -1 // null or dialog already being shown
+ }
+ if (!LocationHelper.checkLocationPermission(activity)) {
+ Log.d(TAG, "No permission given, showing dialog")
+ if (shouldShowRequestPermissionRationale(
+ Manifest.permission.ACCESS_FINE_LOCATION
+ )
+ ) {
+ alertDialog = AlertDialog.Builder(activity)
+ .setMessage(requireContext().getString(R.string.ask_use_permission))
+ .setPositiveButton(android.R.string.ok) { _, _ ->
+ requestPermissions(
+ arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
+ LocationHelper.PERMISSIONS_LOCATION
+ )
+ }
+ .setNegativeButton(android.R.string.cancel, null).create()
+ alertDialog?.apply {
+ show()
+ }
+ } else {
+
+ requestPermissions(
+ arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
+ LocationHelper.PERMISSIONS_LOCATION
+ )
+
+ }
+ return 0 //wait
+ } else {
+ Log.d(TAG, "Permission given, not showing dialog")
+ return 1
+ }
+ }
+
+
+
+ private fun startLocationUpdates(){
+ locationDataListener.getLocationData().removeObservers(this.viewLifecycleOwner)
+ locationDataListener.getLocationData().observe(this.viewLifecycleOwner, Observer {
+ Log.d(TAG, "Location data aquired: ${it.latitude}, ${it.longitude}")
+ pageViewModel.updateLocation(it)
+ currentWeatherViewModel.getCurrentWeather(requireContext(), it).observe(this.viewLifecycleOwner, Observer {
+ Log.d(TAG, "Weather data aquired: $it")
+ pageViewModel.setWeatherData(it)
+ // latLong.text = getString(R.string.latLong, it.longitude, it.latitude)
+
+ })
+ updateBackground()
+ })
+ }
+ private fun stopLocationUpdates(){
+ locationDataListener.getLocationData().removeObservers(this.viewLifecycleOwner)
+ }
+ private fun updateBackground(){
+
+//This function will change background drawable, so place it where you want.
+//This function will change background drawable, so place it where you want.
+ var id : Int
+ if(DateTimeHelper.isDayTime()) id = R.drawable.bg_day else id = R.drawable.bg_night
+ constraintLayout.background = requireContext().getDrawable(id)
+ }
+ private fun updateLocationUI(on : Boolean){
+ if(view != null) {
+ var statusView = view!!.findViewById(R.id.status_label)
+ var text = ""//""Location data is allowed"
+ if(!on){
+ text = getString(R.string.no_location_check)
+ val btnRetry = view!!.findViewById(R.id.btn_retry)
+ btnRetry.setVisibility(View.VISIBLE)
+ } else {
+ val btnRetry = view!!.findViewById(R.id.btn_retry)
+ btnRetry.setVisibility(View.INVISIBLE)
+ }
+ statusView.text = text
+ val locationSwitch = view!!.findViewById(R.id.location_switch)
+ locationSwitch.isChecked = on
+ }
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ Log.d(TAG,"onRequestPermissionsResult")
+ if(LocationHelper.arePermissionsResultYes(requestCode,
+ permissions, grantResults, requireContext()
+ )) {
+ Log.d(TAG,"Location permission granted")
+ startLocationUpdates()
+ updateLocationUI(true)
+
+ } else {
+ Log.d(TAG,"Location permission not granted")
+ stopLocationUpdates()
+ updateLocationUI(false)
+ }
+
+ }
+
+
+ companion object {
+ /**
+ * The fragment argument representing the section number for this
+ * fragment.
+ */
+ private const val ARG_SECTION_NUMBER = "section_number"
+
+ /**
+ * Returns a new instance of this fragment for the given section
+ * number.
+ */
+ @JvmStatic
+ fun newInstance(sectionNumber: Int): CurrentWeatherFragment {
+ return CurrentWeatherFragment().apply {
+ arguments = Bundle().apply {
+ putInt(ARG_SECTION_NUMBER, sectionNumber)
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/ui/main/CurrentWeatherViewModel.kt b/app/src/main/java/se/bynumbers/daresayweather/ui/main/CurrentWeatherViewModel.kt
new file mode 100644
index 00000000..543e7240
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/ui/main/CurrentWeatherViewModel.kt
@@ -0,0 +1,40 @@
+package se.bynumbers.daresayweather.ui.main
+
+import android.app.Application
+import android.content.Context
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import com.android.volley.Response
+import com.android.volley.VolleyError
+import com.google.gson.Gson
+import com.google.gson.JsonObject
+import se.bynumbers.daresayweather.model.LocationData
+import se.bynumbers.daresayweather.util.WeatherDataHelper
+
+class CurrentWeatherLiveData : MutableLiveData(), Response.Listener,
+ Response.ErrorListener {
+
+ override fun onResponse(response: JsonObject?) {
+ value = response
+ }
+
+ override fun onErrorResponse(error: VolleyError?) {
+ TODO("Not yet implemented")
+ }
+
+}
+
+class CurrentWeatherViewModel(application: Application) : AndroidViewModel(application) {
+ private val TAG = "CurrentWeatherViewModel"
+ private var currentWeatherData = MutableLiveData()
+
+ //TODO Singleton
+ private val wdHelper = WeatherDataHelper()
+
+ fun getCurrentWeather(context: Context, locationData: LocationData) : MutableLiveData {
+ currentWeatherData = wdHelper.getForecast(context, locationData)
+ return currentWeatherData
+ }
+ //
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/ui/main/ForecastWeatherFragment.kt b/app/src/main/java/se/bynumbers/daresayweather/ui/main/ForecastWeatherFragment.kt
new file mode 100644
index 00000000..d75102e0
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/ui/main/ForecastWeatherFragment.kt
@@ -0,0 +1,58 @@
+package se.bynumbers.daresayweather.ui.main
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+
+import se.bynumbers.daresayweather.R
+
+/**
+ * A placeholder fragment containing a simple view.
+ */
+//TODO
+class ForecastWeatherFragment : Fragment() {
+
+ private lateinit var pageViewModel: PageForecastViewModel
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val root = inflater.inflate(R.layout.fragment_forecast, container, false)
+ val textView: TextView = root.findViewById(R.id.status_label)
+ pageViewModel.text.observe(this.viewLifecycleOwner, Observer {
+ textView.text = it
+ })
+ return root
+ }
+
+ companion object {
+ /**
+ * The fragment argument representing the section number for this
+ * fragment.
+ */
+ private const val ARG_SECTION_NUMBER = "section_number"
+
+ /**
+ * Returns a new instance of this fragment for the given section
+ * number.
+ */
+ @JvmStatic
+ fun newInstance(sectionNumber: Int): ForecastWeatherFragment {
+ return ForecastWeatherFragment().apply {
+ arguments = Bundle().apply {
+ putInt(ARG_SECTION_NUMBER, sectionNumber)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/ui/main/PageCurrentWeatherViewModel.kt b/app/src/main/java/se/bynumbers/daresayweather/ui/main/PageCurrentWeatherViewModel.kt
new file mode 100644
index 00000000..3bb1cd30
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/ui/main/PageCurrentWeatherViewModel.kt
@@ -0,0 +1,98 @@
+package se.bynumbers.daresayweather.ui.main
+
+import android.app.Application
+import android.graphics.drawable.Drawable
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Transformations
+import com.google.gson.Gson
+import com.google.gson.JsonArray
+import com.google.gson.JsonObject
+
+import se.bynumbers.daresayweather.model.LocationData
+import se.bynumbers.daresayweather.model.Main
+import se.bynumbers.daresayweather.model.Weather
+import se.bynumbers.daresayweather.util.Constants
+import se.bynumbers.daresayweather.util.DateTimeHelper
+import se.bynumbers.daresayweather.util.ResourceHelper
+import se.bynumbers.daresayweather.R
+import kotlin.math.roundToInt
+
+
+class PageCurrentWeatherViewModel(application : Application) : AndroidViewModel(application) {
+ private val TAG = "PageCurrentWeatherViewModel"
+ private val _index = MutableLiveData()
+ private val _currentWeatherImage = MutableLiveData()
+ private val _currentWeather =
+ CurrentWeatherLiveData()
+ private val _currentPlace = MutableLiveData()
+ private var _latestLocation =
+ LocationData(0.0, 0.0)
+
+ //TODO: Gör en klass, plocka ut element för element CurrentWeather
+ val text: LiveData = Transformations.map(_currentPlace) {
+ // Log.d("PgeCurrentWeatherViewModel","Calling getForecast")
+ //WeatherHelper.getForecast(application.applicationContext, it)
+ //_currentWeather.getCurrentWeather(application.applicationContext, it)
+ if(it == null){
+ application.applicationContext.getString(R.string.ask_use_permission)
+ } else {
+ ""
+ }
+ }
+
+ val current_label: LiveData = Transformations.map(_currentWeather) {
+
+ it["name"].asString
+ }
+ /* val degreeLabel : LiveData = Transformations.map(_currentWeather) {
+ val _context = application.applicationContext
+ var degreeDrawable : Drawable? = null
+ degreeDrawable = ResourceHelper.getFahrenheitOrCelsius(_context)
+ degreeDrawable
+ }*/
+ val weatherImage: LiveData = Transformations.map(_currentWeather) {
+ val _context = application.applicationContext
+ var weatherDrawable : Drawable?
+ weatherDrawable = ResourceHelper.getWeatherDrawableFromMap(_context, getWeatherIconKey(it))
+ weatherDrawable
+ }
+ val temperature: LiveData = Transformations.map(_currentWeather) {
+
+ val gson = Gson()
+ //TODO Fugly, use TypeToken instead
+ val jo : JsonObject = it["main"].asJsonObject
+ val main : Main = gson.fromJson(jo, Main::class.java)
+ main.temp.roundToInt().toString()
+ }
+ private fun getWeatherIconKey(jo:JsonObject) : String {
+ val gson = Gson()
+ //TOOO Fix with TypeToken plz
+ val ja : JsonArray = jo["weather"].asJsonArray
+ val weatherMeta : Weather = gson.fromJson(ja.get(0).asJsonObject, Weather::class.java)
+
+ var dayOrNight = if(DateTimeHelper.isDayTime()) "d" else "n"
+ var key = Constants.weatherIconMap["${weatherMeta.id}$dayOrNight"]
+ if(key == null){
+ key = "wi_na"
+ }
+ return key
+ }
+ fun setWeatherData(currentWeather: JsonObject?){
+ _currentWeather.value = currentWeather
+ }
+ fun updateLocation(locationData : LocationData){
+ if(!locationData.equals(_latestLocation)) {
+ _currentPlace.value = locationData
+ _latestLocation = locationData
+ }
+ }
+ fun setIndex(index: Int) {
+ _index.value = index
+ }
+ fun setImage(drawable: Drawable){
+ _currentWeatherImage.value = drawable
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/ui/main/PageForecastViewModel.kt b/app/src/main/java/se/bynumbers/daresayweather/ui/main/PageForecastViewModel.kt
new file mode 100644
index 00000000..ce0b59f6
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/ui/main/PageForecastViewModel.kt
@@ -0,0 +1,23 @@
+package se.bynumbers.daresayweather.ui.main
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Transformations
+import androidx.lifecycle.ViewModel
+import se.bynumbers.daresayweather.model.CurrentWeather
+//TODO
+class PageForecastViewModel : ViewModel() {
+
+ private val _index = MutableLiveData()
+ private val _currentWeather = MutableLiveData()
+ val text: LiveData = Transformations.map(_index) {
+ "Hello world from section: $it"
+ }
+ val currentPlace: LiveData = Transformations.map(_currentWeather) {
+ "${it.name}"
+ }
+ fun setIndex(index: Int) {
+ _index.value = index
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/ui/main/SectionsPagerAdapter.kt b/app/src/main/java/se/bynumbers/daresayweather/ui/main/SectionsPagerAdapter.kt
new file mode 100644
index 00000000..d78006de
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/ui/main/SectionsPagerAdapter.kt
@@ -0,0 +1,37 @@
+package se.bynumbers.daresayweather.ui.main
+
+import android.content.Context
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.fragment.app.FragmentPagerAdapter
+import se.bynumbers.daresayweather.R
+
+private val TAB_TITLES = arrayOf(
+ R.string.tab_text_1,
+ R.string.tab_text_2
+)
+
+/**
+ * A [FragmentPagerAdapter] that returns a fragment corresponding to
+ * one of the sections/tabs/pages.
+ */
+class SectionsPagerAdapter(private val context: Context, fm: FragmentManager)
+ : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
+
+ override fun getItem(position: Int): Fragment {
+ // getItem is called to instantiate the fragment for the given page.
+ // Return a PlaceholderFragment (defined as a static inner class below).
+ return CurrentWeatherFragment.newInstance(
+ position + 1
+ )
+ }
+
+ override fun getPageTitle(position: Int): CharSequence? {
+ return context.resources.getString(TAB_TITLES[position])
+ }
+
+ override fun getCount(): Int {
+ // Show 2 total pages.
+ return 1
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/util/Constants.kt b/app/src/main/java/se/bynumbers/daresayweather/util/Constants.kt
new file mode 100644
index 00000000..ee85fd02
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/util/Constants.kt
@@ -0,0 +1,126 @@
+package se.bynumbers.daresayweather.util
+
+class Constants {
+ //weather.id (from Open->icon
+ companion object {
+ const val WEATHER_URL = "https://worksample-api.herokuapp.com/weather"
+ const val SP_DARESAY_WEATHER = "SP_DARESAY_WEATHER"
+ const val SP_LOCATION_ENABLED = "SP_LOCATION_ENABLED"
+ const val SP_FAHRENHEIT = "SP_FAHRENHEIT"
+ const val API_KEY = "api-key"
+ val weatherIconMap: HashMap = hashMapOf(
+ "201d" to "wi_day_thunderstorm",
+ "201n" to "wi_night_alt_thunderstorm",
+ "202d" to "wi_day_thunderstorm",
+ "202n" to "wi_night_alt_thunderstorm",
+ "210d" to "wi_day_thunderstorm",
+ "210n" to "wi_night_alt_thunderstorm",
+ "211d" to "wi_day_thunderstorm",
+ "211n" to "wi_night_alt_thunderstorm",
+ "212d" to "wi_day_thunderstorm",
+ "212n" to "wi_night_alt_thunderstorm",
+ "221d" to "wi_day_thunderstorm",
+ "221d" to "wi_night_alt_thunderstorm",
+ "230d" to "wi_day_thunderstorm",
+ "230n" to "wi_night_alt_thunderstorm",
+ "231d" to "wi_day_thunderstorm",
+ "231n" to "wi_night_alt_thunderstorm",
+ "232d" to "wi_day_thunderstorm",
+ "232n" to "wi_night_alt_thunderstorm",
+
+ "300d" to "wi_day_sprinkle",
+ "300n" to "wi_night_sprinkle",
+ "301d" to "wi_day_sprinkle",
+ "301n" to "wi_night_sprinkle",
+ "302d" to "wi_day_rain",
+ "302n" to "wi_night_rain",
+ "310d" to "wi_day_rain",
+ "310n" to "wi_night_rain",
+ "311d" to "wi_day_rain",
+ "311n" to "wi_night_rain",
+ "312d" to "wi_day_rain",
+ "312n" to "wi_night_rain",
+ "313d" to "wi_day_showers",
+ "313n" to "wi_night_showers",
+ "314d" to "wi_day_showers",
+ "314n" to "wi_night_showers",
+ "321d" to "wi_rain",
+ "321n" to "wi_night_rain",
+
+ "500d" to "wi_day_sprinkle",
+ "500n" to "wi_night_sprinkle",
+ "501d" to "wi_day_sprinkle",
+ "501n" to "wi_night_sprinkle",
+ "502d" to "wi_rain",
+ "502n" to "wi_night_rain",
+ "503d" to "wi_rain",
+ "503n" to "wi_night_rain",
+ "504d" to "wi_rain",
+ "504n" to "wi_night_rain",
+ "511d" to "wi_hail",
+ "511n" to "wi_night_hail",
+ "520d" to "wi_day_showers",
+ "520n" to "wi_night_showers",
+ "521d" to "wi_day_showers",
+ "522n" to "wi_night_showers",
+ "531d" to "wi_day_showers",
+ "531n" to "wi_night_showers",
+
+ "600d" to "wi_day_snow",
+ "600n" to "wi_night_alt_snow",
+ "601d" to "wi_day_snow",
+ "601n" to "wi_night_alt_snow",
+ "602d" to "wi_day_snow",
+ "602n" to "wi_night_alt_snow",
+ "611d" to "wi_day_sleet",
+ "611n" to "wi_night_alt_sleet",
+ "612d" to "wi_day_sleet",
+ "612n" to "wi_night_alt_sleet",
+ "613d" to "wi_day_sleet",
+ "613n" to "wi_night_alt_sleet",
+ "615d" to "wi_day_sleet",
+ "615n" to "wi_night_alt_sleet",
+ "616d" to "wi_day_sleet",
+ "616n" to "wi_night_alt_sleet",
+ "620d" to "wi_day_snow",
+ "620n" to "wi_night_alt_snow",
+ "621d" to "wi_day_snow",
+ "621n" to "wi_night_alt_snow",
+ "622d" to "wi_day_snow",
+ "622n" to "wi_night_alt_snow",
+
+ "701d" to "wi_fog",
+ "701n" to "wi_night_fog",
+ "711d" to "wi_fog",
+ "711n" to "wi_night_fog",
+ "721d" to "wi_fog",
+ "721n" to "wi_night_fog",
+ "731d" to "wi_fog",
+ "731n" to "wi_night_fog",
+ "741d" to "wi_fog",
+ "741n" to "wi_night_fog",
+ "751d" to "wi_fog",
+ "751n" to "wi_night_fog",
+ "761d" to "wi_fog",
+ "761n" to "wi_night_fog",
+ "762d" to "wi_fog",
+ "762n" to "wi_night_fog",
+ "771d" to "wi_fog",
+ "771n" to "wi_night_fog",
+ "781d" to "wi_day_rain_wind",
+ "781n" to "wi_night_rain_wind",
+
+ "800d" to "wi_day_sunny",
+ "800n" to "wi_night_clear",
+ "801d" to "wi_day_cloudy_high",
+ "801n" to "wi_night_cloudy_high",
+ "802d" to "wi_day_cloudy_high",
+ "802n" to "wi_night_cloudy_high",
+ "803d" to "wi_day_cloudy",
+ "803n" to "wi_night_cloudy",
+ "804d" to "wi_day_sunny_overcast",
+ "804n" to "wi_night_cloudy_high",
+ "na" to "wi_na"
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/util/DateTimeHelper.kt b/app/src/main/java/se/bynumbers/daresayweather/util/DateTimeHelper.kt
new file mode 100644
index 00000000..9cb56601
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/util/DateTimeHelper.kt
@@ -0,0 +1,16 @@
+package se.bynumbers.daresayweather.util
+
+
+import java.time.LocalDateTime
+
+class DateTimeHelper {
+ companion object {
+ fun isDayTime() : Boolean {
+ val now : LocalDateTime = LocalDateTime.now()
+ if(now.hour > 6 && now.hour < 18){
+ return true
+ }
+ return false
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/util/HttpHelper.kt b/app/src/main/java/se/bynumbers/daresayweather/util/HttpHelper.kt
new file mode 100644
index 00000000..9c355d9a
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/util/HttpHelper.kt
@@ -0,0 +1,68 @@
+package se.bynumbers.daresayweather.util
+
+import android.content.Context
+import android.util.Log
+import android.widget.Toast
+import com.android.volley.*
+
+import com.android.volley.toolbox.JsonObjectRequest
+import com.android.volley.toolbox.Volley
+//import com.android.volley.toolbox.
+import com.google.gson.Gson
+import com.google.gson.JsonArray
+import com.google.gson.JsonObject
+import kotlinx.serialization.PrimitiveKind
+import se.bynumbers.daresayweather.model.CurrentWeather
+//import se.bynumbers.daresayweather.model.CurrentWeatherHelper
+
+import se.bynumbers.daresayweather.R
+
+
+val url = "http://my-json-feed"
+
+class HttpHelper private constructor(context: Context) {
+ init {
+ // Init using context argument
+ }
+
+ companion object : SingletonHolder(::HttpHelper)
+ val TAG = "HttpHelper"
+
+ val requestQueue: RequestQueue by lazy {
+ // applicationContext is key, it keeps you from leaking the
+ // Activity or BroadcastReceiver if someone passes one in.
+ Volley.newRequestQueue(context.applicationContext)
+ }
+
+ fun addToRequestQueue(req: Request) {
+ requestQueue.add(req)
+ }
+
+ fun getCurrentWeatherJson(context : Context, url: String, callback: WeatherDataHelper) {
+ val gson = Gson()
+ val jsonObjectRequest = JsonObjectRequest(
+ Request.Method.GET, url, null,
+ Response.Listener { response ->
+
+ Log.d(TAG, "Response: ${response}")
+ val retJo = gson.fromJson(response.toString(), JsonObject::class.java)
+ callback.onResponse(retJo)
+
+ },
+ Response.ErrorListener { error ->
+ Log.e(TAG, "Network error: ${error.message}")
+ //retJo = null
+ //TODO: On ERROR
+ Toast.makeText(context, context.getString(R.string.check_network), Toast.LENGTH_SHORT ).show()
+ }
+ )
+
+
+ this.addToRequestQueue(jsonObjectRequest)
+
+ }
+ fun cancelAll() {
+ requestQueue.cancelAll{true}
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/util/LocationHelper.kt b/app/src/main/java/se/bynumbers/daresayweather/util/LocationHelper.kt
new file mode 100644
index 00000000..1685c067
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/util/LocationHelper.kt
@@ -0,0 +1,80 @@
+package se.bynumbers.daresayweather.util
+
+import android.Manifest
+import android.app.Activity
+import android.app.Application
+import android.content.Context
+import android.content.pm.PackageManager
+import android.util.Log
+import androidx.appcompat.app.AlertDialog
+import androidx.core.app.ActivityCompat
+import androidx.core.app.ActivityCompat.requestPermissions
+import androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale
+import androidx.core.content.ContextCompat
+import se.bynumbers.daresayweather.util.Constants.Companion.SP_DARESAY_WEATHER
+import se.bynumbers.daresayweather.util.Constants.Companion.SP_LOCATION_ENABLED
+import se.bynumbers.daresayweather.R
+
+class LocationHelper {
+
+ companion object {
+ private val TAG = "LocationHelper"
+ const val PERMISSIONS_LOCATION = 1001
+ fun checkLocationPermission(context : Context): Boolean {
+ return ContextCompat.checkSelfPermission(
+ context,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED
+ /*&& ActivityCompat.checkSelfPermission(
+ context,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ ) == PackageManager.PERMISSION_GRANTED*/
+ }
+ fun arePermissionsResultYes(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray,
+ context: Context
+ ) : Boolean {
+ val sp = context.getSharedPreferences(SP_DARESAY_WEATHER,
+ Context.MODE_PRIVATE
+ )
+ when (requestCode) {
+ PERMISSIONS_LOCATION -> {
+ if (grantResults.isNotEmpty()
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED
+ ) {
+
+ // permission was granted, yay! Do the
+ // location-related task you need to do.
+ if (ContextCompat.checkSelfPermission(
+ context,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ )
+ == PackageManager.PERMISSION_GRANTED
+ ) {
+
+ val editor = sp.edit()
+ editor.putBoolean(SP_LOCATION_ENABLED, true)
+ editor.apply()
+
+ return true
+ }
+ }
+
+ }
+ }
+ val editor = sp.edit()
+ editor.putBoolean(SP_LOCATION_ENABLED, false)
+ editor.apply()
+
+ return false
+
+ }
+
+
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/util/PermissionStatusListener.kt b/app/src/main/java/se/bynumbers/daresayweather/util/PermissionStatusListener.kt
new file mode 100644
index 00000000..d811c654
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/util/PermissionStatusListener.kt
@@ -0,0 +1,30 @@
+package se.bynumbers.daresayweather.util
+
+import android.content.Context
+import android.content.pm.PackageManager
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.LiveData
+import se.bynumbers.daresayweather.R
+
+class PermissionStatusListener(private val context: Context,
+ private val permissionToListen: String) : LiveData() {
+
+ override fun onActive() = handlePermissionCheck()
+
+ private fun handlePermissionCheck() {
+ val isPermissionGranted = ContextCompat.checkSelfPermission(context,
+ permissionToListen) == PackageManager.PERMISSION_GRANTED
+
+ if (isPermissionGranted)
+ postValue(PermissionStatus.Granted())
+ else
+ postValue(PermissionStatus.Denied())
+ }
+}
+
+sealed class PermissionStatus {
+ data class Granted(val message: Int = R.string.permission_status_granted) : PermissionStatus()
+ data class Denied(val message: Int = R.string.permission_status_denied) : PermissionStatus()
+ data class Blocked(val message: Int = R.string.permission_status_blocked) : PermissionStatus()
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/util/ResourceHelper.kt b/app/src/main/java/se/bynumbers/daresayweather/util/ResourceHelper.kt
new file mode 100644
index 00000000..e609dd62
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/util/ResourceHelper.kt
@@ -0,0 +1,85 @@
+package se.bynumbers.daresayweather.util
+
+import android.content.Context
+import android.content.Context.MODE_PRIVATE
+import android.content.SharedPreferences
+import android.graphics.drawable.Drawable
+import android.util.Log
+import androidx.appcompat.content.res.AppCompatResources
+import androidx.core.text.isDigitsOnly
+import se.bynumbers.daresayweather.util.Constants.Companion.SP_DARESAY_WEATHER
+import se.bynumbers.daresayweather.util.Constants.Companion.SP_FAHRENHEIT
+import se.bynumbers.daresayweather.R
+import kotlin.math.roundToInt
+
+class ResourceHelper {
+
+ companion object {
+ private val TAG = "ResourceHelper"
+ fun getWeatherDrawableFromMap(context: Context, key: String): Drawable? {
+
+ Log.d(TAG, "Looking for resource with name: $key")
+ val r = context.resources
+
+ val packageName = context.packageName
+ val i = r.getIdentifier(key, "drawable", packageName)
+
+ return AppCompatResources.getDrawable(context, i)
+
+
+ }
+ fun setFahrenheit(on : Boolean, context : Context){
+ val sp = context.getSharedPreferences(SP_DARESAY_WEATHER,
+ MODE_PRIVATE
+ )
+ val editor = sp.edit()
+ editor.putBoolean(SP_FAHRENHEIT, on)
+ editor.apply()
+
+ }
+ fun toFahrenheit(temp : String) : String {
+ if(temp.isEmpty()) return "0"
+ val temp1 = temp.substringBefore(" ")
+
+ //TODO check for digits only (but note minus degre
+ if(temp1.isEmpty()) return "0"
+ val fahrenheit = (temp1.toDouble() * 9)/5 + 32
+
+ return fahrenheit.roundToInt().toString()
+ }
+ fun toCelsius(temp : String) : String {
+ if(temp.isEmpty()) return "0"
+ val temp1 = temp.substringBefore(" ")
+ if(temp1.isEmpty() || !temp1.isDigitsOnly()) return "0"
+ val celsius = ((temp1.toDouble()-32) * 5)/9
+
+ return celsius.roundToInt().toString()
+
+ }
+
+ fun getFahrenheitOrCelsius(context: Context): String? {
+
+
+ /* val r = context.resources
+
+ val packageName = context.packageName
+ val sp = context.getSharedPreferences("SP_DARESAY_WEATHER", MODE_PRIVATE)
+ val fahrenheit = sp.getBoolean("SP_FARENHEIT", false)
+
+ var id = R.drawable.wi_celsius
+ if (fahrenheit) {
+ id = R.drawable.wi_fahrenheit
+ }
+ Log.d(TAG, "Farenheit or celsius: $id")
+ return AppCompatResources.getDrawable(context, id)
+*/ val sp = context.getSharedPreferences(SP_DARESAY_WEATHER, MODE_PRIVATE)
+ val fahrenheit = sp.getBoolean(SP_FAHRENHEIT, false)
+
+ var ret ="\u00B0C"
+ if (fahrenheit) {
+ ret = "\u00B0F"
+ }
+ return ret
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/util/SingletonHolder.kt b/app/src/main/java/se/bynumbers/daresayweather/util/SingletonHolder.kt
new file mode 100644
index 00000000..33a88d21
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/util/SingletonHolder.kt
@@ -0,0 +1,38 @@
+package se.bynumbers.daresayweather.util
+
+// Convenience class that you only want to write once...
+// Use with, for example:
+// class HttpHelper private constructor(context: Context) {
+// init {
+// // Init using context argument
+// }
+//
+// companion object : SingletonHolder(::HttpHelper)
+//}
+// And then
+// HttpHelper.getInstance(context).doStuff()
+
+
+open class SingletonHolder(creator: (A) -> T) {
+ private var creator: ((A) -> T)? = creator
+ @Volatile private var instance: T? = null
+
+ fun getInstance(arg: A): T {
+ val i = instance
+ if (i != null) {
+ return i
+ }
+
+ return synchronized(this) {
+ val i2 = instance
+ if (i2 != null) {
+ i2
+ } else {
+ val created = creator!!(arg)
+ instance = created
+ creator = null
+ created
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/se/bynumbers/daresayweather/util/WeatherHelper.kt b/app/src/main/java/se/bynumbers/daresayweather/util/WeatherHelper.kt
new file mode 100644
index 00000000..693b5e5e
--- /dev/null
+++ b/app/src/main/java/se/bynumbers/daresayweather/util/WeatherHelper.kt
@@ -0,0 +1,69 @@
+package se.bynumbers.daresayweather.util
+
+import android.content.Context
+import android.content.res.Resources
+import android.util.Log
+import android.widget.Toast
+import androidx.lifecycle.LiveData
+
+import androidx.lifecycle.MutableLiveData
+import com.android.volley.Response
+import com.android.volley.VolleyError
+import com.google.gson.Gson
+import com.google.gson.JsonObject
+
+import se.bynumbers.daresayweather.model.LocationData
+import se.bynumbers.daresayweather.util.Constants.Companion.WEATHER_URL
+import se.bynumbers.daresayweather.R
+import java.io.InputStream
+import java.util.*
+
+//TODO Should refactor this to listener...when time.
+class WeatherDataHelper : MutableLiveData(), Response.Listener,
+
+ Response.ErrorListener {
+ var weatherData = MutableLiveData()
+
+ override fun onErrorResponse(error: VolleyError?) {
+
+ }
+
+ override fun onResponse(response: JsonObject) {
+ //if(response CurrentWeather){
+ //TODO!! Change type here (Fix Json->Pojo
+ weatherData.value = response
+ }
+ fun getForecast(context: Context, locationData : LocationData) : MutableLiveData {
+
+ val apiKey = getApiKey(context)
+
+ val url =
+ "${WEATHER_URL}?lat=${locationData.latitude}&lon=${locationData.longitude}&key=$apiKey"
+ HttpHelper.getInstance(context).getCurrentWeatherJson(context, url, this)
+ return weatherData
+ }
+
+ private fun getApiKey(
+ context: Context
+ ): String? {
+
+ val resources: Resources = context.resources
+ val TAG = "WeatherHelper"
+ //TODO: Cache api-key in SecurePrefs?
+ try {
+ val rawResource: InputStream = resources.openRawResource(R.raw.config)
+ val properties = Properties()
+ properties.load(rawResource)
+ return properties.getProperty(Constants.API_KEY)
+ } catch (e: Exception) {
+ Log.e(TAG, "Unable to aquire api-key: " + e.message)
+ Toast.makeText(context, context.getString(R.string.no_config_file), Toast.LENGTH_SHORT ).show()
+ }
+ return ""
+ }
+}
+
+
+
+
+
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 00000000..2b068d11
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_day.png b/app/src/main/res/drawable/bg_day.png
new file mode 100644
index 00000000..e652579b
Binary files /dev/null and b/app/src/main/res/drawable/bg_day.png differ
diff --git a/app/src/main/res/drawable/bg_night.png b/app/src/main/res/drawable/bg_night.png
new file mode 100644
index 00000000..fe07208f
Binary files /dev/null and b/app/src/main/res/drawable/bg_night.png differ
diff --git a/app/src/main/res/drawable/daresay_logo.png b/app/src/main/res/drawable/daresay_logo.png
new file mode 100644
index 00000000..f243ad58
Binary files /dev/null and b/app/src/main/res/drawable/daresay_logo.png differ
diff --git a/app/src/main/res/drawable/daresay_logo1024.png b/app/src/main/res/drawable/daresay_logo1024.png
new file mode 100644
index 00000000..38817e94
Binary files /dev/null and b/app/src/main/res/drawable/daresay_logo1024.png differ
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..a0ad202f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/wi_alien.xml b/app/src/main/res/drawable/wi_alien.xml
new file mode 100644
index 00000000..668dbb02
--- /dev/null
+++ b/app/src/main/res/drawable/wi_alien.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_celsius.xml b/app/src/main/res/drawable/wi_celsius.xml
new file mode 100644
index 00000000..5d05632d
--- /dev/null
+++ b/app/src/main/res/drawable/wi_celsius.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_cloud.xml b/app/src/main/res/drawable/wi_cloud.xml
new file mode 100644
index 00000000..f9e527cc
--- /dev/null
+++ b/app/src/main/res/drawable/wi_cloud.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_cloudy.xml b/app/src/main/res/drawable/wi_cloudy.xml
new file mode 100644
index 00000000..7c86114d
--- /dev/null
+++ b/app/src/main/res/drawable/wi_cloudy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_cloudy_gusts.xml b/app/src/main/res/drawable/wi_cloudy_gusts.xml
new file mode 100644
index 00000000..624ae9a2
--- /dev/null
+++ b/app/src/main/res/drawable/wi_cloudy_gusts.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_cloudy_windy.xml b/app/src/main/res/drawable/wi_cloudy_windy.xml
new file mode 100644
index 00000000..bcbb11c8
--- /dev/null
+++ b/app/src/main/res/drawable/wi_cloudy_windy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_cloudy.xml b/app/src/main/res/drawable/wi_day_cloudy.xml
new file mode 100644
index 00000000..bff6d42a
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_cloudy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_cloudy_gusts.xml b/app/src/main/res/drawable/wi_day_cloudy_gusts.xml
new file mode 100644
index 00000000..4a6f9e2a
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_cloudy_gusts.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_cloudy_high.xml b/app/src/main/res/drawable/wi_day_cloudy_high.xml
new file mode 100644
index 00000000..de43fcca
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_cloudy_high.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_cloudy_windy.xml b/app/src/main/res/drawable/wi_day_cloudy_windy.xml
new file mode 100644
index 00000000..cf949b12
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_cloudy_windy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_fog.xml b/app/src/main/res/drawable/wi_day_fog.xml
new file mode 100644
index 00000000..d1fdc1bb
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_fog.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_hail.xml b/app/src/main/res/drawable/wi_day_hail.xml
new file mode 100644
index 00000000..8f19a68a
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_hail.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_haze.xml b/app/src/main/res/drawable/wi_day_haze.xml
new file mode 100644
index 00000000..4b62a504
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_haze.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_light_wind.xml b/app/src/main/res/drawable/wi_day_light_wind.xml
new file mode 100644
index 00000000..a51cadd8
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_light_wind.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_lightning.xml b/app/src/main/res/drawable/wi_day_lightning.xml
new file mode 100644
index 00000000..e84c8e2b
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_lightning.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_rain.xml b/app/src/main/res/drawable/wi_day_rain.xml
new file mode 100644
index 00000000..3c43e14a
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_rain.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_rain_mix.xml b/app/src/main/res/drawable/wi_day_rain_mix.xml
new file mode 100644
index 00000000..a3e9b58e
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_rain_mix.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_rain_wind.xml b/app/src/main/res/drawable/wi_day_rain_wind.xml
new file mode 100644
index 00000000..6e232ef7
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_rain_wind.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_showers.xml b/app/src/main/res/drawable/wi_day_showers.xml
new file mode 100644
index 00000000..7ee1496f
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_showers.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_sleet.xml b/app/src/main/res/drawable/wi_day_sleet.xml
new file mode 100644
index 00000000..3dba5009
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_sleet.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_sleet_storm.xml b/app/src/main/res/drawable/wi_day_sleet_storm.xml
new file mode 100644
index 00000000..7a8461a7
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_sleet_storm.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_snow.xml b/app/src/main/res/drawable/wi_day_snow.xml
new file mode 100644
index 00000000..178231e9
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_snow.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_snow_thunderstorm.xml b/app/src/main/res/drawable/wi_day_snow_thunderstorm.xml
new file mode 100644
index 00000000..aa643604
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_snow_thunderstorm.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_snow_wind.xml b/app/src/main/res/drawable/wi_day_snow_wind.xml
new file mode 100644
index 00000000..6c8dcb50
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_snow_wind.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_sprinkle.xml b/app/src/main/res/drawable/wi_day_sprinkle.xml
new file mode 100644
index 00000000..b4888520
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_sprinkle.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_storm_showers.xml b/app/src/main/res/drawable/wi_day_storm_showers.xml
new file mode 100644
index 00000000..cc0784b3
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_storm_showers.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_sunny.xml b/app/src/main/res/drawable/wi_day_sunny.xml
new file mode 100644
index 00000000..838787bf
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_sunny.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_sunny_overcast.xml b/app/src/main/res/drawable/wi_day_sunny_overcast.xml
new file mode 100644
index 00000000..1549552f
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_sunny_overcast.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_thunderstorm.xml b/app/src/main/res/drawable/wi_day_thunderstorm.xml
new file mode 100644
index 00000000..83a46c64
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_thunderstorm.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_day_windy.xml b/app/src/main/res/drawable/wi_day_windy.xml
new file mode 100644
index 00000000..7fe17794
--- /dev/null
+++ b/app/src/main/res/drawable/wi_day_windy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_degrees.xml b/app/src/main/res/drawable/wi_degrees.xml
new file mode 100644
index 00000000..838e4aec
--- /dev/null
+++ b/app/src/main/res/drawable/wi_degrees.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_direction_down.xml b/app/src/main/res/drawable/wi_direction_down.xml
new file mode 100644
index 00000000..c48846bd
--- /dev/null
+++ b/app/src/main/res/drawable/wi_direction_down.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_direction_down_left.xml b/app/src/main/res/drawable/wi_direction_down_left.xml
new file mode 100644
index 00000000..8d6af957
--- /dev/null
+++ b/app/src/main/res/drawable/wi_direction_down_left.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_direction_down_right.xml b/app/src/main/res/drawable/wi_direction_down_right.xml
new file mode 100644
index 00000000..4c088267
--- /dev/null
+++ b/app/src/main/res/drawable/wi_direction_down_right.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_direction_left.xml b/app/src/main/res/drawable/wi_direction_left.xml
new file mode 100644
index 00000000..c7c5f38e
--- /dev/null
+++ b/app/src/main/res/drawable/wi_direction_left.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_direction_right.xml b/app/src/main/res/drawable/wi_direction_right.xml
new file mode 100644
index 00000000..4128d087
--- /dev/null
+++ b/app/src/main/res/drawable/wi_direction_right.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_direction_up.xml b/app/src/main/res/drawable/wi_direction_up.xml
new file mode 100644
index 00000000..ba79309f
--- /dev/null
+++ b/app/src/main/res/drawable/wi_direction_up.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_direction_up_left.xml b/app/src/main/res/drawable/wi_direction_up_left.xml
new file mode 100644
index 00000000..048d3a78
--- /dev/null
+++ b/app/src/main/res/drawable/wi_direction_up_left.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_direction_up_right.xml b/app/src/main/res/drawable/wi_direction_up_right.xml
new file mode 100644
index 00000000..244326f8
--- /dev/null
+++ b/app/src/main/res/drawable/wi_direction_up_right.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_dust.xml b/app/src/main/res/drawable/wi_dust.xml
new file mode 100644
index 00000000..7c25f685
--- /dev/null
+++ b/app/src/main/res/drawable/wi_dust.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_fahrenheit.xml b/app/src/main/res/drawable/wi_fahrenheit.xml
new file mode 100644
index 00000000..fccda550
--- /dev/null
+++ b/app/src/main/res/drawable/wi_fahrenheit.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_fog.xml b/app/src/main/res/drawable/wi_fog.xml
new file mode 100644
index 00000000..aa78fa7b
--- /dev/null
+++ b/app/src/main/res/drawable/wi_fog.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_hail.xml b/app/src/main/res/drawable/wi_hail.xml
new file mode 100644
index 00000000..ea804c06
--- /dev/null
+++ b/app/src/main/res/drawable/wi_hail.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_hot.xml b/app/src/main/res/drawable/wi_hot.xml
new file mode 100644
index 00000000..5c24303d
--- /dev/null
+++ b/app/src/main/res/drawable/wi_hot.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_lightning.xml b/app/src/main/res/drawable/wi_lightning.xml
new file mode 100644
index 00000000..ddfac178
--- /dev/null
+++ b/app/src/main/res/drawable/wi_lightning.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_na.xml b/app/src/main/res/drawable/wi_na.xml
new file mode 100644
index 00000000..96b86889
--- /dev/null
+++ b/app/src/main/res/drawable/wi_na.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_cloudy.xml b/app/src/main/res/drawable/wi_night_alt_cloudy.xml
new file mode 100644
index 00000000..acd7a864
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_cloudy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_cloudy_gusts.xml b/app/src/main/res/drawable/wi_night_alt_cloudy_gusts.xml
new file mode 100644
index 00000000..47aab846
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_cloudy_gusts.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_cloudy_windy.xml b/app/src/main/res/drawable/wi_night_alt_cloudy_windy.xml
new file mode 100644
index 00000000..d6fd8834
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_cloudy_windy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_hail.xml b/app/src/main/res/drawable/wi_night_alt_hail.xml
new file mode 100644
index 00000000..b0b32386
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_hail.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_lightning.xml b/app/src/main/res/drawable/wi_night_alt_lightning.xml
new file mode 100644
index 00000000..597fb460
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_lightning.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_partly_cloudy.xml b/app/src/main/res/drawable/wi_night_alt_partly_cloudy.xml
new file mode 100644
index 00000000..00dfb9ae
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_partly_cloudy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_rain.xml b/app/src/main/res/drawable/wi_night_alt_rain.xml
new file mode 100644
index 00000000..80643d00
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_rain.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_rain_mix.xml b/app/src/main/res/drawable/wi_night_alt_rain_mix.xml
new file mode 100644
index 00000000..a964499b
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_rain_mix.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_rain_wind.xml b/app/src/main/res/drawable/wi_night_alt_rain_wind.xml
new file mode 100644
index 00000000..38a4e48d
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_rain_wind.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_showers.xml b/app/src/main/res/drawable/wi_night_alt_showers.xml
new file mode 100644
index 00000000..a45af3ef
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_showers.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_sleet.xml b/app/src/main/res/drawable/wi_night_alt_sleet.xml
new file mode 100644
index 00000000..296262d7
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_sleet.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_sleet_storm.xml b/app/src/main/res/drawable/wi_night_alt_sleet_storm.xml
new file mode 100644
index 00000000..29c0b486
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_sleet_storm.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_snow.xml b/app/src/main/res/drawable/wi_night_alt_snow.xml
new file mode 100644
index 00000000..457db3f7
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_snow.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_snow_thunderstorm.xml b/app/src/main/res/drawable/wi_night_alt_snow_thunderstorm.xml
new file mode 100644
index 00000000..fd35b9a1
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_snow_thunderstorm.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_sprinkle.xml b/app/src/main/res/drawable/wi_night_alt_sprinkle.xml
new file mode 100644
index 00000000..f79e08a0
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_sprinkle.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_storm_showers.xml b/app/src/main/res/drawable/wi_night_alt_storm_showers.xml
new file mode 100644
index 00000000..fbf82484
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_storm_showers.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_alt_thunderstorm.xml b/app/src/main/res/drawable/wi_night_alt_thunderstorm.xml
new file mode 100644
index 00000000..6f30be66
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_alt_thunderstorm.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_clear.xml b/app/src/main/res/drawable/wi_night_clear.xml
new file mode 100644
index 00000000..2de4fa85
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_clear.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_cloudy.xml b/app/src/main/res/drawable/wi_night_cloudy.xml
new file mode 100644
index 00000000..2096581f
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_cloudy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_cloudy_gusts.xml b/app/src/main/res/drawable/wi_night_cloudy_gusts.xml
new file mode 100644
index 00000000..7557cb77
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_cloudy_gusts.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_cloudy_high.xml b/app/src/main/res/drawable/wi_night_cloudy_high.xml
new file mode 100644
index 00000000..0a556a75
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_cloudy_high.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_cloudy_windy.xml b/app/src/main/res/drawable/wi_night_cloudy_windy.xml
new file mode 100644
index 00000000..31eb30e4
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_cloudy_windy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_fog.xml b/app/src/main/res/drawable/wi_night_fog.xml
new file mode 100644
index 00000000..b6d757e8
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_fog.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_hail.xml b/app/src/main/res/drawable/wi_night_hail.xml
new file mode 100644
index 00000000..ae400f76
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_hail.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_lightning.xml b/app/src/main/res/drawable/wi_night_lightning.xml
new file mode 100644
index 00000000..6aca63bb
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_lightning.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_low_wind.xml b/app/src/main/res/drawable/wi_night_low_wind.xml
new file mode 100644
index 00000000..dbeef91f
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_low_wind.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_partly_cloudy.xml b/app/src/main/res/drawable/wi_night_partly_cloudy.xml
new file mode 100644
index 00000000..0a556a75
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_partly_cloudy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_rain.xml b/app/src/main/res/drawable/wi_night_rain.xml
new file mode 100644
index 00000000..edd18f40
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_rain.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_rain_mix.xml b/app/src/main/res/drawable/wi_night_rain_mix.xml
new file mode 100644
index 00000000..a44400f9
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_rain_mix.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_rain_wind.xml b/app/src/main/res/drawable/wi_night_rain_wind.xml
new file mode 100644
index 00000000..6ac2ab72
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_rain_wind.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_showers.xml b/app/src/main/res/drawable/wi_night_showers.xml
new file mode 100644
index 00000000..def54118
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_showers.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_sprinkle.xml b/app/src/main/res/drawable/wi_night_sprinkle.xml
new file mode 100644
index 00000000..2c2d0d5c
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_sprinkle.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_night_storm_showers.xml b/app/src/main/res/drawable/wi_night_storm_showers.xml
new file mode 100644
index 00000000..9a63eac1
--- /dev/null
+++ b/app/src/main/res/drawable/wi_night_storm_showers.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_rain.xml b/app/src/main/res/drawable/wi_rain.xml
new file mode 100644
index 00000000..40906ac0
--- /dev/null
+++ b/app/src/main/res/drawable/wi_rain.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_rain_mix.xml b/app/src/main/res/drawable/wi_rain_mix.xml
new file mode 100644
index 00000000..b5ebc264
--- /dev/null
+++ b/app/src/main/res/drawable/wi_rain_mix.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_refresh.xml b/app/src/main/res/drawable/wi_refresh.xml
new file mode 100644
index 00000000..ce6e1ab0
--- /dev/null
+++ b/app/src/main/res/drawable/wi_refresh.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_showers.xml b/app/src/main/res/drawable/wi_showers.xml
new file mode 100644
index 00000000..031b9e1f
--- /dev/null
+++ b/app/src/main/res/drawable/wi_showers.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_sleet.xml b/app/src/main/res/drawable/wi_sleet.xml
new file mode 100644
index 00000000..e7320651
--- /dev/null
+++ b/app/src/main/res/drawable/wi_sleet.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_snow.xml b/app/src/main/res/drawable/wi_snow.xml
new file mode 100644
index 00000000..cc9ef7b2
--- /dev/null
+++ b/app/src/main/res/drawable/wi_snow.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_sprinkle.xml b/app/src/main/res/drawable/wi_sprinkle.xml
new file mode 100644
index 00000000..667a8a7a
--- /dev/null
+++ b/app/src/main/res/drawable/wi_sprinkle.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_stars.xml b/app/src/main/res/drawable/wi_stars.xml
new file mode 100644
index 00000000..97362153
--- /dev/null
+++ b/app/src/main/res/drawable/wi_stars.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_storm_showers.xml b/app/src/main/res/drawable/wi_storm_showers.xml
new file mode 100644
index 00000000..b5f5925c
--- /dev/null
+++ b/app/src/main/res/drawable/wi_storm_showers.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_sunrise.xml b/app/src/main/res/drawable/wi_sunrise.xml
new file mode 100644
index 00000000..ef4158c6
--- /dev/null
+++ b/app/src/main/res/drawable/wi_sunrise.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_sunset.xml b/app/src/main/res/drawable/wi_sunset.xml
new file mode 100644
index 00000000..b0557004
--- /dev/null
+++ b/app/src/main/res/drawable/wi_sunset.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wi_thunderstorm.xml b/app/src/main/res/drawable/wi_thunderstorm.xml
new file mode 100644
index 00000000..2b9235f5
--- /dev/null
+++ b/app/src/main/res/drawable/wi_thunderstorm.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/font/libre_franklin_bold.ttf b/app/src/main/res/font/libre_franklin_bold.ttf
new file mode 100644
index 00000000..4ed839d0
Binary files /dev/null and b/app/src/main/res/font/libre_franklin_bold.ttf differ
diff --git a/app/src/main/res/font/libre_franklin_medium.ttf b/app/src/main/res/font/libre_franklin_medium.ttf
new file mode 100644
index 00000000..4fe2cdbf
Binary files /dev/null and b/app/src/main/res/font/libre_franklin_medium.ttf differ
diff --git a/app/src/main/res/font/libre_franklin_regular.ttf b/app/src/main/res/font/libre_franklin_regular.ttf
new file mode 100644
index 00000000..0bc60245
Binary files /dev/null and b/app/src/main/res/font/libre_franklin_regular.ttf differ
diff --git a/app/src/main/res/layout-land/fragment_current_weather.xml b/app/src/main/res/layout-land/fragment_current_weather.xml
new file mode 100644
index 00000000..0f4fef5e
--- /dev/null
+++ b/app/src/main/res/layout-land/fragment_current_weather.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..af0d0bf9
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_current_weather.xml b/app/src/main/res/layout/fragment_current_weather.xml
new file mode 100644
index 00000000..1fec6e3d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_current_weather.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_forecast.xml b/app/src/main/res/layout/fragment_forecast.xml
new file mode 100644
index 00000000..224edb0f
--- /dev/null
+++ b/app/src/main/res/layout/fragment_forecast.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..247d1606
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..61da551c
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..938b2c01
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..db5080a7
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..28d58f6c
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..da31a871
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..96ac0085
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..b216f2d3
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..dd324535
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..e96783cc
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 00000000..63fc8164
--- /dev/null
+++ b/app/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 64dp
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..62953b57
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #000000
+ #000000
+ #FFFFFF
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..1927bee3
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,8 @@
+
+
+ 16dp
+ 16dp
+ 16dp
+ 16dp
+ 8dp
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..97d5f36b
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,15 @@
+
+ Daresay Weather
+ Current
+ Forecast
+ Location permission granted
+ Location permission denied
+ Location permission blocked
+ Network error: check network connection
+ Permission not granted for using location. Please check settings.
+ Hello! We must have your permission to use your location. If not, the app is very boring.
+ Could not aquire api-key from file. Does config.properties exist?
+ Location
+ Fahrenheit
+
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..c111ddb6
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/weathericons.xml b/app/src/main/res/values/weathericons.xml
new file mode 100644
index 00000000..cce39b37
--- /dev/null
+++ b/app/src/main/res/values/weathericons.xml
@@ -0,0 +1,601 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/test/java/se/bynumbers/daresayweather/ExampleUnitTest.kt b/app/src/test/java/se/bynumbers/daresayweather/ExampleUnitTest.kt
new file mode 100644
index 00000000..2e46b1f6
--- /dev/null
+++ b/app/src/test/java/se/bynumbers/daresayweather/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package se.bynumbers.daresayweather
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 00000000..c5ee20e0
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,30 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ ext.kotlin_version = '1.3.72'
+ repositories {
+ google()
+ jcenter()
+
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.6.3'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 00000000..23339e0d
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f6b961fd
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..af0a2305
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Sat May 23 08:07:18 CEST 2020
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 00000000..cccdd3d5
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 00000000..f9553162
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 00000000..51d97bc9
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name='Daresay Weather'
+include ':app'