not working
This commit is contained in:
parent
a13db7aa7d
commit
376f28dc9d
21 changed files with 360 additions and 57 deletions
|
@ -3,6 +3,7 @@ package com.henryhiles.qweather.di
|
|||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import com.henryhiles.qweather.domain.remote.GeocodingApi
|
||||
import com.henryhiles.qweather.domain.remote.WeatherApi
|
||||
import okhttp3.Cache
|
||||
import okhttp3.Interceptor
|
||||
|
@ -30,7 +31,6 @@ private fun isNetworkAvailable(context: Context): Boolean {
|
|||
|
||||
val appModule = module {
|
||||
fun provideWeatherApi(context: Context): WeatherApi {
|
||||
|
||||
val cacheControlInterceptor = Interceptor { chain ->
|
||||
val originalResponse = chain.proceed(chain.request())
|
||||
if (isNetworkAvailable(context)) {
|
||||
|
@ -50,13 +50,25 @@ val appModule = module {
|
|||
val cache = Cache(context.cacheDir, cacheSize.toLong())
|
||||
val builder = Builder()
|
||||
.cache(cache)
|
||||
builder.networkInterceptors()
|
||||
.add(cacheControlInterceptor)
|
||||
builder.networkInterceptors().add(cacheControlInterceptor)
|
||||
val okHttpClient = builder.build()
|
||||
|
||||
return Retrofit.Builder().baseUrl("https://api.open-meteo.com").client(okHttpClient)
|
||||
.addConverterFactory(MoshiConverterFactory.create()).build().create()
|
||||
return Retrofit.Builder()
|
||||
.baseUrl("https://api.open-meteo.com")
|
||||
.client(okHttpClient)
|
||||
.addConverterFactory(MoshiConverterFactory.create())
|
||||
.build()
|
||||
.create()
|
||||
}
|
||||
|
||||
fun provideGeocodingApi(): GeocodingApi {
|
||||
return Retrofit.Builder()
|
||||
.baseUrl("https://geocoding-api.open-meteo.com")
|
||||
.addConverterFactory(MoshiConverterFactory.create())
|
||||
.build()
|
||||
.create()
|
||||
}
|
||||
|
||||
singleOf(::provideWeatherApi)
|
||||
singleOf(::provideGeocodingApi)
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
package com.henryhiles.qweather.di
|
||||
|
||||
import com.henryhiles.qweather.presentation.screenmodel.AppearancePreferenceManager
|
||||
import com.henryhiles.qweather.presentation.screenmodel.LocationPreferenceManager
|
||||
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val managerModule = module {
|
||||
singleOf(::AppearancePreferenceManager)
|
||||
singleOf(::LocationPreferenceManager)
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
package com.henryhiles.qweather.di
|
||||
|
||||
import com.henryhiles.qweather.domain.repository.GeocodingRepository
|
||||
import com.henryhiles.qweather.domain.repository.WeatherRepository
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val repositoryModule = module {
|
||||
singleOf(::WeatherRepository)
|
||||
singleOf(::GeocodingRepository)
|
||||
}
|
|
@ -3,11 +3,13 @@ package com.henryhiles.qweather.di
|
|||
import com.henryhiles.qweather.presentation.screenmodel.AppearancePreferencesScreenModel
|
||||
import com.henryhiles.qweather.presentation.screenmodel.DailyWeatherScreenModel
|
||||
import com.henryhiles.qweather.presentation.screenmodel.HourlyWeatherScreenModel
|
||||
import com.henryhiles.qweather.presentation.screenmodel.LocationPickerScreenModel
|
||||
import org.koin.core.module.dsl.factoryOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val screenModelModule = module {
|
||||
factoryOf(::AppearancePreferencesScreenModel)
|
||||
factoryOf(::LocationPickerScreenModel)
|
||||
factoryOf(::HourlyWeatherScreenModel)
|
||||
factoryOf(::DailyWeatherScreenModel)
|
||||
}
|
|
@ -8,7 +8,7 @@ import android.location.Location
|
|||
import android.location.LocationManager
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
class LocationTracker constructor(
|
||||
class LocationTracker(
|
||||
private val application: Application
|
||||
) {
|
||||
fun getCurrentLocation(): Location? {
|
||||
|
|
|
@ -10,15 +10,15 @@ data class DailyWeatherDataDto(
|
|||
@field:Json(name = "precipitation_probability_max")
|
||||
val precipitationProbabilityMax: List<Int>,
|
||||
@field:Json(name = "precipitation_sum")
|
||||
val precipitationSum: List<Double>,
|
||||
val precipitationSum: List<Float>,
|
||||
@field:Json(name = "windspeed_10m_max")
|
||||
val windSpeedMax: List<Double>,
|
||||
val windSpeedMax: List<Float>,
|
||||
@field:Json(name = "temperature_2m_max")
|
||||
val temperatureMax: List<Double>,
|
||||
val temperatureMax: List<Float>,
|
||||
@field:Json(name = "temperature_2m_min")
|
||||
val temperatureMin: List<Double>,
|
||||
val temperatureMin: List<Float>,
|
||||
@field:Json(name = "apparent_temperature_max")
|
||||
val apparentTemperatureMax: List<Double>,
|
||||
val apparentTemperatureMax: List<Float>,
|
||||
@field:Json(name = "apparent_temperature_min")
|
||||
val apparentTemperatureMin: List<Double>
|
||||
val apparentTemperatureMin: List<Float>
|
||||
)
|
|
@ -0,0 +1,11 @@
|
|||
package com.henryhiles.qweather.domain.remote
|
||||
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface GeocodingApi {
|
||||
@GET("v1/search?count=4")
|
||||
suspend fun getGeocodingData(
|
||||
@Query("name") location: String,
|
||||
): GeocodingDto
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.henryhiles.qweather.domain.remote
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
|
||||
data class GeocodingDto(
|
||||
@field:Json(name = "results")
|
||||
val results: List<GeocodingLocationDto>
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
package com.henryhiles.qweather.domain.remote
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
|
||||
data class GeocodingLocationDto(
|
||||
@field:Json(name = "name")
|
||||
val city: String,
|
||||
@field:Json(name = "country")
|
||||
val country: String,
|
||||
@field:Json(name = "admin1")
|
||||
val admin: String,
|
||||
@field:Json(name = "latitude")
|
||||
val latitude: Float,
|
||||
@field:Json(name = "longitude")
|
||||
val longitude: Float
|
||||
)
|
|
@ -6,13 +6,13 @@ data class HourlyWeatherDataDto(
|
|||
@field:Json(name = "time")
|
||||
val time: List<String>,
|
||||
@field:Json(name = "temperature_2m")
|
||||
val temperature: List<Double>,
|
||||
val temperature: List<Float>,
|
||||
@field:Json(name = "apparent_temperature")
|
||||
val apparentTemperature: List<Double>,
|
||||
val apparentTemperature: List<Float>,
|
||||
@field:Json(name = "weathercode")
|
||||
val weatherCode: List<Int>,
|
||||
@field:Json(name = "precipitation_probability")
|
||||
val precipitationProbability: List<Int>,
|
||||
@field:Json(name = "windspeed_10m")
|
||||
val windSpeed: List<Double>,
|
||||
val windSpeed: List<Float>,
|
||||
)
|
|
@ -15,14 +15,14 @@ const val URL = "v1/forecast?$HOURLY&$DAILY&$TIMEZONE&$FORECAST_DAYS"
|
|||
interface WeatherApi {
|
||||
@GET(URL)
|
||||
suspend fun getWeatherData(
|
||||
@Query("latitude") lat: Double,
|
||||
@Query("longitude") long: Double,
|
||||
@Query("latitude") lat: Float,
|
||||
@Query("longitude") long: Float,
|
||||
): WeatherDto
|
||||
|
||||
@Headers("Cache-Control: no-cache")
|
||||
@GET(URL)
|
||||
suspend fun getWeatherDataWithoutCache(
|
||||
@Query("latitude") lat: Double,
|
||||
@Query("longitude") long: Double,
|
||||
@Query("latitude") lat: Float,
|
||||
@Query("longitude") long: Float,
|
||||
): WeatherDto
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.henryhiles.qweather.domain.repository
|
||||
|
||||
import com.henryhiles.qweather.domain.remote.GeocodingApi
|
||||
import com.henryhiles.qweather.domain.remote.GeocodingLocationDto
|
||||
import com.henryhiles.qweather.domain.util.Resource
|
||||
|
||||
class GeocodingRepository(private val api: GeocodingApi) {
|
||||
suspend fun getGeocodingData(location: String): Resource<List<GeocodingLocationDto>> {
|
||||
return try {
|
||||
Resource.Success(
|
||||
data = api.getGeocodingData(location = location).results
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Resource.Error(e.message ?: "An unknown error occurred.")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,10 +7,10 @@ import com.henryhiles.qweather.domain.util.Resource
|
|||
import com.henryhiles.qweather.domain.weather.DailyWeatherData
|
||||
import com.henryhiles.qweather.domain.weather.HourlyWeatherInfo
|
||||
|
||||
class WeatherRepository constructor(private val api: WeatherApi) {
|
||||
class WeatherRepository(private val api: WeatherApi) {
|
||||
suspend fun getHourlyWeatherData(
|
||||
lat: Double,
|
||||
long: Double,
|
||||
lat: Float,
|
||||
long: Float,
|
||||
cache: Boolean = true
|
||||
): Resource<HourlyWeatherInfo> {
|
||||
return try {
|
||||
|
@ -31,8 +31,8 @@ class WeatherRepository constructor(private val api: WeatherApi) {
|
|||
}
|
||||
|
||||
suspend fun getDailyWeatherData(
|
||||
lat: Double,
|
||||
long: Double,
|
||||
lat: Float,
|
||||
long: Float,
|
||||
cache: Boolean = true
|
||||
): Resource<List<DailyWeatherData>> {
|
||||
return try {
|
||||
|
@ -43,8 +43,7 @@ class WeatherRepository constructor(private val api: WeatherApi) {
|
|||
) else api.getWeatherDataWithoutCache(
|
||||
lat = lat,
|
||||
long = long
|
||||
))
|
||||
.dailyWeatherData.toDailyWeatherDataMap()
|
||||
)).dailyWeatherData.toDailyWeatherDataMap()
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
|
|
|
@ -5,17 +5,23 @@ import androidx.activity.ComponentActivity
|
|||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.ui.Modifier
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.transitions.SlideTransition
|
||||
import com.henryhiles.qweather.presentation.screen.LocationPickerScreen
|
||||
import com.henryhiles.qweather.presentation.screen.MainScreen
|
||||
import com.henryhiles.qweather.presentation.screenmodel.AppearancePreferenceManager
|
||||
import com.henryhiles.qweather.presentation.screenmodel.LocationPreferenceManager
|
||||
import com.henryhiles.qweather.presentation.screenmodel.Theme
|
||||
import com.henryhiles.qweather.presentation.ui.theme.WeatherAppTheme
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class QWeatherActivity : ComponentActivity() {
|
||||
private val prefs: AppearancePreferenceManager by inject()
|
||||
private val location: LocationPreferenceManager by inject()
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -26,10 +32,12 @@ class QWeatherActivity : ComponentActivity() {
|
|||
Theme.LIGHT -> false
|
||||
Theme.DARK -> true
|
||||
}
|
||||
val isLocationSet = location.location != ""
|
||||
|
||||
WeatherAppTheme(darkTheme = isDark, monet = prefs.monet) {
|
||||
Surface {
|
||||
Navigator(screen = MainScreen()) {
|
||||
Surface(modifier = Modifier.fillMaxSize()) {
|
||||
Text(text = location.location)
|
||||
Navigator(screen = if (isLocationSet) MainScreen() else LocationPickerScreen()) {
|
||||
SlideTransition(it)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.*
|
|||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -21,8 +23,8 @@ fun WeatherHour(
|
|||
onChangeSelected: () -> Unit
|
||||
) {
|
||||
data.let {
|
||||
val formattedTime = remember(it) {
|
||||
it.time.format(DateTimeFormatter.ofPattern("HH:mm"))
|
||||
val formattedTime by remember {
|
||||
derivedStateOf { it.time.format(DateTimeFormatter.ofPattern("HH:mm")) }
|
||||
}
|
||||
Card(modifier = modifier.clickable {
|
||||
onChangeSelected()
|
||||
|
@ -44,21 +46,7 @@ fun WeatherHour(
|
|||
|
||||
Text(text = "${it.temperature}°C")
|
||||
}
|
||||
|
||||
}
|
||||
// Column(
|
||||
// horizontalAlignment = Alignment.CenterHorizontally,
|
||||
// verticalArrangement = Arrangement.SpaceBetween,
|
||||
// modifier = modifier
|
||||
// ) {
|
||||
// Text(text = formattedTime)
|
||||
// Image(
|
||||
// painter = painterResource(id = it.weatherType.iconRes),
|
||||
// contentDescription = "Image of ${it.weatherType.weatherDesc}",
|
||||
// modifier = Modifier.width(40.dp)
|
||||
// )
|
||||
// Text(text = "${it.temperature}°C")
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
|
@ -20,14 +20,10 @@ import com.henryhiles.qweather.presentation.components.settings.SettingsSwitch
|
|||
import com.henryhiles.qweather.presentation.screenmodel.AppearancePreferencesScreenModel
|
||||
|
||||
class AppearanceSettingsScreen : Screen {
|
||||
|
||||
@Composable
|
||||
override fun Content() = Screen()
|
||||
|
||||
@Composable
|
||||
private fun Screen() {
|
||||
override fun Content() {
|
||||
val screenModel: AppearancePreferencesScreenModel = getScreenModel()
|
||||
val ctx = LocalContext.current
|
||||
val context = LocalContext.current
|
||||
|
||||
Scaffold(topBar = {
|
||||
SmallToolbar(
|
||||
|
@ -51,7 +47,7 @@ class AppearanceSettingsScreen : Screen {
|
|||
SettingsItemChoice(
|
||||
label = stringResource(R.string.appearance_theme),
|
||||
pref = screenModel.prefs.theme,
|
||||
labelFactory = { ctx.getString(it.label) }
|
||||
labelFactory = { context.getString(it.label) }
|
||||
) { screenModel.prefs.theme = it }
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
package com.henryhiles.qweather.presentation.screen
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.outlined.MyLocation
|
||||
import androidx.compose.material.icons.outlined.Search
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.koin.getScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import com.henryhiles.qweather.R
|
||||
import com.henryhiles.qweather.presentation.screenmodel.LocationPickerScreenModel
|
||||
|
||||
class LocationPickerScreen : Screen {
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val screenModel: LocationPickerScreenModel = getScreenModel()
|
||||
var latitude by remember { mutableStateOf(0f) }
|
||||
var longitude by remember { mutableStateOf(0f) }
|
||||
var location by remember { mutableStateOf("") }
|
||||
var locationSearch by remember { mutableStateOf("") }
|
||||
val navigator = LocalNavigator.current
|
||||
val context = LocalContext.current
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
screenModel.state.error?.let {
|
||||
AlertDialog(
|
||||
onDismissRequest = {},
|
||||
confirmButton = {},
|
||||
title = { Text(text = stringResource(id = R.string.error)) },
|
||||
text = {
|
||||
SelectionContainer {
|
||||
Text(
|
||||
text = it,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
} ?: AlertDialog(
|
||||
onDismissRequest = {},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
screenModel.prefs.location = location
|
||||
screenModel.prefs.latitude = latitude
|
||||
screenModel.prefs.longitude = longitude
|
||||
navigator?.push(MainScreen())
|
||||
},
|
||||
enabled = location != ""
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.action_apply))
|
||||
}
|
||||
},
|
||||
title = { Text(text = stringResource(id = R.string.location_choose)) },
|
||||
text = {
|
||||
Column {
|
||||
OutlinedTextField(
|
||||
label = { Text(text = stringResource(id = R.string.location)) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
capitalization = KeyboardCapitalization.Sentences,
|
||||
imeAction = ImeAction.Search
|
||||
),
|
||||
keyboardActions = KeyboardActions(onSearch = {
|
||||
screenModel.loadGeolocationInfo(
|
||||
locationSearch
|
||||
)
|
||||
}),
|
||||
maxLines = 1,
|
||||
value = locationSearch,
|
||||
onValueChange = {
|
||||
locationSearch = it
|
||||
},
|
||||
trailingIcon = {
|
||||
if (locationSearch == "")
|
||||
IconButton(onClick = {
|
||||
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.MyLocation,
|
||||
contentDescription = stringResource(id = R.string.location_auto_pick)
|
||||
)
|
||||
}
|
||||
else
|
||||
IconButton(onClick = {
|
||||
screenModel.loadGeolocationInfo(
|
||||
locationSearch
|
||||
)
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Search,
|
||||
contentDescription = stringResource(id = R.string.action_search)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(text = "${screenModel.state.locations != null}")
|
||||
screenModel.state.locations?.let {
|
||||
Text(
|
||||
text = "hi"
|
||||
)
|
||||
}
|
||||
|
||||
if (screenModel.state.isLoading) CircularProgressIndicator(
|
||||
modifier = Modifier.align(
|
||||
Alignment.CenterHorizontally
|
||||
)
|
||||
) else screenModel.state.locations?.let {
|
||||
LazyColumn {
|
||||
items(it) {
|
||||
val locationText by remember {
|
||||
mutableStateOf(
|
||||
context.getString(
|
||||
R.string.location_string,
|
||||
it.city, it.admin, it.country
|
||||
)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Card(modifier = Modifier.clickable {
|
||||
location = locationText
|
||||
longitude = it.longitude
|
||||
latitude = it.latitude
|
||||
}) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (location == locationText) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Check,
|
||||
contentDescription = stringResource(
|
||||
id = R.string.selected
|
||||
),
|
||||
modifier = Modifier.height(16.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
Text(text = locationText)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ data class DailyWeatherState(
|
|||
val expanded: Int? = null
|
||||
)
|
||||
|
||||
class DailyWeatherScreenModel constructor(
|
||||
class DailyWeatherScreenModel(
|
||||
private val repository: WeatherRepository,
|
||||
private val locationTracker: LocationTracker,
|
||||
) : ScreenModel {
|
||||
|
@ -34,8 +34,8 @@ class DailyWeatherScreenModel constructor(
|
|||
currentLocation?.let { location ->
|
||||
state = when (val result =
|
||||
repository.getDailyWeatherData(
|
||||
lat = location.latitude,
|
||||
long = location.longitude,
|
||||
lat = location.latitude.toFloat(),
|
||||
long = location.longitude.toFloat(),
|
||||
cache = cache
|
||||
)) {
|
||||
is Resource.Success -> {
|
||||
|
|
|
@ -20,7 +20,7 @@ data class HourlyWeatherState(
|
|||
val selected: Int? = null
|
||||
)
|
||||
|
||||
class HourlyWeatherScreenModel constructor(
|
||||
class HourlyWeatherScreenModel(
|
||||
private val repository: WeatherRepository,
|
||||
private val locationTracker: LocationTracker,
|
||||
private val context: Context
|
||||
|
@ -35,8 +35,8 @@ class HourlyWeatherScreenModel constructor(
|
|||
currentLocation?.let { location ->
|
||||
state = when (val result =
|
||||
repository.getHourlyWeatherData(
|
||||
lat = location.latitude,
|
||||
long = location.longitude,
|
||||
lat = location.latitude.toFloat(),
|
||||
long = location.longitude.toFloat(),
|
||||
cache = cache
|
||||
)) {
|
||||
is Resource.Success -> {
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package com.henryhiles.qweather.presentation.screenmodel
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import cafe.adriel.voyager.core.model.coroutineScope
|
||||
import com.henryhiles.qweather.domain.location.LocationTracker
|
||||
import com.henryhiles.qweather.domain.manager.BasePreferenceManager
|
||||
import com.henryhiles.qweather.domain.remote.GeocodingLocationDto
|
||||
import com.henryhiles.qweather.domain.repository.GeocodingRepository
|
||||
import com.henryhiles.qweather.domain.util.Resource
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
data class LocationPickerState(
|
||||
val locations: List<GeocodingLocationDto>? = null,
|
||||
val isLoading: Boolean = false,
|
||||
val error: String? = null,
|
||||
)
|
||||
|
||||
class LocationPreferenceManager(context: Context) :
|
||||
BasePreferenceManager(context.getSharedPreferences("location", Context.MODE_PRIVATE)) {
|
||||
var latitude by floatPreference("lat", 0f)
|
||||
var longitude by floatPreference("long", 0f)
|
||||
var location by stringPreference("string")
|
||||
}
|
||||
|
||||
class LocationPickerScreenModel(
|
||||
val prefs: LocationPreferenceManager,
|
||||
private val repository: GeocodingRepository,
|
||||
private val locationTracker: LocationTracker,
|
||||
private val context: Context
|
||||
) : ScreenModel {
|
||||
var state by mutableStateOf(LocationPickerState())
|
||||
private set
|
||||
|
||||
fun loadGeolocationInfo(location: String) {
|
||||
coroutineScope.launch {
|
||||
state = state.copy(isLoading = true, error = null)
|
||||
|
||||
state = when (val result =
|
||||
repository.getGeocodingData(
|
||||
location = location
|
||||
)) {
|
||||
is Resource.Success -> {
|
||||
state.copy(
|
||||
locations = result.data,
|
||||
isLoading = false,
|
||||
error = null,
|
||||
)
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
state.copy(
|
||||
locations = null,
|
||||
isLoading = false,
|
||||
error = result.message
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,11 +5,15 @@
|
|||
<string name="tab_settings">Settings</string>
|
||||
|
||||
<string name="action_back">Back</string>
|
||||
<string name="action_apply">Apply</string>
|
||||
<string name="action_confirm">Confirm</string>
|
||||
<string name="action_open_about">About</string>
|
||||
<string name="action_search">Search</string>
|
||||
<string name="action_reload">Reload</string>
|
||||
<string name="action_try_again">Try Again</string>
|
||||
|
||||
<string name="selected">Selected</string>
|
||||
|
||||
<string name="appearance_theme">Theme</string>
|
||||
<string name="appearance_monet">Dynamic Theme</string>
|
||||
<string name="appearance_monet_description">Available on Android 12+</string>
|
||||
|
@ -17,6 +21,11 @@
|
|||
<string name="settings_appearance">Appearance</string>
|
||||
<string name="settings_appearance_description">Theme, code style</string>
|
||||
|
||||
<string name="location">Location</string>
|
||||
<string name="location_string">%1$s, %2$s, %3$s</string>
|
||||
<string name="location_auto_pick">Auto-pick location</string>
|
||||
<string name="location_choose">Choose a Location</string>
|
||||
|
||||
<string name="theme_system">System</string>
|
||||
<string name="theme_light">Light</string>
|
||||
<string name="theme_dark">Dark</string>
|
||||
|
|
Reference in a new issue