Update the providers

This commit is contained in:
Tommaso Berlose 2020-10-06 18:11:53 +02:00
parent bd4869540b
commit 1644fb7682
20 changed files with 587 additions and 146 deletions

View File

@ -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">
<activity android:name=".ui.activities.MainActivity" android:launchMode="singleInstance" android:theme="@style/AppTheme.Main" android:screenOrientation="portrait">

View File

@ -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)

View File

@ -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 = "")

View File

@ -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"
}

View File

@ -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,13 +122,115 @@ 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
)
}
}
}
}
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<LinkedTreeMap<String, Any>>?
data?.first()?.let {
val temp = it["temp"] as Double
val weatherInfo = it["weather"] as LinkedTreeMap<String, Any>
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<String, Any>?
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<String, Any>
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
@ -132,7 +238,47 @@ class WeatherNetworkApi(val context: 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
)
}
}
}
}
}

View File

@ -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<String, Any>, HashMap<String, Any>>
@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<String, Any>, HashMap<String, Any>>
}
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<String, Any>, HashMap<String, Any>>
}
interface WeatherApiService {
@Headers("Accept: application/json")
@GET("current.json")
suspend fun getWeather(
@Query("key") key: String,
@Query("q") location: String,
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
}
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<String, Any>, HashMap<String, Any>>
}
interface AccuweatherService {
@GET("")
suspend fun getWeather(
@Path("gridId") gridId: String,
@Path("gridX") gridX: Int,
@Path("gridY") gridY: Int,
@Query("units") unit: String
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
}
interface YrService {
@Headers("User-Agent: AnotherWidget")
@GET("compact.json")
suspend fun getWeather(
@Query("lat") lat: String,
@Query("lon") lon: String,
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
}
}

View File

@ -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<String, Any>, HashMap<String, Any>>
@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<String, Any>, HashMap<String, Any>>
}

View File

@ -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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -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()

View File

@ -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()
}
}
}

View File

@ -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()
}
}
}

View File

@ -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(

View File

@ -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)
list_view.setHasFixedSize(true)
val mLayoutManager = LinearLayoutManager(this)
list_view.layoutManager = mLayoutManager
adapter = SlimAdapter.create()
adapter
.register<Int>(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)
override fun onResume() {
super.onResume()
setListener()
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 != ""
// 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 -> ""
// })
// })
}
WeatherHelper.getProviderInfoSubtitle(this).let {
info_subtitle.text = it
info_subtitle.isVisible = it != ""
}
action_open_provider.text = WeatherHelper.getProviderLinkName(this)
})
viewModel.weatherProviderApi
}
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<Int>(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 -> {}
}
}
}

View File

@ -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)

View File

@ -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()
}
}
}

View File

@ -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)

View File

@ -50,8 +50,26 @@
android:textAppearance="@style/TextAppearance.MaterialComponents.Button"/>
</RelativeLayout>
</com.google.android.material.card.MaterialCardView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<androidx.core.widget.ContentLoadingProgressBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:indeterminateTint="@color/colorAccent"
android:layout_marginTop="-7dp"
android:id="@+id/loader"
style="@style/Widget.AppCompat.ProgressBar.Horizontal" />
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/list_view" />
</RelativeLayout>
<ScrollView
android:layout_width="match_parent"
android:visibility="gone"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"

View File

@ -132,56 +132,41 @@
<string name="settings_weather_provider_open_weather">Open Weather Map</string>
<string name="settings_weather_provider_weatherbit">Weatherbit.io</string>
<string name="settings_weather_provider_foreca">Foreca.com</string>
<string name="settings_weather_provider_weather_api">Weatherapi.com</string>
<string name="settings_weather_provider_here">Here.com</string>
<string name="settings_weather_provider_accuweather">Accuweather.com</string>
<string name="settings_weather_provider_weather_gov">Weather.gov (US)\nPowered by National Weather Services</string>
<string name="settings_weather_provider_yr">YR.no/Met.no\nPowered by Meteorological Institute</string>
<string name="settings_weather_provider_smhi">Smhi.se (Swedish)\nPowered by Swedish Meteorological</string>
<string name="settings_weather_provider_weather_ca">Weather.gc.ca (Canada)</string>
<string name="settings_weather_provider_bom">BOM (Australia)\nPowered by Australia\'s national weather</string>
<string name="settings_weather_provider_meteofrance">Meteofrance.com (France)</string>
<string name="action_open_provider_open_weather">Open openweathermap.com</string>
<string name="action_open_provider_weatherbit">Open weatherbit.io</string>
<string name="action_open_provider_foreca">Open foreca.com</string>
<string name="action_open_provider_weatherapi">Open weatherapi.com</string>
<string name="action_open_provider_here">Open here.com</string>
<string name="action_open_provider_accuweather">Open Accuweather.com</string>
<string name="action_open_provider_weather_gov">Open Weather.gov</string>
<string name="action_open_provider_yr">Open yr.no</string>
<string name="action_open_provider_smhi">Open smhi.se</string>
<string name="action_open_provider_weather_ca">Open weather.gc.ca</string>
<string name="action_open_provider_bom">Open bom.gov.au</string>
<string name="action_open_provider_meteofrance">Open meteofrance.com</string>
<string name="weather_provider_info_open_weather_title">This weather provider needs\nan API key to work correctly.</string>
<string name="weather_provider_info_weatherbit_title">Weatherbit.io</string>
<string name="weather_provider_info_foreca_title">Foreca.com</string>
<string name="weather_provider_info_here_title">Here.com</string>
<string name="weather_provider_info_accuweather_title">Accuweather.com</string>
<string name="weather_provider_info_weatherbit_title">This weather provider needs\nan API key to work correctly.</string>
<string name="weather_provider_info_weatherapi_title">This weather provider needs\nan API key to work correctly.</string>
<string name="weather_provider_info_here_title">This weather provider needs\nan API key to work correctly.</string>
<string name="weather_provider_info_accuweather_title">This weather provider needs\nan API key to work correctly.</string>
<string name="weather_provider_info_weather_gov_title">This weather provider works only\nfor locations inside the US.</string>
<string name="weather_provider_info_yr_title">YR.no/Met.no\nPowered by Meteorological Institute</string>
<string name="weather_provider_info_smhi_title">Smhi.se (Swedish)\nPowered by Swedish Meteorological</string>
<string name="weather_provider_info_weather_ca_title">Weather.gc.ca (Canada)</string>
<string name="weather_provider_info_bom_title">BOM (Australia)\nPowered by Australia\'s national weather</string>
<string name="weather_provider_info_meteofrance_title">Meteofrance.com (France)</string>
<string name="weather_provider_info_yr_title">This weather provider allows only Celsius temperatures.</string>
<string name="weather_provider_info_open_weather_subtitle">Please, open the provider website, create a personal account and copy here the default key.</string>
<string name="weather_provider_info_weatherbit_subtitle">Weatherbit.io</string>
<string name="weather_provider_info_foreca_subtitle">Foreca.com</string>
<string name="weather_provider_info_here_subtitle">Here.com</string>
<string name="weather_provider_info_accuweather_subtitle">Accuweather.com</string>
<string name="weather_provider_info_weatherbit_subtitle">Please, open the provider website, create a personal account and copy here the default key.</string>
<string name="weather_provider_info_weatherapi_subtitle">Please, open the provider website, create a personal account and copy here the default key.</string>
<string name="weather_provider_info_here_subtitle">Please, open the provider website, create a personal account and copy here the default key.</string>
<string name="weather_provider_info_accuweather_subtitle">Please, open the provider website, create a personal account and copy here the default key.</string>
<string name="weather_provider_info_weather_gov_subtitle" />
<string name="weather_provider_info_yr_subtitle">YR.no/Met.no\nPowered by Meteorological Institute</string>
<string name="weather_provider_info_smhi_subtitle">Smhi.se (Swedish)\nPowered by Swedish Meteorological</string>
<string name="weather_provider_info_weather_ca_subtitle">Weather.gc.ca (Canada)</string>
<string name="weather_provider_info_bom_subtitle">BOM (Australia)\nPowered by Australia\'s national weather</string>
<string name="weather_provider_info_meteofrance_subtitle">Meteofrance.com (France)</string>
<string name="weather_provider_info_yr_subtitle" />
<string name="weather_provider_error_missing_key">The weather provider that you\'ve selected requires an API key.</string>
<string name="weather_provider_error_wrong_location">The current location is not supported.</string>
<string name="weather_provider_error_missing_location">Please select a valid location.</string>
<string name="weather_provider_error_expired_key">It seems that your API key has expired.</string>
<string name="weather_provider_error_invalid_key">API key not valid, or not yet activated.</string>
<string name="weather_provider_error_misconfigured">The weather provider is wrongly configured.</string>
<!-- Clock -->