Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions app/src/main/java/ru/otus/composehomework/ui/task1/Task1Screen.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
package ru.otus.composehomework.ui.task1

import androidx.compose.runtime.Composable
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

/**
* Задание 1: Переписывание XML на Compose
Expand All @@ -22,5 +31,31 @@ import androidx.compose.runtime.Composable
*/
@Composable
fun Task1Screen() {
// TODO: Реализуйте экран на Compose
var welcomeText by remember { mutableStateOf("Добро пожаловать!") }

Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(32.dp)
) {
Text(
text = welcomeText,
fontSize = 24.sp,
fontWeight = FontWeight.Bold
)

Image(
painter = painterResource(id = android.R.drawable.ic_dialog_info),
contentDescription = "Welcome",
modifier = Modifier.size(120.dp)
)

Button(
onClick = { welcomeText = "Кнопка нажата!" }
) {
Text("Нажми меня")
}
}
}
42 changes: 40 additions & 2 deletions app/src/main/java/ru/otus/composehomework/ui/task2/Task2Screen.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
package ru.otus.composehomework.ui.task2

import androidx.compose.runtime.Composable
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

/**
* Задание 2: Добавление состояния
Expand All @@ -20,5 +29,34 @@ import androidx.compose.runtime.Composable
*/
@Composable
fun Task2Screen() {
// TODO: Реализуйте экран с состоянием счетчика
var count by remember { mutableStateOf(0) }
val welcomeText = "Кнопка нажата $count раз!"

Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(32.dp)
) {
Text(
text = welcomeText,
fontSize = 24.sp,
fontWeight = FontWeight.Bold
)

Image(
painter = painterResource(id = android.R.drawable.ic_dialog_info),
contentDescription = "Welcome",
modifier = Modifier.size(120.dp)
)

Text(text = "Счетчик: $count")

Button(
onClick = { count++ }
) {
Text("Нажми меня")
}
}
}
187 changes: 185 additions & 2 deletions app/src/main/java/ru/otus/composehomework/ui/task3/Task3Screen.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
package ru.otus.composehomework.ui.task3

import androidx.compose.runtime.Composable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import ru.otus.composehomework.R

/**
* Задание 3: Подключение ViewModel и комплексное состояние (MVI паттерн)
Expand Down Expand Up @@ -44,5 +55,177 @@ import androidx.compose.runtime.Composable
*/
@Composable
fun Task3Screen() {
// TODO: Реализуйте экран с ViewModel и формой
val viewModel: Task3ViewModel = viewModel()
val state by viewModel.state.collectAsState()

Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Text(
text = "Форма обратной связи",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(bottom = 8.dp)
)

TextField(
value = state.name,
onValueChange = {
viewModel.handleIntent(Task3Intent.NameChanged(it))
},
label = { Text("Имя") },
placeholder = { Text(stringResource(R.string.name_hint)) },
modifier = Modifier.fillMaxWidth(),
isError = state.validationErrors?.errors?.get(FieldType.NAME) != null,
supportingText = state.validationErrors?.errors?.get(FieldType.NAME)?.let {
{ Text(it) }
},
enabled = state.uiState !is UiState.Loading
)

TextField(
value = state.email,
onValueChange = {
viewModel.handleIntent(Task3Intent.EmailChanged(it))
},
label = { Text("Email") },
placeholder = { Text(stringResource(R.string.email_hint)) },
modifier = Modifier.fillMaxWidth(),
isError = state.validationErrors?.errors?.get(FieldType.EMAIL) != null,
supportingText = state.validationErrors?.errors?.get(FieldType.EMAIL)?.let {
{ Text(it) }
},
enabled = state.uiState !is UiState.Loading
)

TextField(
value = state.message,
onValueChange = {
viewModel.handleIntent(Task3Intent.MessageChanged(it))
},
label = { Text("Сообщение") },
placeholder = { Text(stringResource(R.string.message_hint)) },
modifier = Modifier.fillMaxWidth(),
minLines = 3,
isError = state.validationErrors?.errors?.get(FieldType.MESSAGE) != null,
supportingText = state.validationErrors?.errors?.get(FieldType.MESSAGE)?.let {
{ Text(it) }
},
enabled = state.uiState !is UiState.Loading
)

Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Button(
onClick = {
viewModel.handleIntent(Task3Intent.SubmitClicked)
},
enabled = state.uiState !is UiState.Loading,
modifier = Modifier.weight(1f)
) {
Text(stringResource(R.string.submit))
}

OutlinedButton(
onClick = {
viewModel.handleIntent(Task3Intent.ClearClicked)
},
enabled = state.uiState !is UiState.Loading,
modifier = Modifier.weight(1f)
) {
Text(stringResource(R.string.clear))
}
}

when (state.uiState) {
is UiState.Loading -> {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
}

is UiState.Success -> {
val successState = state.uiState as UiState.Success
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.3f)
)
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = "Успешно!",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold
)
Text(
text = "Форма успешно отправлена!",
style = MaterialTheme.typography.bodyMedium
)
Text(
text = "ID: ${successState.result.id}",
style = MaterialTheme.typography.bodySmall
)
}
}
}

is UiState.Error -> {
val errorState = state.uiState as UiState.Error
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.errorContainer.copy(alpha = 0.3f)
)
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(
text = "Ошибка",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.error
)
Text(
text = errorState.message,
style = MaterialTheme.typography.bodyMedium
)
Button(
onClick = {
viewModel.handleIntent(Task3Intent.RetryClicked)
},
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.retry))
}
}
}
}

is UiState.ValidationError -> {
// Ошибки валидации уже обработаны
}

is UiState.Idle -> {
// Форма готова к заполнению
}
}
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@
<string name="submit">Отправить</string>
<string name="retry">Повторить</string>
<string name="loading">Загрузка...</string>
<string name="clear">Очистить</string>
</resources>