From 6d32eedbe1ba0371b42e3be91db16d22721a478c Mon Sep 17 00:00:00 2001 From: HeCodes2Much Date: Fri, 5 Jul 2024 20:51:08 +0100 Subject: [PATCH] Fix: Fixed error with fetchWeatherData not finding url. Signed-off-by: HeCodes2Much --- .../launcher/helper/AppHelper.kt | 38 ++++++---- .../launcher/ui/widgets/WidgetFragment.kt | 70 ++++++++++++------- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppHelper.kt b/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppHelper.kt index a7ba2a9..398f17a 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppHelper.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/helper/AppHelper.kt @@ -26,10 +26,9 @@ import com.github.droidworksstudio.launcher.accessibility.ActionService import com.github.droidworksstudio.launcher.helper.weather.WeatherResponse import com.github.droidworksstudio.launcher.utils.WeatherApiService import com.google.gson.Gson -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory +import java.net.UnknownHostException import java.util.Calendar import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -252,43 +251,52 @@ class AppHelper @Inject constructor() { } } - suspend fun fetchWeatherData( + sealed class WeatherResult { + data class Success(val weatherResponse: WeatherResponse) : WeatherResult() + data class Failure(val errorMessage: String) : WeatherResult() + } + + fun fetchWeatherData( context: Context, latitude: Float, longitude: Float - ): WeatherResponse { + ): WeatherResult { // Check if cached data is available and not expired val cachedWeatherData = context.getWeatherDataFromCache() if (cachedWeatherData?.let { System.currentTimeMillis() - it.timestamp < TimeUnit.MINUTES.toMillis(15) } == true) { - return cachedWeatherData.weatherResponse + return WeatherResult.Success(cachedWeatherData.weatherResponse) } - // Fetch weather data from the network val apiKey = BuildConfig.API_KEY + val baseURL = "api.openweathermap.org" val units = "metric" - val retrofit = Retrofit.Builder() - .baseUrl("https://api.openweathermap.org/data/2.5/") - .addConverterFactory(GsonConverterFactory.create()) - .build() + try { + val retrofit = Retrofit.Builder() + .baseUrl("https://$baseURL/data/2.5/") + .addConverterFactory(GsonConverterFactory.create()) + .build() - val service = retrofit.create(WeatherApiService::class.java) + val service = retrofit.create(WeatherApiService::class.java) - return withContext(Dispatchers.IO) { val response = service.getWeather("$latitude", "$longitude", units, apiKey).execute() if (response.isSuccessful) { val weatherResponse = response.body() if (weatherResponse != null) { // Cache the fetched weather data context.cacheWeatherData(weatherResponse) - weatherResponse + return WeatherResult.Success(weatherResponse) } else { - throw NullPointerException("Weather response body is null") + return WeatherResult.Failure("Weather response body is null") } } else { - throw Exception("Failed to fetch weather data: ${response.errorBody()}") + return WeatherResult.Failure("Failed to fetch weather data: ${response.errorBody()}") } + } catch (e: UnknownHostException) { + return WeatherResult.Failure("Unknown Host : $baseURL") + } catch (e: Exception) { + return WeatherResult.Failure("${e.message}") } } diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/widgets/WidgetFragment.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/widgets/WidgetFragment.kt index 46b31f0..28fd288 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/widgets/WidgetFragment.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/widgets/WidgetFragment.kt @@ -28,6 +28,7 @@ import androidx.navigation.fragment.findNavController import com.github.droidworksstudio.common.capitalizeEachWord import com.github.droidworksstudio.common.hasInternetPermission import com.github.droidworksstudio.common.hideKeyboard +import com.github.droidworksstudio.common.showLongToast import com.github.droidworksstudio.launcher.R import com.github.droidworksstudio.launcher.databinding.FragmentWidgetsBinding import com.github.droidworksstudio.launcher.helper.AppHelper @@ -36,7 +37,9 @@ import com.github.droidworksstudio.launcher.listener.OnSwipeTouchListener import com.github.droidworksstudio.launcher.listener.ScrollEventListener import com.github.droidworksstudio.launcher.utils.Constants import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -120,6 +123,7 @@ class WidgetFragment : Fragment(), } + @OptIn(DelicateCoroutinesApi::class) private fun setupWeatherWidget() { val sharedPreferences = context.getSharedPreferences(Constants.WEATHER_PREFS, Context.MODE_PRIVATE) @@ -139,7 +143,9 @@ class WidgetFragment : Fragment(), if (!showWeatherWidget || !context.hasInternetPermission()) return@launch try { - val weatherDeferred = async { appHelper.fetchWeatherData(context, latitude, longitude) } + val weatherDeferred = GlobalScope.async { + appHelper.fetchWeatherData(context, latitude, longitude) + } // Prepare UI elements concurrently withContext(Dispatchers.Main) { @@ -163,40 +169,50 @@ class WidgetFragment : Fragment(), } } - val weatherResponse = weatherDeferred.await() - Log.d("weatherResponse", "$weatherResponse") + val result = weatherDeferred.await() + Log.d("weatherResponse", "$result") - withContext(Dispatchers.Main) { - val timestamp = convertTimestampToReadableDate(weatherResponse.dt) - binding.apply { - weatherCity.text = getString(R.string.widget_weather_location, weatherResponse.name, weatherResponse.sys.country) - weatherTemperature.text = getString(R.string.widget_weather_temp, weatherResponse.main.temp, temperatureScale) - weatherDescription.text = getString(R.string.widget_weather_description, weatherResponse.weather[0].description).capitalizeEachWord() - weatherWind.text = getString(R.string.widget_weather_wind, weatherResponse.wind.speed, speedScale) - weatherHumidity.text = getString(R.string.widget_weather_humidity, weatherResponse.main.humidity) - weatherLastRun.text = timestamp - weatherRefresh.text = getString(R.string.widget_weather_refresh, getString(R.string.refresh_icon)) + when (result) { + is AppHelper.WeatherResult.Success -> { + val weatherResponse = result.weatherResponse - val weatherIconBitmap = createWeatherIcon(context, setWeatherIcon(context, weatherResponse.weather[0].id)) - weatherIcon.setImageBitmap(weatherIconBitmap) // Ensure this matches your ImageView ID - weatherIcon.setColorFilter(widgetTextColor) + withContext(Dispatchers.Main) { + val timestamp = convertTimestampToReadableDate(weatherResponse.dt) + binding.apply { + weatherCity.text = getString(R.string.widget_weather_location, weatherResponse.name, weatherResponse.sys.country) + weatherTemperature.text = getString(R.string.widget_weather_temp, weatherResponse.main.temp, temperatureScale) + weatherDescription.text = getString(R.string.widget_weather_description, weatherResponse.weather[0].description).capitalizeEachWord() + weatherWind.text = getString(R.string.widget_weather_wind, weatherResponse.wind.speed, speedScale) + weatherHumidity.text = getString(R.string.widget_weather_humidity, weatherResponse.main.humidity) + weatherLastRun.text = timestamp + weatherRefresh.text = getString(R.string.widget_weather_refresh, getString(R.string.refresh_icon)) - val sunriseIconBitmap = createSunIcon(context, getString(R.string.sunrise_icon)) - sunriseIcon.setImageBitmap(sunriseIconBitmap) - sunriseIcon.setColorFilter(widgetTextColor) + val weatherIconBitmap = createWeatherIcon(context, setWeatherIcon(context, weatherResponse.weather[0].id)) + weatherIcon.setImageBitmap(weatherIconBitmap) // Ensure this matches your ImageView ID + weatherIcon.setColorFilter(widgetTextColor) - val sunsetIconBitmap = createSunIcon(context, getString(R.string.sunset_icon)) - sunsetIcon.setImageBitmap(sunsetIconBitmap) - sunsetIcon.setColorFilter(widgetTextColor) + val sunriseIconBitmap = createSunIcon(context, getString(R.string.sunrise_icon)) + sunriseIcon.setImageBitmap(sunriseIconBitmap) + sunriseIcon.setColorFilter(widgetTextColor) - val sunriseTime = convertTimestampToReadableDate(weatherResponse.sys.sunrise) - sunriseText.text = getString(R.string.widget_sunrise_time, sunriseTime) + val sunsetIconBitmap = createSunIcon(context, getString(R.string.sunset_icon)) + sunsetIcon.setImageBitmap(sunsetIconBitmap) + sunsetIcon.setColorFilter(widgetTextColor) - val sunsetTime = convertTimestampToReadableDate(weatherResponse.sys.sunset) - sunsetText.text = getString(R.string.widget_sunset_time, sunsetTime) + val sunriseTime = convertTimestampToReadableDate(weatherResponse.sys.sunrise) + sunriseText.text = getString(R.string.widget_sunrise_time, sunriseTime) + val sunsetTime = convertTimestampToReadableDate(weatherResponse.sys.sunset) + sunsetText.text = getString(R.string.widget_sunset_time, sunsetTime) - weatherRoot.visibility = View.VISIBLE + weatherRoot.visibility = View.VISIBLE + } + } + } + + is AppHelper.WeatherResult.Failure -> { + val errorMessage = result.errorMessage + context.showLongToast(errorMessage) } } } catch (e: Exception) {