diff --git a/app/build.gradle b/app/build.gradle index c0cce840a..e856b975e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,11 +17,11 @@ android { targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() // NOTE: Version Code Format (TargetSDK, Version Name, Build Number, Variant Code (Android: 0, WearOS: 1) // ex) 345100131 = (34, 5.10, 013, 0) - versionCode 375140110 - versionName "5.14.0" + versionCode 375140120 + versionName "5.14.1" vectorDrawables { - useSupportLibrary = true + useSupportLibrary true } } diff --git a/app/src/main/java/com/thewizrd/simpleweather/activities/LocationSearchActivity.kt b/app/src/main/java/com/thewizrd/simpleweather/activities/LocationSearchActivity.kt index fc58ba67f..3a54ddacc 100644 --- a/app/src/main/java/com/thewizrd/simpleweather/activities/LocationSearchActivity.kt +++ b/app/src/main/java/com/thewizrd/simpleweather/activities/LocationSearchActivity.kt @@ -20,7 +20,6 @@ import androidx.core.view.ViewGroupCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePaddingRelative import androidx.lifecycle.lifecycleScope -import com.google.android.material.R as materialRes import com.google.android.material.search.SearchView import com.google.android.material.snackbar.Snackbar import com.google.android.material.transition.platform.MaterialContainerTransform @@ -42,7 +41,6 @@ import com.thewizrd.shared_resources.utils.ContextUtils.getOrientation import com.thewizrd.shared_resources.utils.ContextUtils.isSmallestWidth import com.thewizrd.shared_resources.utils.JSONParser import com.thewizrd.shared_resources.utils.UserThemeMode -import com.thewizrd.simpleweather.R import com.thewizrd.simpleweather.databinding.ActivityLocationSearchBinding import com.thewizrd.simpleweather.snackbar.SnackbarWindowAdjustCallback import kotlinx.coroutines.Job @@ -51,6 +49,7 @@ import kotlinx.coroutines.ensureActive import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope +import com.google.android.material.R as materialRes class LocationSearch : ActivityResultContract() { override fun createIntent(context: Context, input: Void?): Intent { @@ -138,14 +137,14 @@ class LocationSearchActivity : WindowColorActivity() { } // Initialize - binding.searchView.setVisible(true) - binding.searchView.addTransitionListener { _, _, newState -> + binding.locationSearchView.setVisible(true) + binding.locationSearchView.addTransitionListener { _, _, newState -> if (newState == SearchView.TransitionState.HIDING || newState == SearchView.TransitionState.HIDDEN) { setResult(RESULT_CANCELED) onBackPressedDispatcher.onBackPressed() } } - binding.searchView.editText.addTextChangedListener(object : TextWatcher { + binding.locationSearchView.editText.addTextChangedListener(object : TextWatcher { private var textChangedJob: Job? = null override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { @@ -177,18 +176,18 @@ class LocationSearchActivity : WindowColorActivity() { fetchLocations(newText) } }) - binding.searchView.editText.setOnEditorActionListener(TextView.OnEditorActionListener { v, actionId, _ -> + binding.locationSearchView.editText.setOnEditorActionListener(TextView.OnEditorActionListener { v, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_SEARCH) { fetchLocations(v.text.toString()) - binding.searchView.clearFocusAndHideKeyboard() + binding.locationSearchView.clearFocusAndHideKeyboard() return@OnEditorActionListener true } false }) - binding.searchView.onItemClickListener = recyclerClickListener + binding.locationSearchView.onItemClickListener = recyclerClickListener val padding = dpToPx(8f).toInt() - binding.searchView.recyclerView.updatePaddingRelative( + binding.locationSearchView.recyclerView.updatePaddingRelative( start = padding, end = padding, top = padding ) @@ -207,13 +206,13 @@ class LocationSearchActivity : WindowColorActivity() { lifecycleScope.launch { locationSearchViewModel.isLoading.collect { loading -> - binding.searchView.showLoading(loading) + binding.locationSearchView.showLoading(loading) } } lifecycleScope.launch { locationSearchViewModel.locations.collectLatest { - binding.searchView.submitList(it) + binding.locationSearchView.submitList(it) } } @@ -243,11 +242,11 @@ class LocationSearchActivity : WindowColorActivity() { override fun onResume() { super.onResume() - binding.searchView.requestFocusAndShowKeyboard() + binding.locationSearchView.requestFocusAndShowKeyboard() } override fun onPause() { - binding.searchView.clearFocusAndHideKeyboard() + binding.locationSearchView.clearFocusAndHideKeyboard() super.onPause() } @@ -274,7 +273,7 @@ class LocationSearchActivity : WindowColorActivity() { } binding.root.setBackgroundColor(backgroundColor) - binding.searchView.setBackgroundOverlayColor(backgroundColor) + binding.locationSearchView.setBackgroundOverlayColor(backgroundColor) window.setTransparentWindow( backgroundColor, Colors.TRANSPARENT, @@ -296,7 +295,7 @@ class LocationSearchActivity : WindowColorActivity() { } private fun onErrorMessage(error: ErrorMessage) { - binding.searchView.clearFocusAndHideKeyboard() + binding.locationSearchView.clearFocusAndHideKeyboard() when (error) { is ErrorMessage.Resource -> { diff --git a/app/src/main/res/layout/activity_location_search.xml b/app/src/main/res/layout/activity_location_search.xml index 8ac674341..d8f8097f8 100644 --- a/app/src/main/res/layout/activity_location_search.xml +++ b/app/src/main/res/layout/activity_location_search.xml @@ -26,7 +26,7 @@ android:transitionName="shared_element_container"> ? = response.place.addressComponents?.asList() + val addressComponents: List? = + response.place.addressComponents?.asList() if (!addressComponents.isNullOrEmpty()) { for (addrCmp in addressComponents) { + if (town == null && addrCmp?.types?.contains("neighborhood") == true) { + town = addrCmp + } if (town == null && addrCmp?.types?.contains("locality") == true) { town = addrCmp } @@ -120,6 +128,128 @@ fun createLocationModel( locationTZLong = null + locationSource = WeatherAPI.GOOGLE + updateWeatherSource(weatherAPI) + } +} + +/* Google Geocoding API Result */ +fun createLocationModel( + response: GeocodingResult, + @WeatherAPI.WeatherProviders weatherAPI: String? +): LocationQuery { + return LocationQuery().apply { + var town: GeocodingAddressComponent? = null + var region: GeocodingAddressComponent? = null + var adminArea: GeocodingAddressComponent? = null + var country: GeocodingAddressComponent? = null + + val addressComponents: List? = + response.addressComponents?.asList() + + if (!addressComponents.isNullOrEmpty()) { + for (addrCmp in addressComponents) { + if (town == null && addrCmp?.types?.contains(AddressComponentType.NEIGHBORHOOD) == true) { + town = addrCmp + } + if (town == null && addrCmp?.types?.contains(AddressComponentType.LOCALITY) == true) { + town = addrCmp + } + if (adminArea == null && addrCmp?.types?.contains(AddressComponentType.ADMINISTRATIVE_AREA_LEVEL_2) == true) { + adminArea = addrCmp + } + if (region == null && addrCmp?.types?.contains(AddressComponentType.ADMINISTRATIVE_AREA_LEVEL_1) == true) { + region = addrCmp + } + if (country == null && addrCmp?.types?.contains(AddressComponentType.COUNTRY) == true) { + country = addrCmp + locationCountry = addrCmp.shortName + } + if (town != null && adminArea != null && region != null && country != null) { + break + } + } + } + + val isUS = country?.shortName == "US" || country?.longName == "United States" + + if (town != null && region != null && adminArea != null && !(adminArea.longName == region.longName || adminArea.longName.contains( + region.longName, + true + ) || adminArea.longName == town.longName || adminArea.longName.contains( + town.longName, + true + )) + ) { + locationName = String.format( + "%s, %s, %s", + town.longName, + adminArea.longName, + if (isUS) region.shortName else region.longName + ) + } else if (town != null && region != null) { + locationName = if (town.longName == region.longName) { + String.format("%s, %s", town.longName, country?.longName) + } else { + String.format( + "%s, %s", + town.longName, + if (isUS) region.shortName else region.longName + ) + } + } else { + if (town == null || region == null) { + locationName = if (town == null) { + String.format("%s, %s", region?.longName, country?.longName) + } else { + String.format("%s, %s", town.longName, country?.longName) + } + } + } + + if (locationName.isNullOrBlank()) { + locationName = response.formattedAddress.let { addr -> + var updatedAddr = addr + + if (response.geometry.locationType != LocationType.APPROXIMATE) { + // Trim un-needed address components + val streetNo = response.addressComponents.firstOrNull { adrcmp -> + adrcmp.types.contains(AddressComponentType.STREET_NUMBER) + } + val route = response.addressComponents.firstOrNull { adrcmp -> + adrcmp.types.contains(AddressComponentType.ROUTE) + } + val postalCode = response.addressComponents.firstOrNull { adrcmp -> + adrcmp.types.contains(AddressComponentType.POSTAL_CODE) + } + + if (streetNo != null && route != null) { + val streetAddress = "${streetNo.longName} ${route.shortName}" + updatedAddr = + updatedAddr.replaceFirst(streetAddress, "").trimStart().trimStart(',') + } + if (postalCode != null) { + updatedAddr = + updatedAddr.replaceFirst(" ${postalCode.longName}", "").trimStart() + .trimStart(',') + } + } + + updatedAddr.trim() + } + } + if (locationCountry.isNullOrBlank()) { + locationCountry = country?.shortName ?: country?.longName + } + if (locationRegion.isNullOrBlank()) { + locationRegion = region?.longName ?: adminArea?.longName + } + + locationLat = response.geometry.location.lat + locationLong = response.geometry.location.lng + + locationTZLong = null + locationSource = WeatherAPI.GOOGLE updateWeatherSource(weatherAPI) } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/AccuWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/AccuWeatherProvider.kt index a7d271fac..decbaba3e 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/AccuWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/accuweather/weather/AccuWeatherProvider.kt @@ -232,9 +232,9 @@ class AccuWeatherProvider : WeatherProviderImpl(), PollenProvider { CurrentsResponse(it) } - requireNotNull(dailyRoot) - requireNotNull(hourlyRoot) - requireNotNull(currentRoot) + requireNotNull(dailyRoot) { "dailyRoot is null" } + requireNotNull(hourlyRoot) { "hourlyRoot is null" } + requireNotNull(currentRoot) { "currentRoot is null" } weather = createWeatherData(dailyRoot, hourlyRoot, currentRoot) } catch (ex: Exception) { @@ -312,7 +312,7 @@ class AccuWeatherProvider : WeatherProviderImpl(), PollenProvider { } } - requireNotNull(dailyRoot) + requireNotNull(dailyRoot) { "dailyRoot is null" } val dailyForecast = dailyRoot.dailyForecasts?.firstOrNull { !it?.airAndPollen.isNullOrEmpty() } diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/BrightSkyProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/BrightSkyProvider.kt index 7f08826f9..1a5d3f90d 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/BrightSkyProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/brightsky/BrightSkyProvider.kt @@ -196,8 +196,8 @@ class BrightSkyProvider : WeatherProviderImpl() { forecastStream.closeQuietly() alertStream.closeQuietly() - requireNotNull(currRoot) - requireNotNull(foreRoot) + requireNotNull(currRoot) { "currRoot is null" } + requireNotNull(foreRoot) { "foreRoot is null" } weather = createWeatherData(currRoot, foreRoot, location) weather.weatherAlerts = createWeatherAlerts(alertsRoot) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/eccc/ECCCWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/eccc/ECCCWeatherProvider.kt index fad1de8c2..574e82158 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/eccc/ECCCWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/eccc/ECCCWeatherProvider.kt @@ -145,7 +145,8 @@ class ECCCWeatherProvider : WeatherProviderImpl() { // End Stream forecastStream.closeQuietly() - val foreRoot = requireNotNull(root?.firstOrNull()) + val foreRoot = + requireNotNull(root?.firstOrNull()) { "List is null" } weather = createWeatherData(foreRoot) } catch (ex: Exception) { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/google/location/AndroidLocationProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/google/location/AndroidLocationProvider.kt index 673c89398..2d2bf99d3 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/google/location/AndroidLocationProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/google/location/AndroidLocationProvider.kt @@ -5,15 +5,16 @@ import android.util.Log import com.thewizrd.shared_resources.exceptions.ErrorStatus import com.thewizrd.shared_resources.exceptions.WeatherException import com.thewizrd.shared_resources.locationdata.LocationQuery -import com.thewizrd.shared_resources.utils.* +import com.thewizrd.shared_resources.utils.Coordinate +import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.WeatherAPI.LocationProviders +import com.thewizrd.weather_api.google.utils.GeocoderException import com.thewizrd.weather_api.locationdata.WeatherLocationProviderImpl import com.thewizrd.weather_api.weatherModule import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.io.IOException -import java.util.* open class AndroidLocationProvider : WeatherLocationProviderImpl() { @LocationProviders @@ -43,7 +44,7 @@ open class AndroidLocationProvider : WeatherLocationProviderImpl() { ): Collection = withContext(Dispatchers.IO) { if (!isGeocoderAvailable()) { throw WeatherException(ErrorStatus.NETWORKERROR).apply { - initCause(Exception("Geocoder unavailable")) + initCause(GeocoderException("Geocoder unavailable")) } } @@ -64,7 +65,11 @@ open class AndroidLocationProvider : WeatherLocationProviderImpl() { } else if (ex is IllegalArgumentException) { wEx = WeatherException(ErrorStatus.QUERYNOTFOUND, ex) } - Logger.writeLine(Log.ERROR, ex, "GoogleLocationProvider: error getting location") + Logger.writeLine( + Log.ERROR, + ex, + "AndroidLocationProvider: error getting geocoder locations" + ) } if (wEx != null) throw wEx @@ -87,7 +92,7 @@ open class AndroidLocationProvider : WeatherLocationProviderImpl() { ): LocationQuery = withContext(Dispatchers.IO) { if (!isGeocoderAvailable()) { throw WeatherException(ErrorStatus.NETWORKERROR).apply { - initCause(Exception("Geocoder unavailable")) + initCause(GeocoderException("Geocoder unavailable")) } } @@ -98,7 +103,7 @@ open class AndroidLocationProvider : WeatherLocationProviderImpl() { try { val addresses = weatherModule.geocoder.getFromLocationNameAsync(model.locationName!!, 1) - result = addresses[0] + result = addresses.firstOrNull() } catch (ex: Exception) { result = null if (ex is IOException) { @@ -106,7 +111,11 @@ open class AndroidLocationProvider : WeatherLocationProviderImpl() { } else if (ex is IllegalArgumentException) { wEx = WeatherException(ErrorStatus.QUERYNOTFOUND, ex) } - Logger.writeLine(Log.ERROR, ex, "GoogleLocationProvider: error getting location") + Logger.writeLine( + Log.ERROR, + ex, + "AndroidLocationProvider: error getting geocoder location" + ) } if (wEx != null) throw wEx @@ -123,7 +132,7 @@ open class AndroidLocationProvider : WeatherLocationProviderImpl() { ): LocationQuery = withContext(Dispatchers.IO) { if (!isGeocoderAvailable()) { throw WeatherException(ErrorStatus.NETWORKERROR).apply { - initCause(Exception("Geocoder unavailable")) + initCause(GeocoderException("Geocoder unavailable")) } } @@ -138,7 +147,7 @@ open class AndroidLocationProvider : WeatherLocationProviderImpl() { 1 ) - result = addresses[0] + result = addresses.firstOrNull() } catch (ex: Exception) { result = null if (ex is IOException) { @@ -146,7 +155,11 @@ open class AndroidLocationProvider : WeatherLocationProviderImpl() { } else if (ex is IllegalArgumentException) { wEx = WeatherException(ErrorStatus.QUERYNOTFOUND, ex) } - Logger.writeLine(Log.ERROR, ex, "GoogleLocationProvider: error getting location") + Logger.writeLine( + Log.ERROR, + ex, + "AndroidLocationProvider: error getting geocoded location" + ) } if (wEx != null) throw wEx diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/google/location/GeocoderCache.kt b/weather-api/src/main/java/com/thewizrd/weather_api/google/location/GeocoderCache.kt new file mode 100644 index 000000000..88d627ceb --- /dev/null +++ b/weather-api/src/main/java/com/thewizrd/weather_api/google/location/GeocoderCache.kt @@ -0,0 +1,83 @@ +package com.thewizrd.weather_api.google.location + +import android.location.Address +import android.os.Parcel +import com.thewizrd.shared_resources.sharedDeps +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.internal.cache.DiskLruCache +import okhttp3.internal.concurrent.TaskRunner +import okio.FileSystem +import okio.Path.Companion.toPath +import okio.buffer +import java.io.File +import java.io.IOException +import java.security.MessageDigest + +internal object GeocoderCache { + private val cacheDir = File(sharedDeps.context.cacheDir, "geocoder_cache") + private val diskCache: DiskLruCache by lazy { + DiskLruCache( + fileSystem = FileSystem.SYSTEM, + directory = cacheDir.absolutePath.toPath(), + appVersion = 1, + valueCount = 1, + maxSize = 1 * 1024 * 1024, // 1MB + taskRunner = TaskRunner.INSTANCE + ) + } + + private fun hashKey(key: String): String { + val md = MessageDigest.getInstance("MD5") + val digest = md.digest(key.toByteArray()) + return digest.joinToString("") { "%02x".format(it) } + } + + suspend fun get(key: String): List
? = withContext(Dispatchers.IO) { + val hashedKey = hashKey(key) + try { + diskCache[hashedKey]?.use { snapshot -> + snapshot.getSource(0).buffer().use { source -> + val bytes = source.readByteArray() + val parcel = Parcel.obtain() + try { + parcel.unmarshall(bytes, 0, bytes.size) + parcel.setDataPosition(0) + val addresses = mutableListOf
() + parcel.readTypedList(addresses, Address.CREATOR) + addresses + } finally { + parcel.recycle() + } + } + } + } catch (_: Exception) { + null + } + } + + suspend fun put(key: String, addresses: List
) = withContext(Dispatchers.IO) { + val hashedKey = hashKey(key) + try { + diskCache.edit(hashedKey)?.let { editor -> + try { + editor.newSink(0).buffer().use { sink -> + val parcel = Parcel.obtain() + try { + parcel.writeTypedList(addresses) + val bytes = parcel.marshall() + sink.write(bytes) + editor.commit() + } finally { + parcel.recycle() + } + } + } catch (_: Exception) { + editor.abort() + } + } + } catch (_: IOException) { + // ignore + } + } +} diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/google/location/GeocoderExt.common.kt b/weather-api/src/main/java/com/thewizrd/weather_api/google/location/GeocoderExt.common.kt index 3d345bd4c..c2e605212 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/google/location/GeocoderExt.common.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/google/location/GeocoderExt.common.kt @@ -6,71 +6,132 @@ package com.thewizrd.weather_api.google.location import android.location.Address import android.location.Geocoder import android.os.Build +import com.thewizrd.shared_resources.utils.LocaleUtils +import com.thewizrd.shared_resources.utils.Logger +import com.thewizrd.weather_api.google.utils.GeocoderException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext +import java.io.IOException +import java.text.DecimalFormat +import java.util.Locale import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException -@Throws(Exception::class) +@Throws(GeocoderException::class, IllegalArgumentException::class, IOException::class) suspend fun Geocoder.getFromLocationNameAsync( locationName: String, maxResults: Int ): List
= withContext(Dispatchers.IO) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - suspendCancellableCoroutine { continuation -> - continuation.invokeOnCancellation { - // - } + val cacheKey = "name:$locationName|locale:${LocaleUtils.getLocale().toLanguageTag()}" - getFromLocationName(locationName, maxResults, object : Geocoder.GeocodeListener { - override fun onGeocode(p0: List
) { - if (continuation.isActive) { - continuation.resume(p0) - } + try { + val result = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + suspendCancellableCoroutine { continuation -> + continuation.invokeOnCancellation { + // } - override fun onError(errorMessage: String?) { - super.onError(errorMessage) - if (continuation.isActive) { - continuation.resumeWithException(Exception(errorMessage)) + getFromLocationName(locationName, maxResults, object : Geocoder.GeocodeListener { + override fun onGeocode(p0: List
) { + if (continuation.isActive) { + continuation.resume(p0) + } + } + + override fun onError(errorMessage: String?) { + super.onError(errorMessage) + if (continuation.isActive) { + continuation.resumeWithException(GeocoderException(errorMessage)) + } + } + }) + } + } else { + getFromLocationName(locationName, maxResults) ?: emptyList() + } + + if (result.isNotEmpty()) { + GeocoderCache.put(cacheKey, result) + } + + result + } catch (e: Exception) { + if (e is IOException || e is GeocoderException) { + GeocoderCache.get(cacheKey)?.let { cachedResults -> + if (cachedResults.isNotEmpty()) { + Logger.warn("Geocoder", e) + + return@withContext if (cachedResults.size > maxResults) { + cachedResults.subList(0, maxResults) + } else { + cachedResults } } - }) + } } - } else { - getFromLocationName(locationName, maxResults) ?: emptyList() + throw e } } -@Throws(Exception::class) +@Throws(GeocoderException::class, IllegalArgumentException::class, IOException::class) suspend fun Geocoder.getFromLocationAsync( latitude: Double, longitude: Double, maxResults: Int ): List
= withContext(Dispatchers.IO) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - suspendCancellableCoroutine { continuation -> - continuation.invokeOnCancellation { - // - } + val df = DecimalFormat.getInstance(Locale.ROOT) as DecimalFormat + df.applyPattern("0.####") - getFromLocation(latitude, longitude, maxResults, object : Geocoder.GeocodeListener { - override fun onGeocode(p0: List
) { - if (continuation.isActive) { - continuation.resume(p0) - } + val cacheKey = "loc:${df.format(latitude)},${df.format(longitude)}|locale:${ + LocaleUtils.getLocale().toLanguageTag() + }" + + try { + val result = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + suspendCancellableCoroutine { continuation -> + continuation.invokeOnCancellation { + // } - override fun onError(errorMessage: String?) { - super.onError(errorMessage) - if (continuation.isActive) { - continuation.resumeWithException(Exception(errorMessage)) + getFromLocation(latitude, longitude, maxResults, object : Geocoder.GeocodeListener { + override fun onGeocode(p0: List
) { + if (continuation.isActive) { + continuation.resume(p0) + } + } + + override fun onError(errorMessage: String?) { + super.onError(errorMessage) + if (continuation.isActive) { + continuation.resumeWithException(GeocoderException(errorMessage)) + } + } + }) + } + } else { + getFromLocation(latitude, longitude, maxResults) ?: emptyList() + } + + if (result.isNotEmpty()) { + GeocoderCache.put(cacheKey, result) + } + + result + } catch (e: Exception) { + if (e is IOException || e is GeocoderException) { + GeocoderCache.get(cacheKey)?.let { cachedResults -> + if (cachedResults.isNotEmpty()) { + Logger.warn("Geocoder", e) + + return@withContext if (cachedResults.size > maxResults) { + cachedResults.subList(0, maxResults) + } else { + cachedResults } } - }) + } } - } else { - getFromLocation(latitude, longitude, maxResults) ?: emptyList() + throw e } -} \ No newline at end of file +} diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/google/utils/GeocoderException.kt b/weather-api/src/main/java/com/thewizrd/weather_api/google/utils/GeocoderException.kt new file mode 100644 index 000000000..ade43f531 --- /dev/null +++ b/weather-api/src/main/java/com/thewizrd/weather_api/google/utils/GeocoderException.kt @@ -0,0 +1,6 @@ +package com.thewizrd.weather_api.google.utils + +class GeocoderException : Exception { + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable) : super(message, cause) +} \ No newline at end of file diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/HEREWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/HEREWeatherProvider.kt index 74c17cf46..c9ffb6849 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/HEREWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/here/weather/HEREWeatherProvider.kt @@ -153,7 +153,7 @@ class HEREWeatherProvider : WeatherProviderImpl() { // End Stream stream.closeQuietly() - requireNotNull(root) + requireNotNull(root) { "WeatherResponse is null" } // Fold into single item val rootObject = root.places!!.fold(PlacesItem()) { base, item -> diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/locationdata/WeatherLocationProviderImpl.kt b/weather-api/src/main/java/com/thewizrd/weather_api/locationdata/WeatherLocationProviderImpl.kt index 86d5792e5..2e66f9929 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/locationdata/WeatherLocationProviderImpl.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/locationdata/WeatherLocationProviderImpl.kt @@ -9,7 +9,9 @@ import com.thewizrd.shared_resources.locationdata.LocationData import com.thewizrd.shared_resources.locationdata.LocationQuery import com.thewizrd.shared_resources.locationdata.WeatherLocationProvider import com.thewizrd.shared_resources.sharedDeps -import com.thewizrd.shared_resources.utils.* +import com.thewizrd.shared_resources.utils.ConversionMethods +import com.thewizrd.shared_resources.utils.Coordinate +import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.weather_api.google.location.createLocationModel import com.thewizrd.weather_api.google.location.getFromLocationAsync @@ -108,7 +110,7 @@ abstract class WeatherLocationProviderImpl : WeatherLocationProvider, RateLimite } if (result == null) { - result = addresses[0] + result = addresses.firstOrNull() } } catch (ex: Exception) { result = null @@ -165,7 +167,7 @@ abstract class WeatherLocationProviderImpl : WeatherLocationProvider, RateLimite val addresses = weatherModule.geocoder.getFromLocationNameAsync(model.locationName!!, 1) - result = addresses[0] + result = addresses.firstOrNull() } catch (ex: Exception) { result = null if (ex is IOException) { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/locationiq/LocationIQProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/locationiq/LocationIQProvider.kt index 05b7b9062..eba35c507 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/locationiq/LocationIQProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/locationiq/LocationIQProvider.kt @@ -9,7 +9,10 @@ import com.thewizrd.shared_resources.locationdata.LocationQuery import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.await import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.getStream import com.thewizrd.shared_resources.sharedDeps -import com.thewizrd.shared_resources.utils.* +import com.thewizrd.shared_resources.utils.Coordinate +import com.thewizrd.shared_resources.utils.JSONParser +import com.thewizrd.shared_resources.utils.LocaleUtils +import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.WeatherAPI.LocationProviders import com.thewizrd.weather_api.keys.Keys @@ -27,7 +30,7 @@ import java.io.IOException import java.net.HttpURLConnection import java.net.URLEncoder import java.text.DecimalFormat -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit class LocationIQProvider : WeatherLocationProviderImpl() { @@ -110,7 +113,7 @@ class LocationIQProvider : WeatherLocationProviderImpl() { val arrListType = listType() val root = JSONParser.deserializer>(stream, arrListType) - requireNotNull(root) + requireNotNull(root) { "List is null" } for (result in root) { // Filter: only store city results diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/MeteoFranceProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/MeteoFranceProvider.kt index feb742419..b8a7d86d5 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/MeteoFranceProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/MeteoFranceProvider.kt @@ -223,8 +223,8 @@ class MeteoFranceProvider : WeatherProviderImpl() { forecastStream.closeQuietly() alertStream?.closeQuietly() - requireNotNull(currRoot) - requireNotNull(foreRoot) + requireNotNull(currRoot) { "currRoot is null" } + requireNotNull(foreRoot) { "foreRoot is null" } weather = createWeatherData(currRoot, foreRoot, alertsRoot) } catch (ex: Exception) { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/WeatherData.kt index 458923277..66ae75bc3 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/meteofrance/weather/WeatherData.kt @@ -114,9 +114,9 @@ fun createForecast(day: DailyForecastItem): Forecast { } condition = - if (!day.dailyWeatherDescription.isNullOrBlank() && locale.toString() == "en" || locale.toString() + if (!day.dailyWeatherDescription.isNullOrBlank() && locale.toLanguageTag() == "en" || locale.toLanguageTag() .startsWith("en_") || - locale.toString() == "fr" || locale.toString().startsWith("fr_") || + locale.toLanguageTag() == "fr" || locale.toLanguageTag().startsWith("fr_") || locale == Locale.ROOT ) { day.dailyWeatherDescription @@ -158,9 +158,9 @@ fun createHourlyForecast(forecast: ForecastItem, } condition = - if (!forecast.weatherDescription.isNullOrBlank() && locale.toString() == "en" || locale.toString() + if (!forecast.weatherDescription.isNullOrBlank() && locale.toLanguageTag() == "en" || locale.toLanguageTag() .startsWith("en_") || - locale.toString() == "fr" || locale.toString().startsWith("fr_") || + locale.toLanguageTag() == "fr" || locale.toLanguageTag().startsWith("fr_") || locale == Locale.ROOT ) { forecast.weatherDescription @@ -302,9 +302,9 @@ fun createCondition(currRoot: CurrentsResponse): Condition { } weather = - if (!currRoot.properties?.gridded?.weatherDescription.isNullOrBlank() && locale.toString() == "en" || locale.toString() + if (!currRoot.properties?.gridded?.weatherDescription.isNullOrBlank() && locale.toLanguageTag() == "en" || locale.toLanguageTag() .startsWith("en_") || - locale.toString() == "fr" || locale.toString().startsWith("fr_") || + locale.toLanguageTag() == "fr" || locale.toLanguageTag().startsWith("fr_") || locale == Locale.ROOT ) { currRoot.properties?.gridded?.weatherDescription diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/meteomatics/weather/MeteomaticsWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/meteomatics/weather/MeteomaticsWeatherProvider.kt index 9b0f41c13..74f01c082 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/meteomatics/weather/MeteomaticsWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/meteomatics/weather/MeteomaticsWeatherProvider.kt @@ -214,9 +214,9 @@ class MeteomaticsWeatherProvider : WeatherProviderImpl() { } } - requireNotNull(currentRoot) - requireNotNull(forecastRoot) - requireNotNull(hourlyRoot) + requireNotNull(currentRoot) { "currentRoot is null" } + requireNotNull(forecastRoot) { "forecastRoot is null" } + requireNotNull(hourlyRoot) { "hourlyRoot is null" } weather = createWeatherData(currentRoot, forecastRoot, hourlyRoot) } catch (ex: Exception) { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/metno/MetnoWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/metno/MetnoWeatherProvider.kt index 32ee584f2..75d9cc010 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/metno/MetnoWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/metno/MetnoWeatherProvider.kt @@ -159,9 +159,9 @@ class MetnoWeatherProvider : WeatherProviderImpl() { sunStream.closeQuietly() moonStream.closeQuietly() - requireNotNull(foreRoot) - requireNotNull(sunRoot) - requireNotNull(moonRoot) + requireNotNull(foreRoot) { "foreRoot is null" } + requireNotNull(sunRoot) { "sunRoot is null" } + requireNotNull(moonRoot) { "moonRoot is null" } weather = createWeatherData(foreRoot, sunRoot, moonRoot, location) } catch (ex: Exception) { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/nws/WeatherData.kt b/weather-api/src/main/java/com/thewizrd/weather_api/nws/WeatherData.kt index 31699e5b5..f4ea2dd33 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/nws/WeatherData.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/nws/WeatherData.kt @@ -202,7 +202,8 @@ fun createForecast(forecastItem: PeriodsItem): Forecast { } } - condition = if (locale.toString() == "en" || locale.toString().startsWith("en_") || + condition = + if (locale.toLanguageTag() == "en" || locale.toLanguageTag().startsWith("en_") || locale == Locale.ROOT ) { forecastItem.shortForecast @@ -236,7 +237,9 @@ fun createForecast(forecastItem: PeriodsItem, nightForecastItem: PeriodsItem): F lowF = nightForecastItem.temperature.toFloat() lowC = ConversionMethods.FtoC(lowF) - condition = if (locale.toString() == "en" || locale.toString().startsWith("en_") || locale == Locale.ROOT) { + condition = if (locale.toLanguageTag() == "en" || locale.toLanguageTag() + .startsWith("en_") || locale == Locale.ROOT + ) { forecastItem.shortForecast } else { provider.getWeatherCondition(forecastItem.icon) @@ -273,7 +276,7 @@ fun createHourlyForecast(forecastItem: PeriodItem, adjustDate: Boolean = false): highC = ConversionMethods.FtoC(it) } - condition = if (locale.toString() == "en" || locale.toString() + condition = if (locale.toLanguageTag() == "en" || locale.toLanguageTag() .startsWith("en_") || locale == Locale.ROOT ) { forecastItem.weather @@ -314,7 +317,7 @@ fun createCondition(forecastResponse: ForecastResponse): Condition { val provider = weatherModule.weatherManager.getWeatherProvider(WeatherAPI.NWS) val locale = LocaleUtils.getLocale() - weather = if (locale.toString() == "en" || locale.toString() + weather = if (locale.toLanguageTag() == "en" || locale.toLanguageTag() .startsWith("en_") || locale == Locale.ROOT ) { forecastResponse.currentobservation.weather diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/nws/alerts/NWSAlertProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/nws/alerts/NWSAlertProvider.kt index efd18e044..1bad61581 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/nws/alerts/NWSAlertProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/nws/alerts/NWSAlertProvider.kt @@ -79,7 +79,7 @@ class NWSAlertProvider : WeatherAlertProvider, RateLimitedRequest { val root = JSONParser.deserializer(stream, AlertRootobject::class.java) - requireNotNull(root) + requireNotNull(root) { "AlertRootobject is null" } alerts = createWeatherAlerts(root) diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/OpenMeteoWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/OpenMeteoWeatherProvider.kt index fdc9851b7..c64ace2e3 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/OpenMeteoWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openmeteo/OpenMeteoWeatherProvider.kt @@ -271,8 +271,8 @@ class OpenMeteoWeatherProvider : WeatherProviderImpl(), PollenProvider { } }.getOrNull() - requireNotNull(root) - requireNotNull(aqiRoot) + requireNotNull(root) { "ForecastResponse is null" } + requireNotNull(aqiRoot) { "AQIResponse is null" } weather = createWeatherData(root, aqiRoot) } catch (ex: Exception) { @@ -365,7 +365,7 @@ class OpenMeteoWeatherProvider : WeatherProviderImpl(), PollenProvider { JSONParser.deserializer(it, AQIResponse::class.java) } - requireNotNull(root) + requireNotNull(root) { "AQIResponse is null" } root.current?.let { current -> val treePollenMeasure = diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/location/OpenWeatherMapLocationProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/location/OpenWeatherMapLocationProvider.kt index 780bab1d8..d2e214875 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/location/OpenWeatherMapLocationProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/location/OpenWeatherMapLocationProvider.kt @@ -10,7 +10,10 @@ import com.thewizrd.shared_resources.locationdata.LocationQuery import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.await import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.getStream import com.thewizrd.shared_resources.sharedDeps -import com.thewizrd.shared_resources.utils.* +import com.thewizrd.shared_resources.utils.Coordinate +import com.thewizrd.shared_resources.utils.JSONParser +import com.thewizrd.shared_resources.utils.LocaleUtils +import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.weather_api.keys.Keys import com.thewizrd.weather_api.locationdata.WeatherLocationProviderImpl @@ -26,7 +29,7 @@ import okhttp3.internal.closeQuietly import java.io.IOException import java.net.HttpURLConnection import java.text.DecimalFormat -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit class OpenWeatherMapLocationProvider : WeatherLocationProviderImpl() { @@ -99,7 +102,7 @@ class OpenWeatherMapLocationProvider : WeatherLocationProviderImpl() { val arrListType = listType() val root = JSONParser.deserializer>(stream, arrListType) - requireNotNull(root) + requireNotNull(root) { "List is null" } locations = HashSet() @@ -189,7 +192,7 @@ class OpenWeatherMapLocationProvider : WeatherLocationProviderImpl() { val arrListType = listType() val root = JSONParser.deserializer>(stream, arrListType) - requireNotNull(root) + requireNotNull(root) { "List is null" } result = root.first() diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/OpenWeatherMapProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/OpenWeatherMapProvider.kt index c3a2710f8..6b61519dc 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/OpenWeatherMapProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/OpenWeatherMapProvider.kt @@ -214,8 +214,8 @@ class OpenWeatherMapProvider : WeatherProviderImpl { currentStream.closeQuietly() forecastStream.closeQuietly() - requireNotNull(currRoot) - requireNotNull(foreRoot) + requireNotNull(currRoot) { "currRoot is null" } + requireNotNull(foreRoot) { "foreRoot is null" } weather = createWeatherData(currRoot, foreRoot) } catch (ex: Exception) { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/OWMOneCallWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/OWMOneCallWeatherProvider.kt index e6228a661..d954b16b6 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/OWMOneCallWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/openweather/weather/onecall/OWMOneCallWeatherProvider.kt @@ -213,7 +213,7 @@ class OWMOneCallWeatherProvider : WeatherProviderImpl, AirQualityProvider { // End Stream stream.closeQuietly() - requireNotNull(root) + requireNotNull(root) { "OneCallRootobject is null" } weather = createOneCallWeatherData(root) } catch (ex: Exception) { @@ -349,7 +349,7 @@ class OWMOneCallWeatherProvider : WeatherProviderImpl, AirQualityProvider { // End Stream stream.closeQuietly() - requireNotNull(root) + requireNotNull(root) { "AirPollutionResponse is null" } aqiData = createAirQuality(root) } catch (ex: Exception) { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/TomorrowIOWeatherProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/TomorrowIOWeatherProvider.kt index a31f2a1aa..f34cad29a 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/TomorrowIOWeatherProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/tomorrow/TomorrowIOWeatherProvider.kt @@ -251,7 +251,7 @@ class TomorrowIOWeatherProvider : WeatherProviderImpl(), PollenProvider { JSONParser.deserializer(it, Rootobject::class.java) } - requireNotNull(root) + requireNotNull(root) { "Rootobject is null" } var minutelyRoot: Rootobject? = null var alertsRoot: AlertsRootobject? = null @@ -351,7 +351,7 @@ class TomorrowIOWeatherProvider : WeatherProviderImpl(), PollenProvider { JSONParser.deserializer(it, Rootobject::class.java) } - requireNotNull(root) + requireNotNull(root) { "Rootobject is null" } root.data.timelines.firstOrNull()?.intervals?.firstOrNull()?.let { item -> pollenData = Pollen().apply { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/location/WeatherApiLocationProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/location/WeatherApiLocationProvider.kt index 2d906ca74..a98f58225 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/location/WeatherApiLocationProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/location/WeatherApiLocationProvider.kt @@ -9,7 +9,11 @@ import com.thewizrd.shared_resources.locationdata.LocationQuery import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.await import com.thewizrd.shared_resources.okhttp3.OkHttp3Utils.getStream import com.thewizrd.shared_resources.sharedDeps -import com.thewizrd.shared_resources.utils.* +import com.thewizrd.shared_resources.utils.ConversionMethods +import com.thewizrd.shared_resources.utils.Coordinate +import com.thewizrd.shared_resources.utils.JSONParser +import com.thewizrd.shared_resources.utils.LocaleUtils +import com.thewizrd.shared_resources.utils.Logger import com.thewizrd.shared_resources.weatherdata.WeatherAPI import com.thewizrd.shared_resources.weatherdata.WeatherAPI.LocationProviders import com.thewizrd.weather_api.google.location.isGeocoderAvailable @@ -26,7 +30,7 @@ import okhttp3.internal.closeQuietly import java.io.IOException import java.net.URLEncoder import java.text.DecimalFormat -import java.util.* +import java.util.Locale import java.util.concurrent.TimeUnit import kotlin.math.abs @@ -100,7 +104,7 @@ class WeatherApiLocationProvider : WeatherLocationProviderImpl() { val arrListType = listType() val root = JSONParser.deserializer>(stream, arrListType) - requireNotNull(root) + requireNotNull(root) { "List is null" } for (result in root) { val added = locations.add(createLocationModel(result, weatherAPI!!)) @@ -207,7 +211,7 @@ class WeatherApiLocationProvider : WeatherLocationProviderImpl() { val arrListType = listType() val locations = JSONParser.deserializer>(stream, arrListType) - requireNotNull(locations) + requireNotNull(locations) { "List is null" } for (item in locations) { if (abs( diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherApiProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherApiProvider.kt index fce4a44ac..754e83e15 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherApiProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherapi/weather/WeatherApiProvider.kt @@ -204,7 +204,7 @@ class WeatherApiProvider : WeatherProviderImpl(), WeatherAlertProvider, PollenPr // End Stream stream.closeQuietly() - requireNotNull(root) + requireNotNull(root) { "ForecastResponse is null" } weather = createWeatherData(root) } catch (ex: Exception) { @@ -280,7 +280,7 @@ class WeatherApiProvider : WeatherProviderImpl(), WeatherAlertProvider, PollenPr // End Stream stream.closeQuietly() - requireNotNull(root) + requireNotNull(root) { "ForecastResponse is null" } alerts = createWeatherAlerts(root.alerts) } catch (ex: Exception) { @@ -343,7 +343,7 @@ class WeatherApiProvider : WeatherProviderImpl(), WeatherAlertProvider, PollenPr // End Stream stream.closeQuietly() - requireNotNull(root) + requireNotNull(root) { "ForecastResponse is null" } root.current?.pollen?.let { currentPollen -> val treePollenValue = maxOf( diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherBitIOProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherBitIOProvider.kt index 98372e50d..5f5116c84 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherBitIOProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherbit/WeatherBitIOProvider.kt @@ -221,8 +221,8 @@ class WeatherBitIOProvider : WeatherProviderImpl(), WeatherAlertProvider { currentStream.closeQuietly() forecastStream.closeQuietly() - requireNotNull(currRoot) - requireNotNull(foreRoot) + requireNotNull(currRoot) { "currRoot is null" } + requireNotNull(foreRoot) { "foreRoot is null" } var hourlyRoot: HourlyResponse? = null @@ -307,7 +307,7 @@ class WeatherBitIOProvider : WeatherProviderImpl(), WeatherAlertProvider { // End Stream stream.closeQuietly() - requireNotNull(root) + requireNotNull(root) { "AlertsResponse is null" } alerts = createWeatherAlerts(root.alerts, root.timezone!!) } catch (ex: Exception) { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherKitProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherKitProvider.kt index 748ac0f89..bd918019a 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherKitProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherkit/WeatherKitProvider.kt @@ -159,7 +159,7 @@ class WeatherKitProvider : WeatherProviderImpl() { // End Stream stream.closeQuietly() - requireNotNull(root) + requireNotNull(root) { "weatherkit.Weather is null" } weather = createWeatherData(root) } catch (ex: Exception) { diff --git a/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherUnlockedProvider.kt b/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherUnlockedProvider.kt index 587114d32..ff7836fcf 100644 --- a/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherUnlockedProvider.kt +++ b/weather-api/src/main/java/com/thewizrd/weather_api/weatherunlocked/WeatherUnlockedProvider.kt @@ -152,8 +152,8 @@ class WeatherUnlockedProvider : WeatherProviderImpl() { currentStream.closeQuietly() forecastStream.closeQuietly() - requireNotNull(currRoot) - requireNotNull(foreRoot) + requireNotNull(currRoot) { "currRoot is null" } + requireNotNull(foreRoot) { "foreRoot is null" } weather = createWeatherData(currRoot, foreRoot) } catch (ex: Exception) {