Weather App JetPack Compose #10 : MainList()

UI.kt

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil.compose.AsyncImage
import com.meter_alc_rgb.weatherappcomposey.data.WeatherModel
import com.meter_alc_rgb.weatherappcomposey.ui.theme.BlueLight
@Composable
fun MainList(list: List<WeatherModel>, currentDay: MutableState<WeatherModel>){
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
itemsIndexed(
list
) { _, item ->
ListItem(item, currentDay)
}
}
}
@Composable
fun ListItem(item: WeatherModel, currentDay: MutableState<WeatherModel>) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(top = 3.dp).clickable {
if (item.hours.isEmpty()) return@clickable
currentDay.value = item
},
backgroundColor = BlueLight,
elevation = 0.dp,
shape = RoundedCornerShape(5.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier.padding(
start = 8.dp,
top = 5.dp,
bottom = 5.dp
)
) {
Text(text = item.time)
Text(
text = item.condition,
color = Color.White
)
}
Text(
text = item.currentTemp.ifEmpty { "${item.maxTemp}/${item.minTemp}" },
color = Color.White,
style = TextStyle(fontSize = 25.sp)
)
AsyncImage(
model = "https:${item.icon}",
contentDescription = "im5",
modifier = Modifier
.padding(
end = 8.dp
)
.size(35.dp)
)
}
}
}

MainSreen.kt

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.produceState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil.compose.AsyncImage
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.pagerTabIndicatorOffset
import com.google.accompanist.pager.rememberPagerState
import com.meter_alc_rgb.weatherappcomposey.R
import com.meter_alc_rgb.weatherappcomposey.data.WeatherModel
import com.meter_alc_rgb.weatherappcomposey.ui.theme.BlueLight
import kotlinx.coroutines.launch
import org.json.JSONArray
import org.json.JSONObject

@Composable
fun MainCard(currentDay: MutableState<WeatherModel>) {
Column(
modifier = Modifier
.padding(5.dp)
) {
Card(
modifier = Modifier.fillMaxWidth(),
backgroundColor = BlueLight,
elevation = 0.dp
) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = currentDay.value.time,
modifier = Modifier.padding(
top = 8.dp,
start = 8.dp
),
style = TextStyle(fontSize = 15.sp),
color = Color.White
)
AsyncImage(
model = "https:" + currentDay.value.icon,
contentDescription = "im2",
modifier = Modifier
.padding(
top = 8.dp,
end = 8.dp
)
.size(35.dp)
)
}
Text(
text = currentDay.value.city,
style = TextStyle(fontSize = 24.sp),
color = Color.White
)
Text(
text = if(currentDay.value.currentTemp.isNotEmpty())
currentDay.value.currentTemp.toFloat().toInt().toString() + "ºC"
else currentDay.value.maxTemp.toFloat().toInt().toString() +
"ºC/${currentDay.value.minTemp.toFloat().toInt()}ºC"
,
style = TextStyle(fontSize = 65.sp),
color = Color.White
)
Text(
text = currentDay.value.condition,
style = TextStyle(fontSize = 16.sp),
color = Color.White
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
IconButton(
onClick = {

}
) {
Icon(
painter = painterResource(id = R.drawable.ic_search),
contentDescription = "im3",
tint = Color.White
)
}
Text(
text = "${currentDay.value
.maxTemp.toFloat().toInt()}ºC/${currentDay
.value.minTemp.toFloat().toInt()}ºC",
style = TextStyle(fontSize = 16.sp),
color = Color.White
)
IconButton(
onClick = {

}
) {
Icon(
painter = painterResource(id = R.drawable.ic_sync),
contentDescription = "im4",
tint = Color.White
)
}
}
}
}
}
}

@OptIn(ExperimentalPagerApi::class)
@Composable
fun TabLayout(daysList: MutableState<List<WeatherModel>>, currentDay: MutableState<WeatherModel>) {
val tabList = listOf("HOURS", "DAYS")
val pagerState = rememberPagerState()
val tabIndex = pagerState.currentPage
val coroutineScope = rememberCoroutineScope()

Column(
modifier = Modifier
.padding(
start = 5.dp,
end = 5.dp
)
.clip(RoundedCornerShape(5.dp))
) {
TabRow(
selectedTabIndex = tabIndex,
indicator = { pos ->
TabRowDefaults.Indicator(
Modifier.pagerTabIndicatorOffset(pagerState, pos)
)
},
backgroundColor = BlueLight,
contentColor = Color.White
) {
tabList.forEachIndexed { index, text ->
Tab(
selected = false,
onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
},
text = {
Text(text = text)
}
)
}
}
HorizontalPager(
count = tabList.size,
state = pagerState,
modifier = Modifier.weight(1.0f)
) { index ->
val list = when(index){
0 -> getWeatherByHours(currentDay.value.hours)
1 -> daysList.value
else -> daysList.value
}
MainList(list, currentDay)
}
}

}

private fun getWeatherByHours(hours: String): List<WeatherModel>{
if (hours.isEmpty()) return listOf()
val hoursArray = JSONArray(hours)
val list = ArrayList<WeatherModel>()
for (i in 0 until hoursArray.length()){
val item = hoursArray[i] as JSONObject
list.add(
WeatherModel(
"",
item.getString("time"),
item.getString("temp_c").toFloat().toInt().toString() + "ºC",
item.getJSONObject("condition").getString("text"),
item.getJSONObject("condition").getString("icon"),
"",
"",
""
)
)
}
return list
}

MainActivity.kt

import android.content.Context
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import com.android.volley.Request
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import com.meter_alc_rgb.weatherappcomposey.data.WeatherModel
import com.meter_alc_rgb.weatherappcomposey.screens.MainCard
import com.meter_alc_rgb.weatherappcomposey.screens.TabLayout
import com.meter_alc_rgb.weatherappcomposey.ui.theme.WeatherAppComposeYTheme
import org.json.JSONObject

const val API_KEY = "Ваш API ключ"
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
WeatherAppComposeYTheme {
val daysList = remember {
mutableStateOf(listOf<WeatherModel>())
}
val currentDay = remember {
mutableStateOf(WeatherModel(
"",
"",
"0.0",
"",
"",
"0.0",
"0.0",
""
)
)
}
getData("London", this, daysList, currentDay)
Image(
painter = painterResource(
id = R.drawable.weather_bg
),
contentDescription = "im1",
modifier = Modifier
.fillMaxSize()
.alpha(0.5f),
contentScale = ContentScale.FillBounds
)
Column{
MainCard(currentDay)
TabLayout(daysList, currentDay)
}

}
}
}
}

private fun getData(city: String, context: Context,
daysList: MutableState<List<WeatherModel>>,
currentDay: MutableState<WeatherModel>){
val url = "https://api.weatherapi.com/v1/forecast.json?key=$API_KEY" +
"&q=$city" +
"&days=" +
"3" +
"&aqi=no&alerts=no"
val queue = Volley.newRequestQueue(context)
val sRequest = StringRequest(
Request.Method.GET,
url,
{
response ->
val list = getWeatherByDays(response)
currentDay.value = list[0]
daysList.value = list
},
{
Log.d("MyLog", "VolleyError: $it")
}
)
queue.add(sRequest)
}

private fun getWeatherByDays(response: String): List<WeatherModel>{
if (response.isEmpty()) return listOf()
val list = ArrayList<WeatherModel>()
val mainObject = JSONObject(response)
val city = mainObject.getJSONObject("location").getString("name")
val days = mainObject.getJSONObject("forecast").getJSONArray("forecastday")

for (i in 0 until days.length()){
val item = days[i] as JSONObject
list.add(
WeatherModel(
city,
item.getString("date"),
"",
item.getJSONObject("day").getJSONObject("condition")
.getString("text"),
item.getJSONObject("day").getJSONObject("condition")
.getString("icon"),
item.getJSONObject("day").getString("maxtemp_c"),
item.getJSONObject("day").getString("mintemp_c"),
item.getJSONArray("hour").toString()

)
)
}
list[0] = list[0].copy(
time = mainObject.getJSONObject("current").getString("last_updated"),
currentTemp = mainObject.getJSONObject("current").getString("temp_c"),
)
return list
}

5 комментариев для “Weather App JetPack Compose #10 : MainList()”

  1. Действительно отличный пример работы с Compose. Прошел все эти несколько уроков, оч понравилось – все понятно сразу стало.

Добавить комментарий

Ваш адрес email не будет опубликован.