From 1644fb768285f080e84871e9e9bff5edf86da4b2 Mon Sep 17 00:00:00 2001 From: Tommaso Berlose Date: Tue, 6 Oct 2020 18:11:53 +0200 Subject: [PATCH] Update the providers --- app/src/main/AndroidManifest.xml | 1 + .../anotherwidget/global/Constants.kt | 8 +- .../anotherwidget/global/Preferences.kt | 6 +- .../anotherwidget/helpers/WeatherHelper.kt | 138 +++++++++++---- .../network/WeatherNetworkApi.kt | 164 +++++++++++++++++- .../anotherwidget/network/api/ApiServices.kt | 74 ++++++++ .../network/api/WeatherGovApiService.kt | 13 -- .../repository/AccuweatherRepository.kt | 25 +++ .../network/repository/HereRepository.kt | 26 +++ .../repository/WeatherApiRepository.kt | 26 +++ .../repository/WeatherGovRepository.kt | 15 +- .../repository/WeatherbitRepository.kt | 26 +++ .../network/repository/YrRepository.kt | 26 +++ .../receivers/WeatherReceiver.kt | 5 +- .../ui/activities/WeatherProviderActivity.kt | 110 ++++++++---- .../ui/fragments/MainFragment.kt | 5 +- .../ui/fragments/WeatherTabFragment.kt | 4 +- .../ui/viewmodels/MainViewModel.kt | 2 +- .../res/layout/activity_weather_provider.xml | 18 ++ app/src/main/res/values/strings.xml | 41 ++--- 20 files changed, 587 insertions(+), 146 deletions(-) create mode 100644 app/src/main/java/com/tommasoberlose/anotherwidget/network/api/ApiServices.kt delete mode 100644 app/src/main/java/com/tommasoberlose/anotherwidget/network/api/WeatherGovApiService.kt create mode 100644 app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/AccuweatherRepository.kt create mode 100644 app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/HereRepository.kt create mode 100644 app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherApiRepository.kt create mode 100644 app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherbitRepository.kt create mode 100644 app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/YrRepository.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index db8528f..b6b658c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,6 +22,7 @@ android:name=".AWApplication" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" + android:usesCleartextTraffic="true" android:theme="@style/AppTheme" tools:ignore="LockedOrientationActivity"> diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt index 1af276e..75b5dd5 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt @@ -42,15 +42,11 @@ object Constants { enum class WeatherProvider(val value: Int) { OPEN_WEATHER(0), WEATHER_BIT(1), - FORECA(2), + WEATHER_API(2), HERE(3), ACCUWEATHER(4), WEATHER_GOV(5), - YR(6), - SMHI(7), - WEATHER_CA(8), - BOM(9), - METEOFRANCE(10); + YR(6); companion object { private val map = WeatherProvider.values().associateBy(WeatherProvider::value) diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/global/Preferences.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/global/Preferences.kt index 1d0d0e2..90c2a71 100755 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/global/Preferences.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/global/Preferences.kt @@ -38,7 +38,11 @@ object Preferences : KotprefModel() { var calendarAppPackage by stringPref(key = "PREF_CALENDAR_APP_PACKAGE", default = "") var weatherAppName by stringPref(key = "PREF_WEATHER_APP_NAME", default = "") var weatherAppPackage by stringPref(key = "PREF_WEATHER_APP_PACKAGE", default = "") - var weatherProviderApi by stringPref(key = "PREF_WEATHER_PROVIDER_API_KEY", default = "") + var weatherProviderApiOpen by stringPref(key = "PREF_WEATHER_PROVIDER_API_KEY", default = "") + var weatherProviderApiHere by stringPref(default = "") + var weatherProviderApiWeatherApi by stringPref(default = "") + var weatherProviderApiWeatherBit by stringPref(default = "") + var weatherProviderApiAccuweather by stringPref(default = "") var weatherProvider by intPref(default = Constants.WeatherProvider.OPEN_WEATHER.value) var weatherProviderError by stringPref(default = "") var weatherProviderLocationError by stringPref(default = "") diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt index 5c60b3d..1346167 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt @@ -52,15 +52,11 @@ object WeatherHelper { return context.getString(when(provider) { Constants.WeatherProvider.OPEN_WEATHER -> R.string.settings_weather_provider_open_weather Constants.WeatherProvider.WEATHER_BIT -> R.string.settings_weather_provider_weatherbit - Constants.WeatherProvider.FORECA -> R.string.settings_weather_provider_foreca + Constants.WeatherProvider.WEATHER_API -> R.string.settings_weather_provider_weather_api Constants.WeatherProvider.HERE -> R.string.settings_weather_provider_here Constants.WeatherProvider.ACCUWEATHER -> R.string.settings_weather_provider_accuweather Constants.WeatherProvider.WEATHER_GOV -> R.string.settings_weather_provider_weather_gov Constants.WeatherProvider.YR -> R.string.settings_weather_provider_yr - Constants.WeatherProvider.SMHI -> R.string.settings_weather_provider_smhi - Constants.WeatherProvider.WEATHER_CA -> R.string.settings_weather_provider_weather_ca - Constants.WeatherProvider.BOM -> R.string.settings_weather_provider_bom - Constants.WeatherProvider.METEOFRANCE -> R.string.settings_weather_provider_meteofrance }) } @@ -68,15 +64,11 @@ object WeatherHelper { return context.getString(when(Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) { Constants.WeatherProvider.OPEN_WEATHER -> R.string.action_open_provider_open_weather Constants.WeatherProvider.WEATHER_BIT -> R.string.action_open_provider_weatherbit - Constants.WeatherProvider.FORECA -> R.string.action_open_provider_foreca + Constants.WeatherProvider.WEATHER_API -> R.string.action_open_provider_weatherapi Constants.WeatherProvider.HERE -> R.string.action_open_provider_here Constants.WeatherProvider.ACCUWEATHER -> R.string.action_open_provider_accuweather Constants.WeatherProvider.WEATHER_GOV -> R.string.action_open_provider_weather_gov Constants.WeatherProvider.YR -> R.string.action_open_provider_yr - Constants.WeatherProvider.SMHI -> R.string.action_open_provider_smhi - Constants.WeatherProvider.WEATHER_CA -> R.string.action_open_provider_weather_ca - Constants.WeatherProvider.BOM -> R.string.action_open_provider_bom - Constants.WeatherProvider.METEOFRANCE -> R.string.action_open_provider_meteofrance else -> R.string.nothing }) } @@ -85,15 +77,11 @@ object WeatherHelper { return context.getString(when(Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) { Constants.WeatherProvider.OPEN_WEATHER -> R.string.weather_provider_info_open_weather_title Constants.WeatherProvider.WEATHER_BIT -> R.string.weather_provider_info_weatherbit_title - Constants.WeatherProvider.FORECA -> R.string.weather_provider_info_foreca_title + Constants.WeatherProvider.WEATHER_API -> R.string.weather_provider_info_weatherapi_title Constants.WeatherProvider.HERE -> R.string.weather_provider_info_here_title Constants.WeatherProvider.ACCUWEATHER -> R.string.weather_provider_info_accuweather_title Constants.WeatherProvider.WEATHER_GOV -> R.string.weather_provider_info_weather_gov_title Constants.WeatherProvider.YR -> R.string.weather_provider_info_yr_title - Constants.WeatherProvider.SMHI -> R.string.weather_provider_info_smhi_title - Constants.WeatherProvider.WEATHER_CA -> R.string.weather_provider_info_weather_ca_title - Constants.WeatherProvider.BOM -> R.string.weather_provider_info_bom_title - Constants.WeatherProvider.METEOFRANCE -> R.string.weather_provider_info_meteofrance_title else -> R.string.nothing }) } @@ -102,15 +90,11 @@ object WeatherHelper { return context.getString(when(Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) { Constants.WeatherProvider.OPEN_WEATHER -> R.string.weather_provider_info_open_weather_subtitle Constants.WeatherProvider.WEATHER_BIT -> R.string.weather_provider_info_weatherbit_subtitle - Constants.WeatherProvider.FORECA -> R.string.weather_provider_info_foreca_subtitle + Constants.WeatherProvider.WEATHER_API -> R.string.weather_provider_info_weatherapi_subtitle Constants.WeatherProvider.HERE -> R.string.weather_provider_info_here_subtitle Constants.WeatherProvider.ACCUWEATHER -> R.string.weather_provider_info_accuweather_subtitle Constants.WeatherProvider.WEATHER_GOV -> R.string.weather_provider_info_weather_gov_subtitle Constants.WeatherProvider.YR -> R.string.weather_provider_info_yr_subtitle - Constants.WeatherProvider.SMHI -> R.string.weather_provider_info_smhi_subtitle - Constants.WeatherProvider.WEATHER_CA -> R.string.weather_provider_info_weather_ca_subtitle - Constants.WeatherProvider.BOM -> R.string.weather_provider_info_bom_subtitle - Constants.WeatherProvider.METEOFRANCE -> R.string.weather_provider_info_meteofrance_subtitle else -> R.string.nothing }) } @@ -118,16 +102,12 @@ object WeatherHelper { fun getProviderLink(): String { return when(Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) { Constants.WeatherProvider.OPEN_WEATHER -> "https://home.openweathermap.org/users/sign_up" - Constants.WeatherProvider.WEATHER_BIT -> "" - Constants.WeatherProvider.FORECA -> "" - Constants.WeatherProvider.HERE -> "" - Constants.WeatherProvider.ACCUWEATHER -> "" - Constants.WeatherProvider.WEATHER_GOV -> "" - Constants.WeatherProvider.YR -> "" - Constants.WeatherProvider.SMHI -> "" - Constants.WeatherProvider.WEATHER_CA -> "" - Constants.WeatherProvider.BOM -> "" - Constants.WeatherProvider.METEOFRANCE -> "" + Constants.WeatherProvider.WEATHER_BIT -> "https://www.weatherbit.io/account/create" + Constants.WeatherProvider.WEATHER_API -> "https://www.weatherapi.com/signup.aspx" + Constants.WeatherProvider.HERE -> "https://developer.here.com/sign-up?create=Freemium-Basic&keepState=true&step=account" + Constants.WeatherProvider.ACCUWEATHER -> "https://developer.accuweather.com/user/register" + Constants.WeatherProvider.WEATHER_GOV -> "http://www.weather.gov/" + Constants.WeatherProvider.YR -> "https://www.yr.no/" else -> "" } } @@ -135,16 +115,12 @@ object WeatherHelper { fun isKeyRequired(): Boolean = when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) { Constants.WeatherProvider.OPEN_WEATHER, Constants.WeatherProvider.WEATHER_BIT, - Constants.WeatherProvider.FORECA, + Constants.WeatherProvider.WEATHER_API, Constants.WeatherProvider.HERE, - Constants.WeatherProvider.ACCUWEATHER, - Constants.WeatherProvider.YR, - Constants.WeatherProvider.SMHI, - Constants.WeatherProvider.WEATHER_CA, - Constants.WeatherProvider.BOM, - Constants.WeatherProvider.METEOFRANCE -> true + Constants.WeatherProvider.ACCUWEATHER -> true - Constants.WeatherProvider.WEATHER_GOV -> false + Constants.WeatherProvider.WEATHER_GOV, + Constants.WeatherProvider.YR -> false else -> true } @@ -389,4 +365,90 @@ object WeatherHelper { else -> "" } + if (isDaytime) "d" else "n" + fun getWeatherBitIcon(iconString: String): String = when { + iconString.contains("t01") -> "11" + iconString.contains("t02") -> "09" + iconString.contains("t03") -> "09" + iconString.contains("t04") -> "09" + iconString.contains("t05") -> "09" + iconString.contains("d01") -> "10" + iconString.contains("d02") -> "10" + iconString.contains("d03") -> "10" + iconString.contains("r01") -> "10" + iconString.contains("r02") -> "10" + iconString.contains("r03") -> "10" + iconString.contains("f01") -> "10" + iconString.contains("r04") -> "10" + iconString.contains("r05") -> "10" + iconString.contains("r06") -> "10" + iconString.contains("s01") -> "13" + iconString.contains("s02") -> "13" + iconString.contains("s03") -> "13" + iconString.contains("s04") -> "81" + iconString.contains("s05") -> "90" + iconString.contains("s06") -> "13" + iconString.contains("a01") -> "82" + iconString.contains("a02") -> "82" + iconString.contains("a03") -> "82" + iconString.contains("a04") -> "82" + iconString.contains("a05") -> "82" + iconString.contains("a06") -> "82" + iconString.contains("c01") -> "01" + iconString.contains("c02") -> "02" + iconString.contains("c03") -> "04" + iconString.contains("c04") -> "04" + else -> "" + } + if (iconString.contains("d")) "d" else "n" + + fun getWeatherApiIcon(icon: Int, isDaytime: Boolean): String = when(icon) { + 1000 -> "01" + 1003 -> "02" + 1006 -> "03" + 1009 -> "04" + 1030 -> "82" + 1063 -> "10" + 1066 -> "10" + 1069 -> "10" + 1072 -> "81" + 1087 -> "11" + 1114 -> "13" + 1117 -> "09" + 1135 -> "82" + 1147 -> "82" + 1150 -> "10" + 1153 -> "10" + 1168 -> "10" + 1171 -> "10" + 1180 -> "10" + 1183 -> "10" + 1186 -> "10" + 1189 -> "10" + 1192 -> "10" + 1195 -> "10" + 1198 -> "81" + 1201 -> "81" + 1204 -> "13" + 1207 -> "13" + 1210 -> "13" + 1213 -> "13" + 1216 -> "13" + 1219 -> "13" + 1222 -> "13" + 1225 -> "13" + 1237 -> "13" + 1240 -> "10" + 1243 -> "10" + 1246 -> "10" + 1249 -> "13" + 1252 -> "13" + 1255 -> "13" + 1258 -> "13" + 1261 -> "13" + 1264 -> "13" + 1273 -> "09" + 1276 -> "09" + 1279 -> "13" + 1282 -> "13" + else -> "" + } + if (isDaytime) "d" else "n" } \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/network/WeatherNetworkApi.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/network/WeatherNetworkApi.kt index c01d796..ead423d 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/network/WeatherNetworkApi.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/network/WeatherNetworkApi.kt @@ -13,12 +13,11 @@ import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.helpers.WeatherHelper -import com.tommasoberlose.anotherwidget.network.repository.WeatherGovRepository +import com.tommasoberlose.anotherwidget.network.repository.* import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import org.greenrobot.eventbus.EventBus import java.lang.Exception @@ -32,6 +31,11 @@ class WeatherNetworkApi(val context: Context) { when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) { Constants.WeatherProvider.OPEN_WEATHER -> useOpenWeatherMap(context) Constants.WeatherProvider.WEATHER_GOV -> useWeatherGov(context) + Constants.WeatherProvider.WEATHER_BIT -> useWeatherBitProvider(context) + Constants.WeatherProvider.WEATHER_API -> useWeatherApiProvider(context) + Constants.WeatherProvider.HERE -> useHereProvider(context) + Constants.WeatherProvider.ACCUWEATHER -> useAccuweatherProvider(context) + Constants.WeatherProvider.YR -> useYrProvider(context) } } else { WeatherHelper.removeWeather( @@ -41,8 +45,8 @@ class WeatherNetworkApi(val context: Context) { } private fun useOpenWeatherMap(context: Context) { - if (Preferences.weatherProviderApi != "" ) { - val helper = OpenWeatherMapHelper(Preferences.weatherProviderApi) + if (Preferences.weatherProviderApiOpen != "" ) { + val helper = OpenWeatherMapHelper(Preferences.weatherProviderApiOpen) helper.setUnits(if (Preferences.weatherTempUnit == "F") Units.IMPERIAL else Units.METRIC) helper.getCurrentWeatherByGeoCoordinates(Preferences.customLocationLat.toDouble(), Preferences.customLocationLon.toDouble(), object : CurrentWeatherCallback { @@ -118,21 +122,163 @@ class WeatherNetworkApi(val context: Context) { } } } catch(ex: Exception) { - } } is NetworkResponse.ServerError -> { if (pointsResponse.body?.containsKey("status") == true && (pointsResponse.body?.get("status") as Double).toInt() == 404) { Preferences.weatherProviderError = "" Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_wrong_location) - - WeatherHelper.removeWeather( - context - ) } + + WeatherHelper.removeWeather( + context + ) } } } } + + private fun useHereProvider(context: Context) { + CoroutineScope(Dispatchers.IO).launch { + val repository = HereRepository() + + when (val response = repository.getWeather()) { + is NetworkResponse.Success -> { + try { + Log.d("ciao - here", response.body.toString()) + } catch(ex: Exception) { + } + } + is NetworkResponse.ServerError -> { + WeatherHelper.removeWeather( + context + ) + } + } + } + } + + private fun useWeatherBitProvider(context: Context) { + CoroutineScope(Dispatchers.IO).launch { + val repository = WeatherbitRepository() + + when (val response = repository.getWeather()) { + is NetworkResponse.Success -> { + try { + val data = response.body["data"] as List>? + data?.first()?.let { + val temp = it["temp"] as Double + val weatherInfo = it["weather"] as LinkedTreeMap + val iconCode = weatherInfo["icon"] as String + + Preferences.weatherTemp = temp.toFloat() + Preferences.weatherIcon = WeatherHelper.getWeatherBitIcon(iconCode) + Preferences.weatherRealTempUnit = Preferences.weatherTempUnit + MainWidget.updateWidget(context) + + EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent()) + } + } catch(ex: Exception) { + } + } + is NetworkResponse.ServerError -> { + when (response.code) { + 403 -> { + Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_invalid_key) + } + } + WeatherHelper.removeWeather( + context + ) + } + } + } + } + + private fun useWeatherApiProvider(context: Context) { + CoroutineScope(Dispatchers.IO).launch { + val repository = WeatherApiRepository() + + when (val response = repository.getWeather()) { + is NetworkResponse.Success -> { + try { + val current = response.body["current"] as LinkedTreeMap? + current?.let { + val tempC = current["temp_c"] as Double + val tempF = current["temp_f"] as Double + val isDay = current["is_day"] as Double + val condition = current["condition"] as LinkedTreeMap + val iconCode = condition["code"] as Double + + Preferences.weatherTemp = if (Preferences.weatherTempUnit == "F") tempF.toFloat() else tempC.toFloat() + Preferences.weatherIcon = WeatherHelper.getWeatherApiIcon(iconCode.toInt(), isDay.toInt() == 1) + Preferences.weatherRealTempUnit = Preferences.weatherTempUnit + MainWidget.updateWidget(context) + + EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent()) + } + } catch(ex: Exception) { + Log.d("ciao", ex.localizedMessage) + } + } + is NetworkResponse.ServerError -> { + when (response.code) { + 401 -> { + Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_invalid_key) + } + 403 -> { + Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_expired_key) + } + } + + WeatherHelper.removeWeather( + context + ) + } + } + } + } + + private fun useAccuweatherProvider(context: Context) { + CoroutineScope(Dispatchers.IO).launch { + val repository = AccuweatherRepository() + +// when (val response = repository.getWeather()) { +// is NetworkResponse.Success -> { +// try { +// Log.d("ciao", response.body.toString()) +// } catch(ex: Exception) { +// +// } +// } +// is NetworkResponse.ServerError -> { +// WeatherHelper.removeWeather( +// context +// ) +// } +// } + } + } + + private fun useYrProvider(context: Context) { + CoroutineScope(Dispatchers.IO).launch { + val repository = YrRepository() + + when (val response = repository.getWeather()) { + is NetworkResponse.Success -> { + try { + Log.d("ciao - yr", response.body.toString()) + } catch(ex: Exception) { + + } + } + is NetworkResponse.ServerError -> { + WeatherHelper.removeWeather( + context + ) + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/network/api/ApiServices.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/network/api/ApiServices.kt new file mode 100644 index 0000000..4c8c2f2 --- /dev/null +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/network/api/ApiServices.kt @@ -0,0 +1,74 @@ +package com.tommasoberlose.anotherwidget.network.api + +import com.haroldadmin.cnradapter.NetworkResponse +import retrofit2.http.* + +object ApiServices { + interface WeatherGovApiService { + @Headers("User-Agent: (Another Widget, tommaso.berlose@gmail.com)") + @GET("points/{latitude},{longitude}") + suspend fun getGridPoints( + @Path("latitude") latitude: String, + @Path("longitude") longitude: String + ): NetworkResponse, HashMap> + + @Headers("User-Agent: (Another Widget, tommaso.berlose@gmail.com)") + @GET("gridpoints/{gridId}/{gridX},{gridY}/forecast") + suspend fun getWeather( + @Path("gridId") gridId: String, + @Path("gridX") gridX: Int, + @Path("gridY") gridY: Int, + @Query("units") unit: String + ): NetworkResponse, HashMap> + } + + interface WeatherBitService { + @GET("current") + suspend fun getWeather( + @Query("key") key: String, + @Query("lat") lat: String, + @Query("lon") lon: String, + @Query("units") units: String, + ): NetworkResponse, HashMap> + } + + interface WeatherApiService { + @Headers("Accept: application/json") + @GET("current.json") + suspend fun getWeather( + @Query("key") key: String, + @Query("q") location: String, + ): NetworkResponse, HashMap> + } + + interface HereService { + @GET("report.json") + suspend fun getWeather( + @Query("apiKey") apiKey: String, + @Query("latitude") latitude: String, + @Query("longitude") longitude: String, + @Query("product") product: String, + @Query("oneobservation") oneobservation: Boolean, + @Query("metric") metric: Boolean, + ): NetworkResponse, HashMap> + } + + interface AccuweatherService { + @GET("") + suspend fun getWeather( + @Path("gridId") gridId: String, + @Path("gridX") gridX: Int, + @Path("gridY") gridY: Int, + @Query("units") unit: String + ): NetworkResponse, HashMap> + } + + interface YrService { + @Headers("User-Agent: AnotherWidget") + @GET("compact.json") + suspend fun getWeather( + @Query("lat") lat: String, + @Query("lon") lon: String, + ): NetworkResponse, HashMap> + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/network/api/WeatherGovApiService.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/network/api/WeatherGovApiService.kt deleted file mode 100644 index 2fd9dd0..0000000 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/network/api/WeatherGovApiService.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.tommasoberlose.anotherwidget.network.api - -import com.haroldadmin.cnradapter.NetworkResponse -import retrofit2.http.* - -interface WeatherGovApiService { - @GET("points/{latitude},{longitude}") - suspend fun getGridPoints(@Path("latitude") latitude: String, @Path("longitude") longitude: String): NetworkResponse, HashMap> - - @Headers("User-Agent: (Another Widget, tommaso.berlose@gmail.com)") - @GET("gridpoints/{gridId}/{gridX},{gridY}/forecast") - suspend fun getWeather(@Path("gridId") gridId: String, @Path("gridX") gridX: Int, @Path("gridY") gridY: Int, @Query("units") unit: String): NetworkResponse, HashMap> -} \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/AccuweatherRepository.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/AccuweatherRepository.kt new file mode 100644 index 0000000..5c24196 --- /dev/null +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/AccuweatherRepository.kt @@ -0,0 +1,25 @@ +package com.tommasoberlose.anotherwidget.network.repository + +import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory +import com.tommasoberlose.anotherwidget.network.api.ApiServices +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +class AccuweatherRepository { + + /* ACCUWEATHER */ + private val apiServiceAccu: ApiServices.AccuweatherService = getRetrofit().create(ApiServices.AccuweatherService::class.java) + suspend fun getWeather(): Nothing = TODO() + + companion object { + private const val BASE_URL_ACCU = "" + + private fun getRetrofit(): Retrofit { + return Retrofit.Builder() + .baseUrl(BASE_URL_ACCU) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(NetworkResponseAdapterFactory()) + .build() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/HereRepository.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/HereRepository.kt new file mode 100644 index 0000000..58290e0 --- /dev/null +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/HereRepository.kt @@ -0,0 +1,26 @@ +package com.tommasoberlose.anotherwidget.network.repository + +import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory +import com.tommasoberlose.anotherwidget.global.Preferences +import com.tommasoberlose.anotherwidget.network.api.ApiServices +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +class HereRepository { + + /* HERE */ + private val apiServiceHere: ApiServices.HereService = getRetrofit().create(ApiServices.HereService::class.java) + suspend fun getWeather() = apiServiceHere.getWeather(Preferences.weatherProviderApiHere, Preferences.customLocationLat, Preferences.customLocationLon, "observation", true, Preferences.weatherTempUnit != "F") + + companion object { + private const val BASE_URL_HERE = "https://weather.ls.hereapi.com/weather/1.0/" + + private fun getRetrofit(): Retrofit { + return Retrofit.Builder() + .baseUrl(BASE_URL_HERE) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(NetworkResponseAdapterFactory()) + .build() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherApiRepository.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherApiRepository.kt new file mode 100644 index 0000000..b51ed18 --- /dev/null +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherApiRepository.kt @@ -0,0 +1,26 @@ +package com.tommasoberlose.anotherwidget.network.repository + +import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory +import com.tommasoberlose.anotherwidget.global.Preferences +import com.tommasoberlose.anotherwidget.network.api.ApiServices +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +class WeatherApiRepository { + + /* WEATHER API*/ + private val apiServiceApi: ApiServices.WeatherApiService = getRetrofit().create(ApiServices.WeatherApiService::class.java) + suspend fun getWeather() = apiServiceApi.getWeather(Preferences.weatherProviderApiWeatherApi, "${Preferences.customLocationLat},${Preferences.customLocationLon}") + + companion object { + private const val BASE_URL_API = "http://api.weatherapi.com/v1/" + + private fun getRetrofit(): Retrofit { + return Retrofit.Builder() + .baseUrl(BASE_URL_API) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(NetworkResponseAdapterFactory()) + .build() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherGovRepository.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherGovRepository.kt index 6c0bf11..dd4c024 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherGovRepository.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherGovRepository.kt @@ -1,22 +1,23 @@ package com.tommasoberlose.anotherwidget.network.repository import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory -import com.tommasoberlose.anotherwidget.network.api.WeatherGovApiService +import com.tommasoberlose.anotherwidget.network.api.ApiServices import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory class WeatherGovRepository { - private val apiService: WeatherGovApiService = getRetrofit().create(WeatherGovApiService::class.java) - - suspend fun getGridPoints(latitude: String, longitude: String) = apiService.getGridPoints(latitude, longitude) - suspend fun getWeather(gridId: String, gridX: Double, gridY: Double, unit: String) = apiService.getWeather(gridId, gridX.toInt(), gridY.toInt(), unit) + /* WEATHER GOV*/ + private val apiServiceGov: ApiServices.WeatherGovApiService = getRetrofit().create(ApiServices.WeatherGovApiService::class.java) + suspend fun getGridPoints(latitude: String, longitude: String) = apiServiceGov.getGridPoints(latitude, longitude) + suspend fun getWeather(gridId: String, gridX: Double, gridY: Double, unit: String) = apiServiceGov.getWeather(gridId, gridX.toInt(), gridY.toInt(), unit) companion object { - private const val BASE_URL = "https://api.weather.gov/" + private const val BASE_URL_GOV = "https://api.weather.gov/" + private fun getRetrofit(): Retrofit { return Retrofit.Builder() - .baseUrl(BASE_URL) + .baseUrl(BASE_URL_GOV) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(NetworkResponseAdapterFactory()) .build() diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherbitRepository.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherbitRepository.kt new file mode 100644 index 0000000..b94dc4a --- /dev/null +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/WeatherbitRepository.kt @@ -0,0 +1,26 @@ +package com.tommasoberlose.anotherwidget.network.repository + +import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory +import com.tommasoberlose.anotherwidget.global.Preferences +import com.tommasoberlose.anotherwidget.network.api.ApiServices +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +class WeatherbitRepository { + + /* BIT */ + private val apiServiceBit: ApiServices.WeatherBitService = getRetrofit().create(ApiServices.WeatherBitService::class.java) + suspend fun getWeather() = apiServiceBit.getWeather(Preferences.weatherProviderApiWeatherBit, Preferences.customLocationLat, Preferences.customLocationLon, if (Preferences.weatherTempUnit == "F") "I" else "M") + + companion object { + private const val BASE_URL_BIT = "https://api.weatherbit.io/v2.0/" + + private fun getRetrofit(): Retrofit { + return Retrofit.Builder() + .baseUrl(BASE_URL_BIT) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(NetworkResponseAdapterFactory()) + .build() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/YrRepository.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/YrRepository.kt new file mode 100644 index 0000000..fbf55e8 --- /dev/null +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/network/repository/YrRepository.kt @@ -0,0 +1,26 @@ +package com.tommasoberlose.anotherwidget.network.repository + +import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory +import com.tommasoberlose.anotherwidget.global.Preferences +import com.tommasoberlose.anotherwidget.network.api.ApiServices +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +class YrRepository { + + /* YR */ + private val apiServiceYr: ApiServices.YrService = getRetrofit().create(ApiServices.YrService::class.java) + suspend fun getWeather() = apiServiceYr.getWeather(Preferences.customLocationLat, Preferences.customLocationLon) + + companion object { + private const val BASE_URL_YR = "https://api.met.no/weatherapi/locationforecast/2.0/" + + private fun getRetrofit(): Retrofit { + return Retrofit.Builder() + .baseUrl(BASE_URL_YR) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(NetworkResponseAdapterFactory()) + .build() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/receivers/WeatherReceiver.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/receivers/WeatherReceiver.kt index 8d6a826..e0114fa 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/receivers/WeatherReceiver.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/receivers/WeatherReceiver.kt @@ -5,7 +5,6 @@ import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.util.Log import com.tommasoberlose.anotherwidget.global.Actions import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.helpers.WeatherHelper @@ -33,7 +32,7 @@ class WeatherReceiver : BroadcastReceiver() { fun setUpdates(context: Context) { removeUpdates(context) - if (Preferences.showWeather && Preferences.weatherProviderApi != "") { + if (Preferences.showWeather) { val interval = MINUTE * when (Preferences.weatherRefreshPeriod) { 0 -> 30 1 -> 60 @@ -55,7 +54,7 @@ class WeatherReceiver : BroadcastReceiver() { } fun setOneTimeUpdate(context: Context) { - if (Preferences.showWeather && Preferences.weatherProviderApi != "") { + if (Preferences.showWeather) { listOf(10, 20, 30).forEach { with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) { setExactAndAllowWhileIdle( diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/WeatherProviderActivity.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/WeatherProviderActivity.kt index 49ac40b..699d017 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/WeatherProviderActivity.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/WeatherProviderActivity.kt @@ -1,33 +1,43 @@ package com.tommasoberlose.anotherwidget.ui.activities -import android.animation.ValueAnimator import android.app.Activity -import android.app.AlertDialog -import android.os.Build +import android.content.Intent +import android.content.pm.ResolveInfo import android.os.Bundle -import android.text.Html import android.view.View -import android.widget.RelativeLayout +import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity -import androidx.core.animation.addListener +import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.core.widget.addTextChangedListener import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import com.bumptech.glide.Glide import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.components.BottomSheetMenu +import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding +import com.tommasoberlose.anotherwidget.databinding.ActivityWeatherProviderBinding import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.helpers.WeatherHelper +import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel -import com.tommasoberlose.anotherwidget.utils.collapse -import com.tommasoberlose.anotherwidget.utils.expand import com.tommasoberlose.anotherwidget.utils.openURI +import kotlinx.android.synthetic.main.activity_choose_application.* import kotlinx.android.synthetic.main.activity_weather_provider.* -import kotlinx.android.synthetic.main.the_widget_sans.* +import kotlinx.android.synthetic.main.activity_weather_provider.action_back +import kotlinx.android.synthetic.main.activity_weather_provider.list_view +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import net.idik.lib.slimadapter.SlimAdapter class WeatherProviderActivity : AppCompatActivity() { + + private lateinit var adapter: SlimAdapter private lateinit var viewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { @@ -35,39 +45,62 @@ class WeatherProviderActivity : AppCompatActivity() { setContentView(R.layout.activity_weather_provider) viewModel = ViewModelProvider(this).get(MainViewModel::class.java) - api_key.editText?.setText(Preferences.weatherProviderApi) - } + api_key.editText?.setText(Preferences.weatherProviderApiOpen) - override fun onResume() { - super.onResume() + list_view.setHasFixedSize(true) + val mLayoutManager = LinearLayoutManager(this) + list_view.layoutManager = mLayoutManager - setListener() + adapter = SlimAdapter.create() + adapter + .register(R.layout.list_item) { item, injector -> + val provider = Constants.WeatherProvider.fromInt(item)!! + injector + .text(R.id.text, WeatherHelper.getProviderName(this, provider)) + .clicked(R.id.text) { + Preferences.weatherProvider = item + } + } + .attachTo(list_view) + + setupListener() subscribeUi(viewModel) } private fun subscribeUi(viewModel: MainViewModel) { - viewModel.weatherProvider.observe(this, Observer { - weather_provider.editText?.setText(WeatherHelper.getProviderName(this, Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!).split("\n").first()) + adapter.updateData(Constants.WeatherProvider.values().map { it.value }) - api_key_container.isVisible = WeatherHelper.isKeyRequired() - - WeatherHelper.getProviderInfoTitle(this).let { - info_title.text = it - info_title.isVisible = it != "" - } - - WeatherHelper.getProviderInfoSubtitle(this).let { - info_subtitle.text = it - info_subtitle.isVisible = it != "" - } - - action_open_provider.text = WeatherHelper.getProviderLinkName(this) - }) - - viewModel.weatherProviderApi +// viewModel.weatherProvider.observe(this, Observer { +// weather_provider.editText?.setText(WeatherHelper.getProviderName(this, Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!).split("\n").first()) +// +// api_key_container.isVisible = WeatherHelper.isKeyRequired() +// +// WeatherHelper.getProviderInfoTitle(this).let { +// info_title.text = it +// info_title.isVisible = it != "" +// } +// +// WeatherHelper.getProviderInfoSubtitle(this).let { +// info_subtitle.text = it +// info_subtitle.isVisible = it != "" +// } +// +// action_open_provider.text = WeatherHelper.getProviderLinkName(this) +// +// api_key.editText?.setText(when (Constants.WeatherProvider.fromInt(it)) { +// Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen +// Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit +// Constants.WeatherProvider.WEATHER_API -> Preferences.weatherProviderApiWeatherApi +// Constants.WeatherProvider.HERE -> Preferences.weatherProviderApiHere +// Constants.WeatherProvider.ACCUWEATHER -> Preferences.weatherProviderApiAccuweather +// Constants.WeatherProvider.WEATHER_GOV, +// Constants.WeatherProvider.YR, +// null -> "" +// }) +// }) } - private fun setListener() { + private fun setupListener() { action_back.setOnClickListener { onBackPressed() } @@ -79,7 +112,7 @@ class WeatherProviderActivity : AppCompatActivity() { weather_provider_inner.setOnClickListener { if (Preferences.showWeather) { val dialog = BottomSheetMenu(this, header = getString(R.string.settings_weather_provider_api)).setSelectedValue(Preferences.weatherProvider) - (0 until 11).forEach { + (0 until 7).forEach { val item = Constants.WeatherProvider.fromInt(it) dialog.addItem(WeatherHelper.getProviderName(this, item!!), it) } @@ -92,7 +125,14 @@ class WeatherProviderActivity : AppCompatActivity() { api_key.editText?.addTextChangedListener { val key = it?.toString() ?: "" - Preferences.weatherProviderApi = key + when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) { + Constants.WeatherProvider.OPEN_WEATHER -> Preferences.weatherProviderApiOpen = key + Constants.WeatherProvider.WEATHER_BIT -> Preferences.weatherProviderApiWeatherBit = key + Constants.WeatherProvider.WEATHER_API -> Preferences.weatherProviderApiWeatherApi = key + Constants.WeatherProvider.HERE -> Preferences.weatherProviderApiHere = key + Constants.WeatherProvider.ACCUWEATHER -> Preferences.weatherProviderApiAccuweather = key + else -> {} + } } } diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt index 5d3fb1c..9e806c1 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt @@ -2,8 +2,6 @@ package com.tommasoberlose.anotherwidget.ui.fragments import android.Manifest import android.animation.ValueAnimator -import android.appwidget.AppWidgetManager -import android.appwidget.AppWidgetProviderInfo import android.content.Intent import android.content.SharedPreferences import android.net.Uri @@ -11,7 +9,6 @@ import android.os.Build import android.os.Bundle import android.provider.Settings import android.util.DisplayMetrics -import android.util.Log import android.util.TypedValue import android.view.LayoutInflater import android.view.View @@ -355,7 +352,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList backgroundColor = ContextCompat.getColor(requireContext(), R.color.errorColorText) badgeGravity = BadgeDrawable.TOP_END }?.isVisible = if (Preferences.showWeather) { - (WeatherHelper.isKeyRequired() && Preferences.weatherProviderApi == "") + (WeatherHelper.isKeyRequired() && Preferences.weatherProviderApiOpen == "") || (Preferences.customLocationAdd == "" && activity?.checkGrantedPermission( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION ) != true) diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/WeatherTabFragment.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/WeatherTabFragment.kt index 15ac3f4..02d8a3c 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/WeatherTabFragment.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/WeatherTabFragment.kt @@ -170,9 +170,11 @@ class WeatherTabFragment : Fragment() { if (activity?.checkGrantedPermission(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACCESS_BACKGROUND_LOCATION else Manifest.permission.ACCESS_FINE_LOCATION) == true) { location_permission_alert?.isVisible = false + background_location_warning.isVisible = Preferences.customLocationAdd == "" WeatherReceiver.setUpdates(requireContext()) } else if (Preferences.showWeather && Preferences.customLocationAdd == "") { location_permission_alert?.isVisible = true + background_location_warning.isVisible = false location_permission_alert?.setOnClickListener { MaterialBottomSheetDialog(requireContext(), message = getString(R.string.background_location_warning)) .setPositiveButton(getString(android.R.string.ok)) { @@ -283,7 +285,7 @@ class WeatherTabFragment : Fragment() { MainWidget.updateWidget(requireContext()) } RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> { - WeatherReceiver.setOneTimeUpdate(requireContext()) + checkLocationPermission() } } } diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt index 9114c39..5e2a799 100644 --- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt +++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt @@ -64,7 +64,7 @@ class MainViewModel : ViewModel() { val weatherRefreshPeriod = Preferences.asLiveData(Preferences::weatherRefreshPeriod) val weatherAppName = Preferences.asLiveData(Preferences::weatherAppName) - val weatherProviderApi = Preferences.asLiveData(Preferences::weatherProviderApi) + val weatherProviderApi = Preferences.asLiveData(Preferences::weatherProviderApiOpen) val customLocationAdd = Preferences.asLiveData(Preferences::customLocationAdd) diff --git a/app/src/main/res/layout/activity_weather_provider.xml b/app/src/main/res/layout/activity_weather_provider.xml index 0ffdc74..d91ba84 100644 --- a/app/src/main/res/layout/activity_weather_provider.xml +++ b/app/src/main/res/layout/activity_weather_provider.xml @@ -50,8 +50,26 @@ android:textAppearance="@style/TextAppearance.MaterialComponents.Button"/> + + + + Open Weather Map Weatherbit.io - Foreca.com + Weatherapi.com Here.com Accuweather.com Weather.gov (US)\nPowered by National Weather Services YR.no/Met.no\nPowered by Meteorological Institute - Smhi.se (Swedish)\nPowered by Swedish Meteorological - Weather.gc.ca (Canada) - BOM (Australia)\nPowered by Australia\'s national weather - Meteofrance.com (France) Open openweathermap.com Open weatherbit.io - Open foreca.com + Open weatherapi.com Open here.com Open Accuweather.com Open Weather.gov Open yr.no - Open smhi.se - Open weather.gc.ca - Open bom.gov.au - Open meteofrance.com This weather provider needs\nan API key to work correctly. - Weatherbit.io - Foreca.com - Here.com - Accuweather.com + This weather provider needs\nan API key to work correctly. + This weather provider needs\nan API key to work correctly. + This weather provider needs\nan API key to work correctly. + This weather provider needs\nan API key to work correctly. This weather provider works only\nfor locations inside the US. - YR.no/Met.no\nPowered by Meteorological Institute - Smhi.se (Swedish)\nPowered by Swedish Meteorological - Weather.gc.ca (Canada) - BOM (Australia)\nPowered by Australia\'s national weather - Meteofrance.com (France) + This weather provider allows only Celsius temperatures. Please, open the provider website, create a personal account and copy here the default key. - Weatherbit.io - Foreca.com - Here.com - Accuweather.com + Please, open the provider website, create a personal account and copy here the default key. + Please, open the provider website, create a personal account and copy here the default key. + Please, open the provider website, create a personal account and copy here the default key. + Please, open the provider website, create a personal account and copy here the default key. - YR.no/Met.no\nPowered by Meteorological Institute - Smhi.se (Swedish)\nPowered by Swedish Meteorological - Weather.gc.ca (Canada) - BOM (Australia)\nPowered by Australia\'s national weather - Meteofrance.com (France) + The weather provider that you\'ve selected requires an API key. The current location is not supported. Please select a valid location. It seems that your API key has expired. + API key not valid, or not yet activated. The weather provider is wrongly configured.