Connect weather.gov api
This commit is contained in:
parent
e9c0cdd61c
commit
bd4869540b
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
1
.idea/codeStyles/Project.xml
generated
1
.idea/codeStyles/Project.xml
generated
@ -17,6 +17,7 @@
|
||||
<package name="" alias="true" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
|
@ -123,6 +123,7 @@ dependencies {
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'
|
||||
implementation "com.github.haroldadmin:NetworkResponseAdapter:4.0.1"
|
||||
|
||||
//Coroutines
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5'
|
||||
|
@ -44,6 +44,7 @@ object WeatherHelper {
|
||||
fun removeWeather(context: Context) {
|
||||
Preferences.remove(Preferences::weatherTemp)
|
||||
Preferences.remove(Preferences::weatherRealTempUnit)
|
||||
Preferences.remove(Preferences::weatherIcon)
|
||||
MainWidget.updateWidget(context)
|
||||
}
|
||||
|
||||
@ -80,6 +81,40 @@ object WeatherHelper {
|
||||
})
|
||||
}
|
||||
|
||||
fun getProviderInfoTitle(context: Context): String {
|
||||
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.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
|
||||
})
|
||||
}
|
||||
|
||||
fun getProviderInfoSubtitle(context: Context): String {
|
||||
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.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
|
||||
})
|
||||
}
|
||||
|
||||
fun getProviderLink(): String {
|
||||
return when(Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||
Constants.WeatherProvider.OPEN_WEATHER -> "https://home.openweathermap.org/users/sign_up"
|
||||
@ -315,4 +350,43 @@ object WeatherHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when {
|
||||
iconString.contains("skc") -> "01"
|
||||
iconString.contains("few") -> "02"
|
||||
iconString.contains("sct") -> "03"
|
||||
iconString.contains("bkn") -> "04"
|
||||
iconString.contains("ovc") -> "04"
|
||||
iconString.contains("wind_skc") -> "01"
|
||||
iconString.contains("wind_few") -> "02"
|
||||
iconString.contains("wind_sct") -> "03"
|
||||
iconString.contains("wind_bkn") -> "04"
|
||||
iconString.contains("wind_ovc") -> "04"
|
||||
iconString.contains("snow") -> "13"
|
||||
iconString.contains("rain_snow") -> "81"
|
||||
iconString.contains("rain_sleet") -> "81"
|
||||
iconString.contains("snow_sleet") -> "81"
|
||||
iconString.contains("fzra") -> "81"
|
||||
iconString.contains("rain_fzra") -> "81"
|
||||
iconString.contains("snow_fzra") -> "81"
|
||||
iconString.contains("sleet") -> "81"
|
||||
iconString.contains("rain") -> "10"
|
||||
iconString.contains("rain_showers") -> "10"
|
||||
iconString.contains("rain_showers_hi") -> "10"
|
||||
iconString.contains("tsra") -> "82"
|
||||
iconString.contains("tsra_sct") -> "82"
|
||||
iconString.contains("tsra_hi") -> "82"
|
||||
iconString.contains("tornado") -> "80"
|
||||
iconString.contains("hurricane") -> "80"
|
||||
iconString.contains("tropical_storm") -> "09"
|
||||
iconString.contains("dust") -> "Dust"
|
||||
iconString.contains("smoke") -> "Smoke"
|
||||
iconString.contains("haze") -> "50"
|
||||
iconString.contains("hot") -> "01"
|
||||
iconString.contains("cold") -> "13"
|
||||
iconString.contains("blizzard") -> "80"
|
||||
iconString.contains("fog") -> "82"
|
||||
else -> ""
|
||||
} + if (isDaytime) "d" else "n"
|
||||
|
||||
}
|
@ -3,10 +3,13 @@ package com.tommasoberlose.anotherwidget.network
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.google.gson.internal.LinkedTreeMap
|
||||
import com.haroldadmin.cnradapter.NetworkResponse
|
||||
import com.haroldadmin.cnradapter.executeWithRetry
|
||||
import com.kwabenaberko.openweathermaplib.constants.Units
|
||||
import com.kwabenaberko.openweathermaplib.implementation.OpenWeatherMapHelper
|
||||
import com.kwabenaberko.openweathermaplib.implementation.callbacks.CurrentWeatherCallback
|
||||
import com.kwabenaberko.openweathermaplib.models.currentweather.CurrentWeather
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||
@ -22,6 +25,9 @@ import java.lang.Exception
|
||||
|
||||
class WeatherNetworkApi(val context: Context) {
|
||||
fun updateWeather() {
|
||||
Preferences.weatherProviderError = ""
|
||||
Preferences.weatherProviderLocationError = ""
|
||||
|
||||
if (Preferences.showWeather && Preferences.customLocationLat != "" && Preferences.customLocationLon != "") {
|
||||
when (Constants.WeatherProvider.fromInt(Preferences.weatherProvider)) {
|
||||
Constants.WeatherProvider.OPEN_WEATHER -> useOpenWeatherMap(context)
|
||||
@ -56,6 +62,9 @@ class WeatherNetworkApi(val context: Context) {
|
||||
|
||||
})
|
||||
} else {
|
||||
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
|
||||
Preferences.weatherProviderLocationError = ""
|
||||
|
||||
WeatherHelper.removeWeather(
|
||||
context
|
||||
)
|
||||
@ -65,23 +74,65 @@ class WeatherNetworkApi(val context: Context) {
|
||||
private fun useWeatherGov(context: Context) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val repository = WeatherGovRepository()
|
||||
try {
|
||||
val points = repository.getGridPoints(
|
||||
val pointsResponse = executeWithRetry(times = 5) {
|
||||
repository.getGridPoints(
|
||||
Preferences.customLocationLat,
|
||||
Preferences.customLocationLon
|
||||
)
|
||||
|
||||
val pp = points["properties"] as LinkedTreeMap<*,*>
|
||||
val gridId = pp["gridId"] as String
|
||||
val gridX = pp["gridX"] as Double
|
||||
val gridY = pp["gridY"] as Double
|
||||
|
||||
val weather = repository.getWeather(gridId, gridX, gridY)
|
||||
|
||||
Log.d("ciao", weather.toString())
|
||||
} catch (ex: Exception) {
|
||||
Log.d("ciao", ex.localizedMessage)
|
||||
}
|
||||
|
||||
when (pointsResponse) {
|
||||
is NetworkResponse.Success -> {
|
||||
try {
|
||||
val pp = pointsResponse.body["properties"] as LinkedTreeMap<*, *>
|
||||
val gridId = pp["gridId"] as String
|
||||
val gridX = pp["gridX"] as Double
|
||||
val gridY = pp["gridY"] as Double
|
||||
|
||||
when (val weatherResponse = repository.getWeather(
|
||||
gridId,
|
||||
gridX,
|
||||
gridY,
|
||||
if (Preferences.weatherTempUnit == "F") "us" else "si"
|
||||
)) {
|
||||
is NetworkResponse.Success -> {
|
||||
try {
|
||||
val props =
|
||||
weatherResponse.body["properties"] as LinkedTreeMap<*, *>
|
||||
val periods = props["periods"] as List<*>
|
||||
val now = periods[0] as LinkedTreeMap<*, *>
|
||||
|
||||
val temp = now["temperature"] as Double
|
||||
val fullIcon = now["icon"] as String
|
||||
val isDaytime = now["isDaytime"] as Boolean
|
||||
|
||||
Preferences.weatherTemp = temp.toFloat()
|
||||
Preferences.weatherIcon = WeatherHelper.getWeatherGovIcon(fullIcon, isDaytime)
|
||||
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
|
||||
|
||||
MainWidget.updateWidget(context)
|
||||
|
||||
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
|
||||
} catch (ex: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
package com.tommasoberlose.anotherwidget.network.api
|
||||
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
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): HashMap<String, Any>
|
||||
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): HashMap<String, Any>
|
||||
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>>
|
||||
}
|
@ -1,15 +1,16 @@
|
||||
package com.tommasoberlose.anotherwidget.network.repository
|
||||
|
||||
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
|
||||
import com.tommasoberlose.anotherwidget.network.api.WeatherGovApiService
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
|
||||
class WeatherGovRepository() {
|
||||
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) = apiService.getWeather(gridId, gridX.toInt(), gridY.toInt())
|
||||
suspend fun getWeather(gridId: String, gridX: Double, gridY: Double, unit: String) = apiService.getWeather(gridId, gridX.toInt(), gridY.toInt(), unit)
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL = "https://api.weather.gov/"
|
||||
@ -17,6 +18,7 @@ class WeatherGovRepository() {
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(BASE_URL)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(NetworkResponseAdapterFactory())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
@ -49,11 +49,22 @@ class WeatherProviderActivity : AppCompatActivity() {
|
||||
viewModel.weatherProvider.observe(this, Observer {
|
||||
weather_provider.editText?.setText(WeatherHelper.getProviderName(this, Constants.WeatherProvider.fromInt(Preferences.weatherProvider)!!).split("\n").first())
|
||||
|
||||
info_container.isVisible = WeatherHelper.isKeyRequired()
|
||||
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
|
||||
}
|
||||
|
||||
private fun setListener() {
|
||||
@ -80,7 +91,8 @@ class WeatherProviderActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
api_key.editText?.addTextChangedListener {
|
||||
Preferences.weatherProviderApi = it?.toString() ?: ""
|
||||
val key = it?.toString() ?: ""
|
||||
Preferences.weatherProviderApi = key
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,8 @@
|
||||
android:clickable="false"
|
||||
android:id="@+id/weather_provider_inner"
|
||||
android:textDirection="locale"
|
||||
android:textStyle="bold"
|
||||
android:cursorVisible="false"
|
||||
android:fontFamily="@font/google_sans"
|
||||
android:gravity="center_vertical|start" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
@ -151,8 +153,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/AnotherWidget.Settings.Title"
|
||||
android:gravity="start"
|
||||
android:id="@+id/info_title"
|
||||
android:textAlignment="viewStart"
|
||||
android:text="This weather provider needs\nan API key to work correctly."/>
|
||||
android:text="@string/weather_provider_info_open_weather_title"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -160,22 +163,28 @@
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="start"
|
||||
android:id="@+id/info_subtitle"
|
||||
android:textAlignment="viewStart"
|
||||
android:text="Please, open the provider website, create a personal account and copy here the default key."/>
|
||||
android:text="@string/weather_provider_info_open_weather_subtitle"/>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:textColor="@color/colorAccent"
|
||||
android:letterSpacing="0"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textSize="15sp"
|
||||
android:gravity="start|center_vertical"
|
||||
android:textAlignment="viewStart"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="-8dp"
|
||||
android:textSize="14sp"
|
||||
android:gravity="center_vertical|end"
|
||||
app:strokeColor="@color/colorAccent"
|
||||
android:textAlignment="viewEnd"
|
||||
app:iconTint="@color/colorAccent"
|
||||
app:icon="@drawable/round_chevron_right"
|
||||
app:iconGravity="end"
|
||||
app:iconSize="20dp"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:textAllCaps="false"
|
||||
android:id="@+id/action_open_provider"
|
||||
android:text="@string/action_open_provider"/>
|
||||
</LinearLayout>
|
||||
|
@ -175,7 +175,7 @@
|
||||
android:id="@+id/weather_provider_error"
|
||||
android:textColor="@color/errorColorText"
|
||||
android:letterSpacing="0"
|
||||
android:fontFamily="@font/google_sans"
|
||||
android:fontFamily="@font/google_sans_bold"
|
||||
android:textStyle="bold"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Button"
|
||||
app:textAllCaps="false" />
|
||||
@ -245,7 +245,7 @@
|
||||
android:id="@+id/weather_provider_location_error"
|
||||
android:textColor="@color/errorColorText"
|
||||
android:letterSpacing="0"
|
||||
android:fontFamily="@font/google_sans"
|
||||
android:fontFamily="@font/google_sans_bold"
|
||||
android:textStyle="bold"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Button"
|
||||
app:textAllCaps="false" />
|
||||
@ -254,7 +254,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/background_location_warning"
|
||||
android:paddingStart="64dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:orientation="horizontal">
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
|
@ -30,5 +30,6 @@
|
||||
<color name="errorColorText">#E93B3B</color>
|
||||
<color name="warningColorText">#FB8C00</color>
|
||||
<color name="disabledButtonBackground">#efefef</color>
|
||||
<color name="success">#43A047</color>
|
||||
|
||||
</resources>
|
||||
|
@ -129,6 +129,7 @@
|
||||
<string name="settings_weather_icon_pack_default">Icon pack %d</string>
|
||||
<string name="background_location_warning">We will collect location data to update the weather information even when the app is closed or not in use.\nWe will not use these data otherwise.</string>
|
||||
<string name="settings_weather_provider_api">Weather provider</string>
|
||||
|
||||
<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>
|
||||
@ -140,6 +141,7 @@
|
||||
<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>
|
||||
@ -152,6 +154,36 @@
|
||||
<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_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_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_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_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_misconfigured">The weather provider is wrongly configured.</string>
|
||||
|
||||
<!-- Clock -->
|
||||
<string name="settings_clock_title">Clock</string>
|
||||
<string name="settings_clock_app_title">Tap on clock opens</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user