Some ui changes and fixes
This commit is contained in:
parent
e75c7f770d
commit
3b456682f6
9 changed files with 65 additions and 87 deletions
|
@ -3,7 +3,6 @@ package com.henryhiles.qweather.presentation
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
|
@ -22,7 +21,6 @@ class QWeatherActivity : ComponentActivity() {
|
||||||
private val prefs: AppearancePreferenceManager by inject()
|
private val prefs: AppearancePreferenceManager by inject()
|
||||||
private val location: LocationPreferenceManager by inject()
|
private val location: LocationPreferenceManager by inject()
|
||||||
|
|
||||||
@OptIn(ExperimentalAnimationApi::class)
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContent {
|
setContent {
|
||||||
|
@ -36,9 +34,6 @@ class QWeatherActivity : ComponentActivity() {
|
||||||
Surface(modifier = Modifier.fillMaxSize()) {
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
Navigator(
|
Navigator(
|
||||||
screen = if (location.locations.isEmpty()) LocationPickerScreen() else MainScreen(),
|
screen = if (location.locations.isEmpty()) LocationPickerScreen() else MainScreen(),
|
||||||
onBackPressed = {
|
|
||||||
it !is MainScreen
|
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
SlideTransition(it)
|
SlideTransition(it)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@ import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Thermostat
|
|
||||||
import androidx.compose.material.icons.outlined.WaterDrop
|
import androidx.compose.material.icons.outlined.WaterDrop
|
||||||
import androidx.compose.material.icons.outlined.WindPower
|
import androidx.compose.material.icons.outlined.WindPower
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
@ -40,7 +40,8 @@ fun WeatherCard(hour: HourlyWeatherData?, modifier: Modifier = Modifier) {
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "Today $formattedTime",
|
text = formattedTime,
|
||||||
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
@ -53,18 +54,12 @@ fun WeatherCard(hour: HourlyWeatherData?, modifier: Modifier = Modifier) {
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
Text(text = "${it.temperature}°C", fontSize = 50.sp)
|
Text(text = "${it.temperature}°C", fontSize = 50.sp)
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
Text(text = it.weatherType.weatherDesc, fontSize = 20.sp)
|
Text(text = "${it.weatherType.weatherDesc} - Feels like ${it.apparentTemperature}°C", fontSize = 20.sp)
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.SpaceAround
|
horizontalArrangement = Arrangement.SpaceEvenly
|
||||||
) {
|
) {
|
||||||
WeatherDataDisplay(
|
|
||||||
value = it.apparentTemperature,
|
|
||||||
unit = "°C",
|
|
||||||
icon = Icons.Outlined.Thermostat,
|
|
||||||
description = "Feels like",
|
|
||||||
)
|
|
||||||
WeatherDataDisplay(
|
WeatherDataDisplay(
|
||||||
value = it.precipitationProbability,
|
value = it.precipitationProbability,
|
||||||
unit = "%",
|
unit = "%",
|
||||||
|
|
|
@ -67,7 +67,7 @@ fun WeatherDay(dailyWeatherData: DailyWeatherData) {
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
|
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
|
||||||
horizontalArrangement = Arrangement.Center
|
horizontalArrangement = Arrangement.SpaceEvenly
|
||||||
) {
|
) {
|
||||||
WeatherDataDisplay(
|
WeatherDataDisplay(
|
||||||
value = dailyWeatherData.precipitationProbabilityMax,
|
value = dailyWeatherData.precipitationProbabilityMax,
|
||||||
|
|
|
@ -2,7 +2,7 @@ package com.henryhiles.qweather.presentation.components.weather
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
@ -16,14 +16,13 @@ fun WeatherForecast(
|
||||||
onChangeSelected: (Int) -> Unit
|
onChangeSelected: (Int) -> Unit
|
||||||
) {
|
) {
|
||||||
state.hourlyWeatherInfo?.weatherData?.let {
|
state.hourlyWeatherInfo?.weatherData?.let {
|
||||||
val hour = LocalDateTime.now().hour
|
|
||||||
LazyRow(modifier = modifier) {
|
LazyRow(modifier = modifier) {
|
||||||
itemsIndexed(it.subList(hour, it.size)) { index, data ->
|
items(it.subList(LocalDateTime.now().hour, it.size)) {
|
||||||
WeatherHour(
|
WeatherHour(
|
||||||
data = data,
|
data = it,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 8.dp)
|
.padding(horizontal = 8.dp)
|
||||||
) { onChangeSelected(index) }
|
) { onChangeSelected(it.time.hour) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,44 @@
|
||||||
package com.henryhiles.qweather.presentation.components.weather
|
package com.henryhiles.qweather.presentation.components.weather
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.henryhiles.qweather.R
|
import com.henryhiles.qweather.R
|
||||||
import com.henryhiles.qweather.presentation.components.VerticalDivider
|
import com.henryhiles.qweather.presentation.components.VerticalDivider
|
||||||
import com.henryhiles.qweather.presentation.screenmodel.HourlyWeatherState
|
import com.henryhiles.qweather.presentation.screenmodel.HourlyWeatherState
|
||||||
|
import com.henryhiles.qweather.presentation.screenmodel.LocationPreferenceManager
|
||||||
|
import org.koin.compose.koinInject
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WeatherToday(state: HourlyWeatherState) {
|
fun WeatherToday(state: HourlyWeatherState) {
|
||||||
|
val locationPreferenceManager: LocationPreferenceManager = koinInject()
|
||||||
|
|
||||||
state.hourlyWeatherInfo?.let {
|
state.hourlyWeatherInfo?.let {
|
||||||
|
Card(
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(8.dp), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.today_in, with(locationPreferenceManager) {
|
||||||
|
locations.getOrNull(selectedIndex)?.location?.split(",")?.first()
|
||||||
|
?: stringResource(id = R.string.unknown)
|
||||||
|
}),
|
||||||
|
style = MaterialTheme.typography.headlineSmall
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(24.dp)
|
.height(24.dp)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.Center
|
horizontalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.weather_high, it.highTemperature),
|
text = stringResource(R.string.weather_high, it.highTemperature),
|
||||||
)
|
)
|
||||||
|
@ -34,10 +53,10 @@ fun WeatherToday(state: HourlyWeatherState) {
|
||||||
id = R.string.weather_precipitation,
|
id = R.string.weather_precipitation,
|
||||||
it
|
it
|
||||||
)
|
)
|
||||||
} ?: stringResource(
|
} ?: stringResource(id = R.string.unknown)
|
||||||
id = R.string.unknown
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,6 @@ import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Info
|
|
||||||
import androidx.compose.material.icons.outlined.Search
|
import androidx.compose.material.icons.outlined.Search
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
|
@ -31,30 +30,21 @@ class LocationPickerScreen : Screen {
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val screenModel: LocationPickerScreenModel = getScreenModel()
|
val screenModel: LocationPickerScreenModel = getScreenModel()
|
||||||
var locationSearch by remember { mutableStateOf("") }
|
var locationSearch by remember { mutableStateOf("") }
|
||||||
var isAboutOpen by remember { mutableStateOf(false) }
|
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.imePadding(),
|
modifier = Modifier.imePadding(),
|
||||||
) {padding ->
|
) { padding ->
|
||||||
Column(modifier = Modifier.padding(padding)) {
|
Column(modifier = Modifier.padding(padding)) {
|
||||||
SmallToolbar(
|
SmallToolbar(
|
||||||
title = { Text(text = stringResource(id = R.string.location_choose)) },
|
title = { Text(text = stringResource(id = R.string.location_choose)) },
|
||||||
backButton = screenModel.prefs.locations.isNotEmpty(),
|
backButton = screenModel.prefs.locations.isNotEmpty(),
|
||||||
actions = {
|
|
||||||
IconButton(
|
|
||||||
onClick = { isAboutOpen = true }) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Outlined.Info,
|
|
||||||
contentDescription = stringResource(id = R.string.help_screen)
|
|
||||||
)
|
)
|
||||||
}
|
|
||||||
})
|
|
||||||
screenModel.state.error?.let {
|
screenModel.state.error?.let {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = {navigator.pop()},
|
onDismissRequest = { navigator.pop() },
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(onClick = {navigator.pop()}) {
|
TextButton(onClick = { navigator.pop() }) {
|
||||||
Text(text = stringResource(id = R.string.action_confirm))
|
Text(text = stringResource(id = R.string.action_confirm))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -69,19 +59,6 @@ class LocationPickerScreen : Screen {
|
||||||
)
|
)
|
||||||
} ?: kotlin.run {
|
} ?: kotlin.run {
|
||||||
Column(modifier = Modifier.padding(16.dp)) {
|
Column(modifier = Modifier.padding(16.dp)) {
|
||||||
if (isAboutOpen)
|
|
||||||
AlertDialog(
|
|
||||||
title = { Text(text = stringResource(id = R.string.location_choose)) },
|
|
||||||
text = { Text(text = stringResource(id = R.string.help_location_picker)) },
|
|
||||||
onDismissRequest = { isAboutOpen = false },
|
|
||||||
confirmButton = {
|
|
||||||
TextButton(
|
|
||||||
onClick = { isAboutOpen = false }) {
|
|
||||||
Text(text = stringResource(id = R.string.action_confirm))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
label = { Text(text = stringResource(id = R.string.location)) },
|
label = { Text(text = stringResource(id = R.string.location)) },
|
||||||
keyboardOptions = KeyboardOptions(
|
keyboardOptions = KeyboardOptions(
|
||||||
|
|
|
@ -19,16 +19,13 @@ import com.henryhiles.qweather.domain.util.NavigationTab
|
||||||
import com.henryhiles.qweather.presentation.components.location.LocationsDrawer
|
import com.henryhiles.qweather.presentation.components.location.LocationsDrawer
|
||||||
import com.henryhiles.qweather.presentation.components.navigation.BottomBar
|
import com.henryhiles.qweather.presentation.components.navigation.BottomBar
|
||||||
import com.henryhiles.qweather.presentation.components.navigation.SmallToolbar
|
import com.henryhiles.qweather.presentation.components.navigation.SmallToolbar
|
||||||
import com.henryhiles.qweather.presentation.screenmodel.LocationPreferenceManager
|
|
||||||
import com.henryhiles.qweather.presentation.tabs.TodayTab
|
import com.henryhiles.qweather.presentation.tabs.TodayTab
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.compose.koinInject
|
|
||||||
|
|
||||||
class MainScreen : Screen {
|
class MainScreen : Screen {
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val locationPreferenceManager: LocationPreferenceManager = koinInject()
|
|
||||||
val drawerState =
|
val drawerState =
|
||||||
rememberDrawerState(initialValue = DrawerValue.Closed)
|
rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
@ -42,14 +39,11 @@ class MainScreen : Screen {
|
||||||
topBar = {
|
topBar = {
|
||||||
SmallToolbar(
|
SmallToolbar(
|
||||||
title = {
|
title = {
|
||||||
with(locationPreferenceManager) {
|
|
||||||
Text(
|
Text(
|
||||||
text = locations.getOrNull(selectedIndex)?.location
|
text = it.current.options.title,
|
||||||
?: stringResource(id = R.string.unknown),
|
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
modifier = Modifier.basicMarquee()
|
modifier = Modifier.basicMarquee()
|
||||||
)
|
)
|
||||||
}
|
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
(it.current as? NavigationTab)?.Actions()
|
(it.current as? NavigationTab)?.Actions()
|
||||||
|
|
|
@ -81,12 +81,12 @@ object TodayTab : NavigationTab {
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
|
WeatherToday(state = weatherViewModel.state)
|
||||||
WeatherCard(
|
WeatherCard(
|
||||||
hour = weatherViewModel.state.selected?.let {
|
hour = weatherViewModel.state.selected?.let {
|
||||||
weatherViewModel.state.hourlyWeatherInfo?.weatherData?.get(it)
|
weatherViewModel.state.hourlyWeatherInfo?.weatherData?.get(it)
|
||||||
} ?: weatherViewModel.state.hourlyWeatherInfo?.currentWeatherData,
|
} ?: weatherViewModel.state.hourlyWeatherInfo?.currentWeatherData,
|
||||||
)
|
)
|
||||||
WeatherToday(state = weatherViewModel.state)
|
|
||||||
WeatherForecast(
|
WeatherForecast(
|
||||||
state = weatherViewModel.state
|
state = weatherViewModel.state
|
||||||
) { weatherViewModel.setSelected(it) }
|
) { weatherViewModel.setSelected(it) }
|
||||||
|
|
|
@ -15,9 +15,6 @@
|
||||||
|
|
||||||
<string name="selected">Selected</string>
|
<string name="selected">Selected</string>
|
||||||
|
|
||||||
<string name="help_screen">How do I use this screen?</string>
|
|
||||||
<string name="help_location_picker">Please search a location, then tap a result. Then tap the apply button in the bottom left corner.</string>
|
|
||||||
|
|
||||||
<string name="appearance_theme">Theme</string>
|
<string name="appearance_theme">Theme</string>
|
||||||
<string name="appearance_monet">Dynamic Theme</string>
|
<string name="appearance_monet">Dynamic Theme</string>
|
||||||
<string name="appearance_monet_description">Available on Android 12+</string>
|
<string name="appearance_monet_description">Available on Android 12+</string>
|
||||||
|
@ -41,6 +38,8 @@
|
||||||
<string name="weather_low">Low: %1$d°C</string>
|
<string name="weather_low">Low: %1$d°C</string>
|
||||||
<string name="weather_precipitation">Precipitation: %1$d﹪</string>
|
<string name="weather_precipitation">Precipitation: %1$d﹪</string>
|
||||||
|
|
||||||
|
<string name="today_in">Today in %1$s</string>
|
||||||
|
|
||||||
<string name="unknown">Unknown</string>
|
<string name="unknown">Unknown</string>
|
||||||
|
|
||||||
<string name="error">An error occurred</string>
|
<string name="error">An error occurred</string>
|
||||||
|
|
Reference in a new issue