I am pdfile

This commit is contained in:
maxnes3 2023-12-28 03:14:59 +04:00
parent 7baad4c44e
commit a29f8803ae
9 changed files with 341 additions and 165 deletions

View File

@ -0,0 +1,5 @@
package com.example.mobileapp.api
enum class ApiStatus {
LOADING, ERROR, DONE, NONE
}

View File

@ -13,9 +13,11 @@ class RemoteConverters {
fun fromBitmap(bitmap: Bitmap): String { fun fromBitmap(bitmap: Bitmap): String {
val outputStream = ByteArrayOutputStream() val outputStream = ByteArrayOutputStream()
val extendedBitmap = scaleRatioBitmap(bitmap)
// Сжимаем изображение до указанного максимального размера // Сжимаем изображение до указанного максимального размера
val quality = calculateQuality(bitmap) val quality = calculateQuality(extendedBitmap)
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream) extendedBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream)
val byteArray = outputStream.toByteArray() val byteArray = outputStream.toByteArray()
return Base64.encodeToString(byteArray, Base64.NO_WRAP) return Base64.encodeToString(byteArray, Base64.NO_WRAP)
@ -28,8 +30,6 @@ class RemoteConverters {
private fun calculateQuality(bitmap: Bitmap): Int { private fun calculateQuality(bitmap: Bitmap): Int {
val outputStream = ByteArrayOutputStream() val outputStream = ByteArrayOutputStream()
/*bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
val initialSize = outputStream.size()*/
// Уменьшаем качество изображения, пока его размер не станет меньше максимального // Уменьшаем качество изображения, пока его размер не станет меньше максимального
var quality = 100 var quality = 100
@ -42,5 +42,21 @@ class RemoteConverters {
// Возвращаем качество, при котором размер изображения удовлетворяет ограничению // Возвращаем качество, при котором размер изображения удовлетворяет ограничению
return if (quality < 0) 0 else quality return if (quality < 0) 0 else quality
} }
private fun scaleRatioBitmap(bitmap: Bitmap): Bitmap {
val maxWidth = 990
val maxHeight = 990
if (bitmap.width > maxWidth || bitmap.height > maxHeight) {
// Если размер превышает максимальный, масштабируем изображение
val ratio = Math.min(maxWidth.toFloat() / bitmap.width,
maxHeight.toFloat() / bitmap.height)
val width = (ratio * bitmap.width).toInt()
val height = (ratio * bitmap.height).toInt()
return Bitmap.createScaledBitmap(bitmap, width, height, true)
}
return bitmap
}
} }
} }

View File

@ -352,16 +352,3 @@ fun DialogWindow(label: String, message: String, onConfirmAction: () -> Unit, on
} }
) )
} }
@Composable
fun LoadingScreen() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
}
}

View File

@ -0,0 +1,75 @@
package com.example.mobileapp.database.viewmodels
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.mobileapp.api.ApiStatus
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.io.IOException
open class CustomViewModel : ViewModel() {
var apiStatus by mutableStateOf(ApiStatus.NONE)
private set
var apiError by mutableStateOf("")
private set
fun runInScope(
actionSuccess: suspend () -> Unit,
actionError: suspend () -> Unit
) {
viewModelScope.launch {
apiStatus = ApiStatus.LOADING
runCatching {
actionSuccess()
apiStatus = ApiStatus.DONE
apiError = ""
}.onFailure { e: Throwable ->
when (e) {
is IOException,
is HttpException -> {
actionError()
apiStatus = ApiStatus.ERROR
apiError = e.localizedMessage ?: e.toString()
}
else -> throw e
}
}
}
}
fun runInScope(actionSuccess: suspend () -> Unit) {
runInScope(actionSuccess, actionError = {})
}
fun clearStatus(){
apiStatus = ApiStatus.NONE
}
}
@Composable
fun LoadingScreen(color: Color) {
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator(
color = color,
strokeWidth = 6.dp
)
}
}

View File

@ -11,7 +11,7 @@ import com.example.mobileapp.database.repositories.UserRepository
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class UserViewModel(private val userRepository: UserRepository): ViewModel() { class UserViewModel(private val userRepository: UserRepository): CustomViewModel() {
//val getAllUsers = userRepository.getAllUsers() //val getAllUsers = userRepository.getAllUsers()
suspend fun getUser(id: Int): User? = userRepository.getUser(id) suspend fun getUser(id: Int): User? = userRepository.getUser(id)
@ -28,9 +28,13 @@ class UserViewModel(private val userRepository: UserRepository): ViewModel() {
if (user.password.isEmpty()){ if (user.password.isEmpty()){
return@launch return@launch
} }
runInScope(
actionSuccess = {
userRepository.updateUser(user) userRepository.updateUser(user)
GlobalUser.getInstance().setUser(user) GlobalUser.getInstance().setUser(user)
} }
)
}
fun deleteUser(user: User) = viewModelScope.launch { fun deleteUser(user: User) = viewModelScope.launch {
userRepository.deleteUser(user) userRepository.deleteUser(user)
@ -44,18 +48,38 @@ class UserViewModel(private val userRepository: UserRepository): ViewModel() {
if(user.email.isEmpty() || !isValidEmail(user.email)){ if(user.email.isEmpty() || !isValidEmail(user.email)){
return@launch return@launch
} }
runInScope(
actionSuccess = {
userRepository.insertUser(user) userRepository.insertUser(user)
GlobalUser.getInstance().setUser(userRepository.getUserByLogin( GlobalUser.getInstance().setUser(userRepository.getUserByLogin(
UserRemoteSignIn(user.login, user.password))) UserRemoteSignIn(user.login, user.password)))
} }
)
/*userRepository.insertUser(user)
GlobalUser.getInstance().setUser(userRepository.getUserByLogin(
UserRemoteSignIn(user.login, user.password)))*/
}
fun authUser(user: User) = viewModelScope.launch { fun authUser(user: User) = viewModelScope.launch {
runInScope(
actionSuccess = {
val globalUser = userRepository.getUserByLogin(UserRemoteSignIn(user.login, user.password)) val globalUser = userRepository.getUserByLogin(UserRemoteSignIn(user.login, user.password))
globalUser?.let { globalUser?.let {
if (user.password.isNotEmpty() && user.password == globalUser.password){ if (user.password.isNotEmpty() && user.password == globalUser.password){
GlobalUser.getInstance().setUser(globalUser) GlobalUser.getInstance().setUser(globalUser)
} }
} }
},
actionError = {
GlobalUser.getInstance().setUser(null)
}
)
/*val globalUser = userRepository.getUserByLogin(UserRemoteSignIn(user.login, user.password))
globalUser?.let {
if (user.password.isNotEmpty() && user.password == globalUser.password){
GlobalUser.getInstance().setUser(globalUser)
}
}*/
} }
private fun isValidEmail(email: String): Boolean { private fun isValidEmail(email: String): Boolean {

View File

@ -1,5 +1,6 @@
package com.example.mobileapp.screens package com.example.mobileapp.screens
import android.widget.Toast
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -23,12 +24,14 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.example.mobileapp.GlobalUser import com.example.mobileapp.GlobalUser
import com.example.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.api.ApiStatus
import com.example.mobileapp.components.ActiveButton import com.example.mobileapp.components.ActiveButton
import com.example.mobileapp.components.NavigationButton import com.example.mobileapp.components.NavigationButton
import com.example.mobileapp.components.PasswordInputField import com.example.mobileapp.components.PasswordInputField
import com.example.mobileapp.components.PlaceholderInputField import com.example.mobileapp.components.PlaceholderInputField
import com.example.mobileapp.database.MobileAppDataBase import com.example.mobileapp.database.MobileAppDataBase
import com.example.mobileapp.database.entities.User import com.example.mobileapp.database.entities.User
import com.example.mobileapp.database.viewmodels.LoadingScreen
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.database.viewmodels.UserViewModel import com.example.mobileapp.database.viewmodels.UserViewModel
import com.example.mobileapp.ui.theme.ButtonColor1 import com.example.mobileapp.ui.theme.ButtonColor1
@ -41,16 +44,23 @@ fun Authorization(navController: NavHostController,
userViewModel: UserViewModel = viewModel( userViewModel: UserViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory factory = MobileAppViewModelProvider.Factory
)) { )) {
val isAuthorizated = remember { mutableStateOf(false) } val context = LocalContext.current
if(GlobalUser.getInstance().getUser() != null && !isAuthorizated.value) { when(userViewModel.apiStatus){
isAuthorizated.value = !isAuthorizated.value ApiStatus.DONE -> {
navController.navigate("main") navController.navigate("main")
userViewModel.clearStatus()
}
ApiStatus.LOADING -> LoadingScreen(ButtonColor2)
ApiStatus.ERROR -> Toast.makeText(context, "Не верные данные или пользователя не существует: "
+ userViewModel.apiError, Toast.LENGTH_SHORT).show()
else -> {}
} }
val login = remember { mutableStateOf("") } val login = remember { mutableStateOf("") }
val password = remember { mutableStateOf("") } val password = remember { mutableStateOf("") }
if(userViewModel.apiStatus != ApiStatus.LOADING) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -64,8 +74,12 @@ fun Authorization(navController: NavHostController,
modifier = Modifier modifier = Modifier
.size(448.dp) .size(448.dp)
.padding(8.dp) .padding(8.dp)
.align(Alignment.CenterHorizontally)) .align(Alignment.CenterHorizontally)
PlaceholderInputField(label = "Логин", isSingleLine = true, onTextChanged = {newlogin -> )
PlaceholderInputField(
label = "Логин",
isSingleLine = true,
onTextChanged = { newlogin ->
login.value = newlogin login.value = newlogin
}) })
PasswordInputField(label = "Пароль", onPasswordChanged = { newpassword -> PasswordInputField(label = "Пароль", onPasswordChanged = { newpassword ->
@ -83,7 +97,10 @@ fun Authorization(navController: NavHostController,
) )
} }
}) })
NavigationButton(navController = navController, destination = "registration", label = "Регистрация", NavigationButton(
backgroundColor = ButtonColor1, textColor = Color.Black) navController = navController, destination = "registration", label = "Регистрация",
backgroundColor = ButtonColor1, textColor = Color.Black
)
}
} }
} }

View File

@ -6,6 +6,7 @@ import android.graphics.ImageDecoder
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.provider.MediaStore import android.provider.MediaStore
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.BorderStroke
@ -44,12 +45,14 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.example.mobileapp.GlobalUser import com.example.mobileapp.GlobalUser
import com.example.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.api.ApiStatus
import com.example.mobileapp.components.ActiveButton import com.example.mobileapp.components.ActiveButton
import com.example.mobileapp.components.NavigationButton import com.example.mobileapp.components.NavigationButton
import com.example.mobileapp.components.PlaceholderInputField import com.example.mobileapp.components.PlaceholderInputField
import com.example.mobileapp.database.entities.Mail import com.example.mobileapp.database.entities.Mail
import com.example.mobileapp.database.entities.Story import com.example.mobileapp.database.entities.Story
import com.example.mobileapp.database.entities.User import com.example.mobileapp.database.entities.User
import com.example.mobileapp.database.viewmodels.LoadingScreen
import com.example.mobileapp.database.viewmodels.MailViewModel import com.example.mobileapp.database.viewmodels.MailViewModel
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.database.viewmodels.StoryViewModel import com.example.mobileapp.database.viewmodels.StoryViewModel
@ -207,6 +210,16 @@ fun EditUserScreen(navController: NavHostController,
factory = MobileAppViewModelProvider.Factory factory = MobileAppViewModelProvider.Factory
)) { )) {
val context = LocalContext.current val context = LocalContext.current
when(userViewModel.apiStatus){
ApiStatus.DONE -> {
navController.navigate("settings")
userViewModel.clearStatus()
}
ApiStatus.LOADING -> LoadingScreen(ButtonColor2)
ApiStatus.ERROR -> Toast.makeText(context, "Не удалось обновить данные пользователя: "
+ userViewModel.apiError, Toast.LENGTH_SHORT).show()
else -> {}
}
var userId = remember { mutableStateOf(0) } var userId = remember { mutableStateOf(0) }
val photo = remember { mutableStateOf<Bitmap>(BitmapFactory.decodeResource(context.resources, R.drawable.photoplaceholder)) } val photo = remember { mutableStateOf<Bitmap>(BitmapFactory.decodeResource(context.resources, R.drawable.photoplaceholder)) }
@ -241,6 +254,7 @@ fun EditUserScreen(navController: NavHostController,
} }
} }
if(userViewModel.apiStatus != ApiStatus.LOADING) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -260,7 +274,8 @@ fun EditUserScreen(navController: NavHostController,
modifier = Modifier modifier = Modifier
.size(512.dp) .size(512.dp)
.blur(12.dp), .blur(12.dp),
colorFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) })) colorFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) })
)
Image( Image(
bitmap = photo.value.asImageBitmap(), bitmap = photo.value.asImageBitmap(),
contentDescription = "editplaceholder", contentDescription = "editplaceholder",
@ -268,9 +283,14 @@ fun EditUserScreen(navController: NavHostController,
modifier = Modifier modifier = Modifier
.padding(8.dp) .padding(8.dp)
.clip(CircleShape) .clip(CircleShape)
.size(384.dp)) .size(384.dp)
)
} }
ActiveButton(label = "Выбрать фото", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = { ActiveButton(
label = "Выбрать фото",
backgroundColor = ButtonColor1,
textColor = Color.Black,
onClickAction = {
launcher.launch("image/*") launcher.launch("image/*")
}) })
PlaceholderInputField(label = "Никнейм", isSingleLine = true, PlaceholderInputField(label = "Никнейм", isSingleLine = true,
@ -285,7 +305,11 @@ fun EditUserScreen(navController: NavHostController,
startValue = email.value, onTextChanged = { newEmail -> startValue = email.value, onTextChanged = { newEmail ->
email.value = newEmail email.value = newEmail
}) })
ActiveButton(label = "Сохранить", backgroundColor = ButtonColor1, textColor = Color.Black, onClickAction = { ActiveButton(
label = "Сохранить",
backgroundColor = ButtonColor1,
textColor = Color.Black,
onClickAction = {
userViewModel.updateUser( userViewModel.updateUser(
User( User(
id = userId.value, id = userId.value,
@ -295,7 +319,6 @@ fun EditUserScreen(navController: NavHostController,
photo = photo.value photo = photo.value
) )
) )
navController.navigate("settings")
}) })
ActiveButton(label = "Назад", backgroundColor = ButtonColor2, textColor = Color.White, ActiveButton(label = "Назад", backgroundColor = ButtonColor2, textColor = Color.White,
onClickAction = { onClickAction = {
@ -303,3 +326,4 @@ fun EditUserScreen(navController: NavHostController,
}) })
} }
} }
}

View File

@ -1,5 +1,6 @@
package com.example.mobileapp.screens package com.example.mobileapp.screens
import android.widget.Toast
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -13,17 +14,20 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.example.mobileapp.GlobalUser import com.example.mobileapp.GlobalUser
import com.example.mobileapp.R import com.example.mobileapp.R
import com.example.mobileapp.api.ApiStatus
import com.example.mobileapp.components.ActiveButton import com.example.mobileapp.components.ActiveButton
import com.example.mobileapp.components.NavigationButton import com.example.mobileapp.components.NavigationButton
import com.example.mobileapp.components.PasswordInputField import com.example.mobileapp.components.PasswordInputField
import com.example.mobileapp.components.PlaceholderInputField import com.example.mobileapp.components.PlaceholderInputField
import com.example.mobileapp.database.entities.User import com.example.mobileapp.database.entities.User
import com.example.mobileapp.database.viewmodels.LoadingScreen
import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider import com.example.mobileapp.database.viewmodels.MobileAppViewModelProvider
import com.example.mobileapp.database.viewmodels.UserViewModel import com.example.mobileapp.database.viewmodels.UserViewModel
import com.example.mobileapp.ui.theme.ButtonColor1 import com.example.mobileapp.ui.theme.ButtonColor1
@ -34,11 +38,15 @@ fun Registration(navController: NavHostController,
userViewModel: UserViewModel = viewModel( userViewModel: UserViewModel = viewModel(
factory = MobileAppViewModelProvider.Factory factory = MobileAppViewModelProvider.Factory
)) { )) {
val isRegistrated = remember { mutableStateOf(false) } val context = LocalContext.current
when(userViewModel.apiStatus){
if(GlobalUser.getInstance().getUser() != null && !isRegistrated.value) { ApiStatus.DONE -> {
isRegistrated.value = !isRegistrated.value
navController.navigate("main") navController.navigate("main")
userViewModel.clearStatus()
}
ApiStatus.LOADING -> LoadingScreen(ButtonColor2)
ApiStatus.ERROR -> Toast.makeText(context, "Не удалось создать пользователя: " + userViewModel.apiError, Toast.LENGTH_SHORT).show()
else -> {}
} }
val login = remember { mutableStateOf("") } val login = remember { mutableStateOf("") }
@ -46,6 +54,7 @@ fun Registration(navController: NavHostController,
val password = remember { mutableStateOf("") } val password = remember { mutableStateOf("") }
val repeatepassword = remember { mutableStateOf("") } val repeatepassword = remember { mutableStateOf("") }
if(userViewModel.apiStatus != ApiStatus.LOADING) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -59,11 +68,18 @@ fun Registration(navController: NavHostController,
modifier = Modifier modifier = Modifier
.size(320.dp) .size(320.dp)
.padding(8.dp) .padding(8.dp)
.align(Alignment.CenterHorizontally)) .align(Alignment.CenterHorizontally)
PlaceholderInputField(label = "Логин", isSingleLine = true, onTextChanged = {newlogin -> )
PlaceholderInputField(
label = "Логин",
isSingleLine = true,
onTextChanged = { newlogin ->
login.value = newlogin login.value = newlogin
}) })
PlaceholderInputField(label = "Email", isSingleLine = true, onTextChanged = {newemail -> PlaceholderInputField(
label = "Email",
isSingleLine = true,
onTextChanged = { newemail ->
email.value = newemail email.value = newemail
}) })
PasswordInputField(label = "Пароль", onPasswordChanged = { newpassword -> PasswordInputField(label = "Пароль", onPasswordChanged = { newpassword ->
@ -84,7 +100,10 @@ fun Registration(navController: NavHostController,
) )
} }
}) })
NavigationButton(navController = navController, destination = "authorization", NavigationButton(
label = "Назад", backgroundColor = ButtonColor1, textColor = Color.Black) navController = navController, destination = "authorization",
label = "Назад", backgroundColor = ButtonColor1, textColor = Color.Black
)
}
} }
} }

View File

@ -12,6 +12,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@ -37,6 +38,18 @@ fun ReportScreen(
.fillMaxWidth(), .fillMaxWidth(),
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center
) { ) {
Column(
modifier = Modifier
.fillMaxWidth(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Отчёт по публикациям:",
fontSize = 28.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(top = 16.dp, bottom = 16.dp, start = 8.dp, end = 8.dp))
}
if(reportViewModel.report.value == null) { if(reportViewModel.report.value == null) {
DatePicker(startValue = dateFrom.value, onDateSelected = { newDateFrom -> DatePicker(startValue = dateFrom.value, onDateSelected = { newDateFrom ->
dateFrom.value = newDateFrom dateFrom.value = newDateFrom
@ -50,13 +63,9 @@ fun ReportScreen(
}) })
} }
else{ else{
Text(text = "Отчёт по публикациям иллюстраций",
fontSize = 28.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(8.dp))
Text(text = "Дата с ${dateFormat.format(reportViewModel.report.value?.dateFrom?.let { Date(it) })}", Text(text = "Дата с ${dateFormat.format(reportViewModel.report.value?.dateFrom?.let { Date(it) })}",
fontSize = 20.sp, fontSize = 20.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
modifier = Modifier modifier = Modifier
.padding(8.dp)) .padding(8.dp))