Skip to content

Commit

Permalink
Merge pull request #68 from odaridavid/fix-location-bugs
Browse files Browse the repository at this point in the history
Fix crashlytics non fatal bug cause of language + minor improvements
  • Loading branch information
odaridavid authored Mar 4, 2024
2 parents 6a504e0 + 502d727 commit 82e6ca0
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 15 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ In your `local.properties` you will need to add your Open Weather API key and co
```properties
OPEN_WEATHER_API_KEY = YOUR KEY
OPEN_WEATHER_BASE_URL=https://api.openweathermap.org
OPEN_WEATHER_ICONS_URL= http://openweathermap.org/img/wn/
OPEN_WEATHER_ICONS_URL= https://openweathermap.org/img/wn/
```

Check for one under [`Api Keys`](https://home.openweathermap.org/api_keys)
Expand Down
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ dependencies {
// Chucker
debugImplementation(libs.chucker.debug)
releaseImplementation(libs.chucker.release)

// Memory Leak Detection
debugImplementation(libs.leakcanary)
}

kapt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.github.odaridavid.weatherapp

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.github.odaridavid.weatherapp.core.api.Logger
import com.github.odaridavid.weatherapp.core.api.SettingsRepository
import com.github.odaridavid.weatherapp.core.model.DefaultLocation
import dagger.hilt.android.lifecycle.HiltViewModel
Expand All @@ -13,7 +14,8 @@ import javax.inject.Inject

@HiltViewModel
class MainViewModel @Inject constructor(
private val settingsRepository: SettingsRepository
private val settingsRepository: SettingsRepository,
private val logger: Logger
) : ViewModel() {

private val _state = MutableStateFlow(MainViewState())
Expand All @@ -37,6 +39,9 @@ class MainViewModel @Inject constructor(
}
setState { copy(defaultLocation = defaultLocation) }
}
is MainViewIntent.LogException -> {
logger.logException(mainViewIntent.throwable)
}
}
}

Expand All @@ -51,7 +56,7 @@ class MainViewModel @Inject constructor(
data class MainViewState(
val isPermissionGranted: Boolean = false,
val isLocationSettingEnabled: Boolean = false,
val defaultLocation: DefaultLocation? = null
val defaultLocation: DefaultLocation? = DefaultLocation(longitude = 0.0, latitude = 0.0)
)

sealed class MainViewIntent {
Expand All @@ -62,4 +67,6 @@ sealed class MainViewIntent {

data class ReceiveLocation(val latitude: Double, val longitude: Double) : MainViewIntent()

data class LogException(val throwable: Throwable) : MainViewIntent()

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ class DefaultSettingsRepository @Inject constructor(
"Version : ${BuildConfig.VERSION_NAME}-${BuildConfig.BUILD_TYPE}"

override fun getAvailableLanguages(): List<String> =
SupportedLanguage.values().map { it.languageName }
SupportedLanguage.entries.map { it.languageName }

override fun getAvailableUnits(): List<String> = Units.values().map { it.value }
override fun getAvailableUnits(): List<String> = Units.entries.map { it.value }

override suspend fun setDefaultLocation(defaultLocation: DefaultLocation) {
set(key = PREF_LAT_LNG, value = "${defaultLocation.latitude}/${defaultLocation.longitude}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ private fun getDate(utcInMillis: Long, formatPattern: String): String {

fun mapResponseCodeToThrowable(code: Int): Throwable = when (code) {
HttpURLConnection.HTTP_UNAUTHORIZED -> UnauthorizedException("Unauthorized access : $code")
in 400..499 -> ClientException("Client error : $code")
in 500..600 -> ServerException("Server error : $code")
in CLIENT_ERRORS -> ClientException("Client error : $code")
in SERVER_ERRORS -> ServerException("Server error : $code")
else -> GenericException("Generic error : $code")
}

Expand All @@ -102,3 +102,6 @@ fun mapThrowableToErrorType(throwable: Throwable): ErrorType {
}
return errorType
}

private val SERVER_ERRORS = 500..600
private val CLIENT_ERRORS = 400..499
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ fun WeatherAppScreensConfig(
.collectAsState()
.value

homeViewModel.processIntent(HomeScreenIntent.LoadWeatherData)

HomeScreen(
state = state,
onSettingClicked = { navController.navigate(Destinations.SETTINGS.route) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ class MainActivity : ComponentActivity() {
)
)
}
}.addOnFailureListener { exception ->
mainViewModel.processIntent(MainViewIntent.LogException(throwable = exception))
}
WeatherAppScreensConfig(navController = rememberNavController())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class HomeViewModel @Inject constructor(
defaultLocation = defaultLocation
)
}
processIntent(HomeScreenIntent.LoadWeatherData)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.odaridavid.weatherapp

import app.cash.turbine.test
import com.github.odaridavid.weatherapp.core.Result
import com.github.odaridavid.weatherapp.core.api.Logger
import com.github.odaridavid.weatherapp.core.api.SettingsRepository
import com.github.odaridavid.weatherapp.core.api.WeatherRepository
Expand Down Expand Up @@ -125,7 +126,11 @@ class HomeViewModelIntegrationTest {

@Test
fun `when we init the screen, then update the state`() = runBlocking {
val weatherRepository = createWeatherRepository()
val weatherRepository = mockk<WeatherRepository>() {
coEvery { fetchWeatherData(any(), any(), any()) } returns Result.Success(
fakeSuccessMappedWeatherResponse
)
}

val viewModel = createViewModel(weatherRepository = weatherRepository)

Expand All @@ -136,8 +141,8 @@ class HomeViewModelIntegrationTest {
),
locationName = "-",
language = "English",
weather = null,
isLoading = true,
weather = fakeSuccessMappedWeatherResponse,
isLoading = false,
errorMessageId = null
)

Expand All @@ -150,7 +155,11 @@ class HomeViewModelIntegrationTest {

@Test
fun `when we receive a city name, the state is updated with it`() = runTest {
val weatherRepository = mockk<WeatherRepository>()
val weatherRepository = mockk<WeatherRepository>() {
coEvery { fetchWeatherData(any(), any(), any()) } returns Result.Success(
fakeSuccessMappedWeatherResponse
)
}

val viewModel = createViewModel(
weatherRepository = weatherRepository
Expand All @@ -163,8 +172,8 @@ class HomeViewModelIntegrationTest {
),
locationName = "Paradise",
language = "English",
weather = null,
isLoading = true,
weather = fakeSuccessMappedWeatherResponse,
isLoading = false,
errorMessageId = null
)

Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ play-services-location = "21.1.0"
retrofit = "2.9.0"
truth = "1.4.2"
turbine = "1.0.0"
leakcanary = "3.0-alpha-1"

[libraries]
activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" }
Expand Down Expand Up @@ -88,6 +89,7 @@ playservices-location = { module = "com.google.android.gms:play-services-locatio
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
truth = { module = "com.google.truth:truth", version.ref = "truth" }
turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" }
leakcanary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" }

[plugins]
com-android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" }
Expand Down

0 comments on commit 82e6ca0

Please sign in to comment.