Fix: Fixed error with fetchWeatherData not finding url.

Signed-off-by: HeCodes2Much <wayne6324@gmail.com>
This commit is contained in:
HeCodes2Much
2024-07-05 20:51:08 +01:00
parent bdfa980621
commit 6d32eedbe1
2 changed files with 66 additions and 42 deletions

View File

@@ -26,10 +26,9 @@ import com.github.droidworksstudio.launcher.accessibility.ActionService
import com.github.droidworksstudio.launcher.helper.weather.WeatherResponse import com.github.droidworksstudio.launcher.helper.weather.WeatherResponse
import com.github.droidworksstudio.launcher.utils.WeatherApiService import com.github.droidworksstudio.launcher.utils.WeatherApiService
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import java.net.UnknownHostException
import java.util.Calendar import java.util.Calendar
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject 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, context: Context,
latitude: Float, latitude: Float,
longitude: Float longitude: Float
): WeatherResponse { ): WeatherResult {
// Check if cached data is available and not expired // Check if cached data is available and not expired
val cachedWeatherData = context.getWeatherDataFromCache() val cachedWeatherData = context.getWeatherDataFromCache()
if (cachedWeatherData?.let { System.currentTimeMillis() - it.timestamp < TimeUnit.MINUTES.toMillis(15) } == true) { 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 // Fetch weather data from the network
val apiKey = BuildConfig.API_KEY val apiKey = BuildConfig.API_KEY
val baseURL = "api.openweathermap.org"
val units = "metric" val units = "metric"
val retrofit = Retrofit.Builder() try {
.baseUrl("https://api.openweathermap.org/data/2.5/") val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create()) .baseUrl("https://$baseURL/data/2.5/")
.build() .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() val response = service.getWeather("$latitude", "$longitude", units, apiKey).execute()
if (response.isSuccessful) { if (response.isSuccessful) {
val weatherResponse = response.body() val weatherResponse = response.body()
if (weatherResponse != null) { if (weatherResponse != null) {
// Cache the fetched weather data // Cache the fetched weather data
context.cacheWeatherData(weatherResponse) context.cacheWeatherData(weatherResponse)
weatherResponse return WeatherResult.Success(weatherResponse)
} else { } else {
throw NullPointerException("Weather response body is null") return WeatherResult.Failure("Weather response body is null")
} }
} else { } 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}")
} }
} }

View File

@@ -28,6 +28,7 @@ import androidx.navigation.fragment.findNavController
import com.github.droidworksstudio.common.capitalizeEachWord import com.github.droidworksstudio.common.capitalizeEachWord
import com.github.droidworksstudio.common.hasInternetPermission import com.github.droidworksstudio.common.hasInternetPermission
import com.github.droidworksstudio.common.hideKeyboard import com.github.droidworksstudio.common.hideKeyboard
import com.github.droidworksstudio.common.showLongToast
import com.github.droidworksstudio.launcher.R import com.github.droidworksstudio.launcher.R
import com.github.droidworksstudio.launcher.databinding.FragmentWidgetsBinding import com.github.droidworksstudio.launcher.databinding.FragmentWidgetsBinding
import com.github.droidworksstudio.launcher.helper.AppHelper 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.listener.ScrollEventListener
import com.github.droidworksstudio.launcher.utils.Constants import com.github.droidworksstudio.launcher.utils.Constants
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -120,6 +123,7 @@ class WidgetFragment : Fragment(),
} }
@OptIn(DelicateCoroutinesApi::class)
private fun setupWeatherWidget() { private fun setupWeatherWidget() {
val sharedPreferences = val sharedPreferences =
context.getSharedPreferences(Constants.WEATHER_PREFS, Context.MODE_PRIVATE) context.getSharedPreferences(Constants.WEATHER_PREFS, Context.MODE_PRIVATE)
@@ -139,7 +143,9 @@ class WidgetFragment : Fragment(),
if (!showWeatherWidget || !context.hasInternetPermission()) return@launch if (!showWeatherWidget || !context.hasInternetPermission()) return@launch
try { try {
val weatherDeferred = async { appHelper.fetchWeatherData(context, latitude, longitude) } val weatherDeferred = GlobalScope.async {
appHelper.fetchWeatherData(context, latitude, longitude)
}
// Prepare UI elements concurrently // Prepare UI elements concurrently
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@@ -163,40 +169,50 @@ class WidgetFragment : Fragment(),
} }
} }
val weatherResponse = weatherDeferred.await() val result = weatherDeferred.await()
Log.d("weatherResponse", "$weatherResponse") Log.d("weatherResponse", "$result")
withContext(Dispatchers.Main) { when (result) {
val timestamp = convertTimestampToReadableDate(weatherResponse.dt) is AppHelper.WeatherResult.Success -> {
binding.apply { val weatherResponse = result.weatherResponse
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 weatherIconBitmap = createWeatherIcon(context, setWeatherIcon(context, weatherResponse.weather[0].id)) withContext(Dispatchers.Main) {
weatherIcon.setImageBitmap(weatherIconBitmap) // Ensure this matches your ImageView ID val timestamp = convertTimestampToReadableDate(weatherResponse.dt)
weatherIcon.setColorFilter(widgetTextColor) 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)) val weatherIconBitmap = createWeatherIcon(context, setWeatherIcon(context, weatherResponse.weather[0].id))
sunriseIcon.setImageBitmap(sunriseIconBitmap) weatherIcon.setImageBitmap(weatherIconBitmap) // Ensure this matches your ImageView ID
sunriseIcon.setColorFilter(widgetTextColor) weatherIcon.setColorFilter(widgetTextColor)
val sunsetIconBitmap = createSunIcon(context, getString(R.string.sunset_icon)) val sunriseIconBitmap = createSunIcon(context, getString(R.string.sunrise_icon))
sunsetIcon.setImageBitmap(sunsetIconBitmap) sunriseIcon.setImageBitmap(sunriseIconBitmap)
sunsetIcon.setColorFilter(widgetTextColor) sunriseIcon.setColorFilter(widgetTextColor)
val sunriseTime = convertTimestampToReadableDate(weatherResponse.sys.sunrise) val sunsetIconBitmap = createSunIcon(context, getString(R.string.sunset_icon))
sunriseText.text = getString(R.string.widget_sunrise_time, sunriseTime) sunsetIcon.setImageBitmap(sunsetIconBitmap)
sunsetIcon.setColorFilter(widgetTextColor)
val sunsetTime = convertTimestampToReadableDate(weatherResponse.sys.sunset) val sunriseTime = convertTimestampToReadableDate(weatherResponse.sys.sunrise)
sunsetText.text = getString(R.string.widget_sunset_time, sunsetTime) 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) { } catch (e: Exception) {