(Jetpack Compose) How to fix the error with custom TextField? [closed] - android

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I can not do it. One mistake for: TextField, Text, IconButton.
#Composable invocations can only happen from the context of a #Composable function
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.withStyle
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import ru.exemple.app.R
import ru.exemple.app.presentation.components.StandardTextField
import ru.exemple.app.ui.theme.SpaceMedium
import ru.exemple.app.ui.theme.SpaceSmall
#Composable
fun LoginScreen(
navController: NavController,
viewModel: LoginViewModel = hiltViewModel()
) {
Box(modifier = Modifier.fillMaxSize()) {
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxSize()
.padding(horizontal = SpaceMedium)
.align(Alignment.Center)
) {
Text(
text = stringResource(id = R.string.login)
)
Spacer(modifier = Modifier.height(SpaceSmall))
StandardTextField(
text = viewModel.usernameText.value,
onValueChange = {
viewModel.setUsernameText(it)
},
hint = stringResource(id = R.string.login_hint)
)
Spacer(modifier = Modifier.height(SpaceSmall))
StandardTextField(
text = viewModel.passwordText.value,
onValueChange = {
viewModel.setPasswordText(it)
},
hint = stringResource(id = R.string.password_hint),
keyboardType = KeyboardType.Password
)
}
Text(
text = buildAnnotatedString {
append(stringResource(id = R.string.dont_have_an_account_yet))
append("")
val signUpText = stringResource(id = R.string.sign_up)
withStyle(
style = SpanStyle(
color = MaterialTheme.colors.primary
)
) {
append(signUpText)
}
},
style = MaterialTheme.typography.body1,
modifier = Modifier
.align(Alignment.BottomCenter)
)
}
}
}
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.runtime.setValue
import androidx.compose.runtime.getValue
import androidx.compose.ui.text.input.KeyboardType
import ru.exemple.app.R
import androidx.compose.runtime.Composable
#Composable
fun StandardTextField(
text: String = "",
hint: String = "",
isError: Boolean = false,
keyboardType: KeyboardType = KeyboardType.Text,
onValueChange: (String) -> Unit
) {
val isPasswordToggleDisplayed by remember {
mutableStateOf(keyboardType == KeyboardType.Password)
}
var isPasswordVisible by remember {
mutableStateOf(false)
}
TextField(
value = text,
onValueChange = onValueChange,
placeholder = {
Text(text = text)
},
isError = isError,
keyboardOptions = KeyboardOptions(
keyboardType = keyboardType
),
sigleLine = true,
trailingIcon = {
if (isPasswordToggleDisplayed) {
IconButton(onClick = {
isPasswordVisible = !isPasswordVisible
}) {
Icon(
imageVector = if (isPasswordVisible) {
Icons.Filled.VisibilityOff
} else {
Icons.Filled.Visibility
},
contentDescription = if (isPasswordVisible) {
stringResource(id = R.string.password_visible_content_description)
} else {
stringResource(id = R.string.password_hidden_content_description)
}
)
}
}
},
modifier = Modifier.fillMaxSize()
)
}
dependencies {
implementation 'androidx.compose.ui:ui:1.0.5'
// Tooling support (Previews, etc.)
implementation 'androidx.compose.ui:ui-tooling:1.0.5'
// Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
implementation 'androidx.compose.foundation:foundation:1.0.5'
// Material Design
implementation 'androidx.compose.material:material:1.0.5'
// Material design icons
implementation 'androidx.compose.material:material-icons-core:1.0.5'
implementation 'androidx.compose.material:material-icons-extended:1.0.5'
// Integration with activities
implementation 'androidx.activity:activity-compose:1.3.1'
// Integration with ViewModels
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07'
// Integration with observables
implementation 'androidx.compose.runtime:runtime-livedata:1.0.5'
implementation 'androidx.compose.runtime:runtime-rxjava2:1.0.5'
// UI Tests
androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.0.5'
}

I've been trying to figure this out for the last 15 minutes, and couldn't wrap my head around it.
It looks like there was a typo:
sigleLine = true,
Not sure why it doesn't catch those.
Hope that helped!

Related

Resize View onClick Jetpack Compose

I'm pretty new to compose and having difficulty resizing views. I have a view where I am initially hardcoding it to some size. When clicking the view I want it to expand it to fill the width to certain extent. How is this possible with in compose?
#Composable
fun InputBar(
hint: String,
onClick: () -> Unit
) {
Card(
onClick = { /* update view to fillMaxWidth() */ },
modifier = Modifier
.width(150.dp)
.height(44.dp),
) {
Row(modifier = Modifier.fillMaxWidth()) {
TextField(
value = "",
onValueChange = {
},
placeholder = { Text(hint) }
)
}
}
}
you could achieve your by using something like this:
import android.util.Log
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.material.Card
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlin.math.log
private const val TAG = "InputBar"
#OptIn(ExperimentalMaterialApi::class)
#Composable
fun InputBar(
hint: String,
onClick: () -> Unit
) {
var isFillMaxWidth by remember { mutableStateOf(false) }
val isExpandModifier = remember(isFillMaxWidth){
Modifier
.height(44.dp)
.then(
if (isFillMaxWidth) {
Log.i(TAG, "InputBar: fillMaxWidth")
Modifier.fillMaxWidth()
} else {
Log.i(TAG, "InputBar: 150")
Modifier.width(150.dp)
}
)}
Card(
modifier = isExpandModifier,
) {
Row(modifier = Modifier.fillMaxWidth()) {
TextField(
value = "",
onValueChange = {
},
placeholder = { Text(hint) },
interactionSource = remember { MutableInteractionSource() }
.also { interactionSource ->
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect {
if (it is PressInteraction.Release) {
// works like onClick
isFillMaxWidth = !isFillMaxWidth
Log.i(TAG, "InputBar: onClick")
}
}
}
}
)
}
}
}

jetpack compose exapmle No get method providing array access

I copied a piece of code from the example in jetpack compose.link
But in Android Studio a problem arises:
I wonder where is the problem? I'm still a beginner
The following is the complete code:
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.*
import androidx.compose.material.MaterialTheme.colors
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.freedom.android.ui.theme.MyApplicationTheme
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
drawerContent = { Text("Drawer content") },
topBar = {
TopAppBar(
title = { Text("Simple Scaffold Screen") },
navigationIcon = {
IconButton(
onClick = {
scope.launch { scaffoldState.drawerState.open() }
}
) {
Icon(Icons.Filled.Menu, contentDescription = "Localized description")
}
}
)
},
floatingActionButtonPosition = FabPosition.End,
floatingActionButton = {
ExtendedFloatingActionButton(
text = { Text("Inc") },
onClick = { /* fab click handler */ }
)
},
content = { innerPadding ->
LazyColumn(contentPadding = innerPadding) {
items(count = 100) {
Box(
Modifier
.fillMaxWidth()
.height(50.dp)
.background(colors[it % colors.size])
)
}
}
}
)
}
}
}
}
#Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
#Preview(showBackground = true)
#Composable
fun DefaultPreview() {
MyApplicationTheme {
Greeting("Android")
}
}
I think the problem is with the colors variable, it doesn't seem to be an array, but this was copied from the official documentation, I didn't change it.
package androidx.compose.material
object MaterialTheme {
/**
* Retrieves the current [Colors] at the call site's position in the hierarchy.
*
* #sample androidx.compose.material.samples.ThemeColorSample
*/
val colors: Colors
#Composable
#ReadOnlyComposable
get() = LocalColors.current
}
If you look at the full source code of the sample the docs use, it has a top level object:
private val colors = listOf(
Color(0xFFffd7d7.toInt()),
Color(0xFFffe9d6.toInt()),
Color(0xFFfffbd0.toInt()),
Color(0xFFe3ffd9.toInt()),
Color(0xFFd0fff8.toInt())
)
So yeah, the colors that sample is referring to is a list that you can index into. If you want to also have a semi-random set of colors for your backgrounds, you can copy that list into your code as well.

Issue in preview , Jetpack Compose Android

A lot of errors showing on API ,
Showing Error in LazyVerticalGrid section :
This foundation API is experimental and is likely to change or be removed in the future.
In weekdays section :
Field requires API level 26 (current min is 21): `java.time.DayOfWeek#SUNDAY`
In months section there is this error:
Field requires API level 26 (current min is 21): `java.time.Month#JULY`
This is my code below .
package com.example.android.weatherapp.ui.components
import android.os.Build
import androidx.annotation.DrawableRes
import androidx.annotation.RequiresApi
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.GridCells
import com.example.android.weatherapp.R
import androidx.compose.foundation.lazy.GridItemSpan
import androidx.compose.foundation.lazy.LazyVerticalGrid
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.android.weatherapp.ui.theme.WeatherAppTheme
import java.time.DayOfWeek
import java.time.format.TextStyle
import java.util.*
data class Month(
val title : String ,
val dateForecasts: List<DateForeCast>
)
data class DateForeCast(
val date: String,
val highTemperature: String,
#DrawableRes val icon: Int
)
#Composable
fun Calendar(
months : List<Month>,
modifier: Modifier = Modifier
){
val gridCellNumber = 7
LazyVerticalGrid(
modifier = modifier ,
cells = GridCells.Fixed(gridCellNumber)
){
months.forEach { month ->
item(
span = { GridItemSpan(gridCellNumber) }
) { MonthLabel(month = month.title) }
items(month.dateForecasts){
DateCard(dataForecasts = it )
}
}
}
}
#Composable
fun MonthLabel(
month: String,
modifier: Modifier = Modifier
){
val weekdays = listOf(
DayOfWeek.SUNDAY,
DayOfWeek.MONDAY,
DayOfWeek.TUESDAY,
DayOfWeek.WEDNESDAY,
DayOfWeek.THURSDAY,
DayOfWeek.FRIDAY,
DayOfWeek.SATURDAY
).map{
it.getDisplayName(TextStyle.SHORT, Locale.getDefault())
}
Column(
modifier = modifier.fillMaxWidth()
) {
Text(
text = month ,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.h5.copy(fontWeight = FontWeight.SemiBold)
)
Row(modifier = Modifier.fillMaxWidth() ){
weekdays.forEach{
Text(
text = it,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.body2,
modifier = Modifier.weight(1f,true)
)
}
}
}
}
#Preview(
showBackground = true
)
#Composable
fun CalendarPreview(){
val months = listOf(
Month(
title = "July",
dateForecasts = List(java.time.Month.JULY.length(false)){
DateForeCast(
date = "$it + 1",
highTemperature = "70",
icon = R.drawable.cloud_cloudy_day_forecast_sun_icon
)
}
),
Month(
title = "August",
dateForecasts = List(java.time.Month.AUGUST.length(false)){
DateForeCast(
date = "$it + 1",
highTemperature = "70",
icon = R.drawable.cloud_cloudy_day_forecast_sun_icon
)
}
)
)
WeatherAppTheme {
Calendar(months = months )
}
}
#Composable
fun DateCard(
dataForecasts: DateForeCast,
modifier: Modifier = Modifier
) = Card (
modifier = modifier,
){
Column (
modifier = Modifier.padding(8.dp),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
){
Text(
text = dataForecasts.date,
style = MaterialTheme.typography.overline,
color = Color.Blue
)
Icon(
painter = painterResource(id = dataForecasts.icon ),
contentDescription = null,
modifier = Modifier
.padding(vertical = 16.dp)
.size(24.dp),
tint = Color.Unspecified
)
}
}
This is mainly the issue of SDK, but still its not working properly.
I tried the inbuild suggestions to remove the error but it's still no progress.
I have the solution for this.
You just have to change your compileSDK and targetSDK to 33 in gradle build.
Then just clear the cache and your build will work properly .

How to change background color of the jetpack compose snackbar?

I want to change solid or gradient color to jetpack compose snack bar. Please guide me how to
change color
Here is my snack bar using material3 compose, I am looking solution to change the background color
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import compose.material.theme.ui.theme.Material3ComposeTheme
import compose.material.theme.ui.theme.Purple40
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
#OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Material3ComposeTheme {
val context = LocalContext.current
val snackState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
topBar = {
},
content = {
fun launchSnackbar(message: String, actionLabel : String?=null, duration: SnackbarDuration = SnackbarDuration.Short){
scope.launch {
snackState.showSnackbar(message = message,actionLabel=actionLabel, duration=duration)
}
}
Column(
modifier = Modifier
.padding(it)
.verticalScroll(rememberScrollState())
) {
Spacer(modifier = Modifier.height(47.dp))
Text("Snackbar", Modifier.padding(bottom = 10.dp), style = MaterialTheme.typography.labelLarge)
Button(onClick = {
// * Snackbar
launchSnackbar(message = "Hi i am snackbar message", actionLabel = "Hide", duration = SnackbarDuration.Long)
}) { Text("Snackbar",style = MaterialTheme.typography.labelLarge) }
ListDividerPadding()
Text("Toast", Modifier.padding(bottom = 10.dp), style = MaterialTheme.typography.labelLarge)
Button(onClick = {
Toast.makeText(
context,
"Hi i am toast message",
Toast.LENGTH_LONG
).show()
}) { Text("Toast",style = MaterialTheme.typography.labelLarge) }
}
}
)
Box(modifier = Modifier.fillMaxSize(), Alignment.BottomCenter){
SnackbarHost(hostState = snackState)
}
}
}
}
}
You can add SnackBar composable to SnackbarHost and change colors as
SnackbarHost(hostState = snackState) {
Snackbar(
snackbarData = it,
containerColor = Color.Green,
contentColor = Color.Red
)
}
Edit
There is no overload function that takes Brush instead of Color but you can add another Composable as with gradient color or more customization via content: #Composable () -> Unit
#Composable
fun Snackbar(
modifier: Modifier = Modifier,
action: #Composable (() -> Unit)? = null,
dismissAction: #Composable (() -> Unit)? = null,
actionOnNewLine: Boolean = false,
shape: Shape = SnackbarTokens.ContainerShape.toShape(),
containerColor: Color = SnackbarTokens.ContainerColor.toColor(),
contentColor: Color = SnackbarTokens.SupportingTextColor.toColor(),
actionContentColor: Color = SnackbarTokens.ActionLabelTextColor.toColor(),
dismissActionContentColor: Color = SnackbarTokens.IconColor.toColor(),
content: #Composable () -> Unit
)
Can be used as
Snackbar {
Row(
modifier = Modifier.background(
brush = Brush.horizontalGradient(
listOf(
Color.Red,
Color.Green,
Color.Blue
)
)
)
) {
Text("Hello World")
}
}

How to transfer the selected day from the calendar with the selected day to the text?

I'm using a third party calendar library. I tried to do it through the current date, but it didn’t work out. Maybe someone knows how to transfer data from a function to another function? I need the date that the user has selected in the calendar to display as text, but I don't know how to do it (
Gradle
val androidMain by getting {
dependencies {
implementation ("com.himanshoe:kalendar:1.0.0-RC5")
implementation("androidx.core:core-ktx:1.8.0")
implementation("androidx.appcompat:appcompat:1.4.2")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.0")
implementation("androidx.activity:activity-compose:1.5.0")
implementation("androidx.compose.ui:ui:1.2.0-rc03")
implementation("androidx.compose.material:material:1.2.0-rc03")
implementation("androidx.compose.ui:ui-tooling-preview:1.2.0-rc03")
implementation("androidx.compose.material:material-icons-extended:1.2.0-rc03")
implementation("com.google.accompanist:accompanist-systemuicontroller:0.24.13-rc")
implementation("io.coil-kt:coil-compose:2.1.0")
implementation("io.coil-kt:coil-gif:2.1.0")
implementation("io.insert-koin:koin-core:3.2.0")
implementation("io.insert-koin:koin-androidx-compose:3.2.0")
implementation("io.github.alexgladkov:odyssey-core:1.0.0-beta12")
implementation("io.github.alexgladkov:odyssey-compose:1.0.0-beta12")
}
DatePicker
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.himanshoe.kalendar.common.KalendarSelector
import com.himanshoe.kalendar.common.KalendarStyle
import com.himanshoe.kalendar.ui.Kalendar
import com.himanshoe.kalendar.ui.KalendarType
import java.time.LocalDate
#Composable
fun DatePicker(modifier: Modifier = Modifier, onDaySelected: (LocalDate) -> Unit) {
Box(modifier = modifier) {
Kalendar(
kalendarType = KalendarType.Firey(),
kalendarStyle = KalendarStyle(
kalendarBackgroundColor = Color.White,
kalendarColor = Color.White,
kalendarSelector = KalendarSelector.Circle(
selectedColor = Color.Black,
eventTextColor = Color.Black,
todayColor = Color.White,
selectedTextColor = Color.White
),
elevation = 0.dp
),
onCurrentDayClick = { day, _ ->
onDaySelected(day)
})
}
}
SelectedDate
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.happy.R
import java.time.LocalDate
#Composable
fun SelectedDate(
date: LocalDate,
modifier: Modifier = Modifier,
onDateClick: () -> Unit
) {
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
Row(
modifier = modifier.clickable { onDateClick() },
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = date.toString(),
style = MaterialTheme.typography.body1
)
Spacer(modifier = Modifier.width(8.dp))
Icon(
painter = painterResource(id = R.drawable.ic_calendar_outline_24),
contentDescription = null
)
}
}
}
DashboardUIState
import com.happy.screens.dashboard.presentation.models.TaskUi
import java.time.LocalDate
#Immutable
data class DashboardUiState(
val currentDate:LocalDate = LocalDate.now(),
val dayOfTheWeek: String = "",
val taskList: List<TaskUi> = emptyList()
) {
companion object {
val Empty = DashboardUiState()
}
}
#Immutable
sealed class DashboardUiEvent {
object OnAddTask : DashboardUiEvent()
class OnTaskClick(val id: Int) : DashboardUiEvent()
}
#Immutable
sealed class DashboardUiEffect {
object NavigateToTaskCreation : DashboardUiEffect()
class NavigateToTaskDetails(val id: Int) : DashboardUiEffect()
}
DashboardViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.time.LocalDate
class DashboardViewModel : ViewModel() {
private val _state = MutableStateFlow(DashboardUiState.Empty)
val state = _state.asStateFlow()
private val _effect = MutableSharedFlow<DashboardUiEffect>()
val effect = _effect.asSharedFlow()
init {
_state.update { it.copy(currentDate = LocalDate.now(), dayOfTheWeek = "Сегодня") }
// val exampleList = listOf(
// TaskUi(id = 0, unicode = "\uD83D\uDD25", isDone = true),
// TaskUi(id = 1, unicode = "\uD83D\uDD25", isDone = false),
// TaskUi(id = 0, unicode = "\uD83D\uDD25", isDone = true),
// TaskUi(id = 0, unicode = "\uD83D\uDD25", isDone = true),
// TaskUi(id = 0, unicode = "\uD83D\uDD25", isDone = true),
// TaskUi(id = 0, unicode = "\uD83D\uDD25", isDone = true),
// TaskUi(id = 0, unicode = "\uD83D\uDD25", isDone = true),
// TaskUi(id = 0, unicode = "\uD83D\uDD25", isDone = true),
// TaskUi(id = 0, unicode = "\uD83D\uDD25", isDone = true)
// )
// _state.update { it.copy(taskList = exampleList) }
}
fun sendEvent(event: DashboardUiEvent) {
when (event) {
DashboardUiEvent.OnAddTask -> {
viewModelScope.launch {
_effect.emit(DashboardUiEffect.NavigateToTaskCreation)
}
}
is DashboardUiEvent.OnTaskClick -> {
viewModelScope.launch {
_effect.emit(DashboardUiEffect.NavigateToTaskDetails(event.id))
}
}
}
}
}
DashboardScreen
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.happy.core.navigation.Screens
import com.happy.core.ui.rememberStateWithLifecycle
import com.happy.screens.calendar.DatePicker
import com.happy.screens.calendar.DayOfTheWeekText
import com.happy.screens.calendar.SelectedDate
import com.happy.screens.dashboard.presentation.components.AddTaskButton
import com.happy.screens.dashboard.presentation.components.EmptyTaskMessage
import com.happy.screens.dashboard.presentation.components.ProfileImage
import com.happy.screens.dashboard.presentation.components.TaskItem
import org.koin.androidx.compose.getViewModel
import kotlinx.coroutines.launch
import ru.alexgladkov.odyssey.compose.extensions.present
import ru.alexgladkov.odyssey.compose.local.LocalRootController
import ru.alexgladkov.odyssey.compose.navigation.modal_navigation.ModalSheetConfiguration
import java.time.LocalDate
#Composable
fun DashboardScreen(
) {
DashboardScreen(
viewModel = getViewModel(),
onTaskCreationClick = {},
onTaskClick = {}
)
}
#Composable
private fun DashboardScreen(
viewModel: DashboardViewModel,
onTaskCreationClick: () -> Unit,
onTaskClick: (Int) -> Unit,
) {
val uiState by rememberStateWithLifecycle(viewModel.state)
val systemUiController = rememberSystemUiController()
val coroutineScope = rememberCoroutineScope()
val rootController = LocalRootController.current
val modalController = rootController.findModalController()
val modalSheetConfiguration = ModalSheetConfiguration(
maxHeight = 0.7f,
cornerRadius = 20,
closeOnSwipe = true
)
var date:LocalDate =LocalDate.now()
LaunchedEffect(Unit) {
viewModel.effect.collect { effect ->
when (effect) {
DashboardUiEffect.NavigateToTaskCreation -> onTaskCreationClick()
is DashboardUiEffect.NavigateToTaskDetails -> onTaskClick(effect.id)
}
}
}
SideEffect {
systemUiController.setSystemBarsColor(color = Color.Transparent, darkIcons = true)
}
Box(
modifier = Modifier
.fillMaxSize()
.systemBarsPadding()
) {
Column(modifier = Modifier.fillMaxSize()) {
Row(
modifier = Modifier
.padding(horizontal = 24.dp)
.padding(top = 16.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
SelectedDate(
date = uiState.currentDate
) {
coroutineScope.launch {
modalController.present(modalSheetConfiguration, content = {
DatePicker {
modalController.popBackStack(animate = true)
}
})
}
}
ProfileImage(isAuthorized = false)
}
DayOfTheWeekText(
day = uiState.dayOfTheWeek,
modifier = Modifier.padding(start = 24.dp, top = 12.dp)
)
if (uiState.taskList.isEmpty()) {
EmptyTaskMessage(
modifier = Modifier
.fillMaxSize()
.padding(bottom = 148.dp)
.padding(horizontal = 34.dp)
)
} else {
LazyVerticalGrid(
columns = GridCells.Fixed(3),
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp),
verticalArrangement = Arrangement.spacedBy(44.dp),
horizontalArrangement = Arrangement.spacedBy(84.dp),
) {
items(uiState.taskList) { task ->
TaskItem(
task = task,
modifier = Modifier
.size(60.dp)
.clickable {
rootController.launch(Screens.TaskList.name)
}
)
}
}
}
}
AddTaskButton(
onClick = { viewModel.sendEvent(DashboardUiEvent.OnAddTask) },
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 16.dp)
)
}
}
DashboardScreen
Since your UI state DashboardUIState is managed by your view model DashboardViewModel, you have to notify DashboardViewModel when the date is changed by the user. The user selects the date in the DatePicker which has a callback onDaySelected: (LocalDate) -> Unit. Inside this callback you can notify your DashboardViewModel that there was a change and that the state should be updated.
In your DashboardScreen update this part of the code
SelectedDate(
date = uiState.currentDate
) {
coroutineScope.launch {
modalController.present(modalSheetConfiguration, content = {
DatePicker { selectedDate ->
modalController.popBackStack(animate = true)
viewModel.updateCurrentDate(selectedDate)
}
})
}
}
In your view model DashboardViewModel add a function that will update the state correctly with the received date value.
fun updateCurrentDate(date: LocalDate) {
val locale = Locale.getDefault() // or set your Locale if the default is not correct
val dayOfTheWeek = date.dayOfWeek.getDisplayName(TextStyle.FULL, locale)
_state.update { it.copy(currentDate = date, dayOfTheWeek = dayOfTheWeek) }
}

Categories

Resources