Improve the code

Signed-off-by: denis0001-dev <denis0001.dev@ya.ru>
This commit is contained in:
2025-09-07 20:29:32 +03:00
Unverified
parent 1c14053e96
commit aa99f415bf
6 changed files with 159 additions and 115 deletions
-18
View File
@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-09-06T11:23:47.273402Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/denis0001-dev/.android/avd/Pixel_9_Pro_XL.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
</project>
+2
View File
@@ -57,5 +57,7 @@
<option name="composableFile" value="true" /> <option name="composableFile" value="true" />
<option name="previewFile" value="true" /> <option name="previewFile" value="true" />
</inspection_tool> </inspection_tool>
<inspection_tool class="PropertyName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedSymbol" enabled="true" level="WEAK WARNING" enabled_by_default="true" editorAttributes="INFO_ATTRIBUTES" />
</profile> </profile>
</component> </component>
@@ -0,0 +1,40 @@
package ru.fromchat.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
@Composable
fun RowHeader(
icon: ImageVector,
title: String,
subtitle: String
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Icon(
imageVector = icon,
contentDescription = null,
modifier = Modifier
.padding(bottom = 8.dp)
.size(30.dp),
)
Text(
text = title,
style = MaterialTheme.typography.titleLarge,
modifier = Modifier.padding(bottom = 8.dp)
)
Text(
text = subtitle,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(bottom = 16.dp)
)
}
}
@@ -2,17 +2,15 @@ package ru.fromchat.ui.auth
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Login import androidx.compose.material.icons.automirrored.filled.Login
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -28,12 +26,14 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.fromchat.api.ApiClient import ru.fromchat.api.ApiClient
import ru.fromchat.api.LoginRequest import ru.fromchat.api.LoginRequest
import ru.fromchat.ui.RowHeader
@Composable @Composable
fun LoginScreen( fun LoginScreen(
onLoginSuccess: () -> Unit, onLoginSuccess: () -> Unit,
onNavigateToRegister: () -> Unit onNavigateToRegister: () -> Unit
) { ) {
Scaffold { innerPadding ->
var username by remember { mutableStateOf("") } var username by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") } var password by remember { mutableStateOf("") }
var alert by remember { mutableStateOf<String?>(null) } var alert by remember { mutableStateOf<String?>(null) }
@@ -41,17 +41,24 @@ fun LoginScreen(
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(innerPadding)
.padding(16.dp), .padding(16.dp),
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Card(modifier = Modifier.padding(16.dp)) { Column(
Column(modifier = Modifier.padding(16.dp)) { modifier = Modifier.padding(16.dp),
RowHeader() horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
RowHeader(
icon = Icons.AutoMirrored.Filled.Login,
title = "Welcome!",
subtitle = "Log in to your account"
)
if (alert != null) { if (alert != null) {
Text(text = alert!!, color = MaterialTheme.colorScheme.error) Text(text = alert!!, color = MaterialTheme.colorScheme.error)
Spacer(Modifier.height(8.dp))
} }
OutlinedTextField( OutlinedTextField(
@@ -60,7 +67,7 @@ fun LoginScreen(
label = { Text("Имя пользователя") }, label = { Text("Имя пользователя") },
singleLine = true singleLine = true
) )
Spacer(Modifier.height(8.dp))
OutlinedTextField( OutlinedTextField(
value = password, value = password,
onValueChange = { password = it }, onValueChange = { password = it },
@@ -69,12 +76,14 @@ fun LoginScreen(
visualTransformation = PasswordVisualTransformation() visualTransformation = PasswordVisualTransformation()
) )
Spacer(Modifier.height(12.dp)) FlowRow(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
Button(onClick = { Button(
onClick = {
if (username.isBlank() || password.isBlank()) { if (username.isBlank() || password.isBlank()) {
alert = "Пожалуйста, заполните все поля" alert = "Пожалуйста, заполните все поля"
return@Button return@Button
} }
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
ApiClient.login(LoginRequest(username, password)) ApiClient.login(LoginRequest(username, password))
@@ -83,21 +92,16 @@ fun LoginScreen(
alert = "Неверное имя пользователя или пароль" alert = "Неверное имя пользователя или пароль"
} }
} }
}) { Text("Войти") }
Spacer(Modifier.height(8.dp))
Button(onClick = onNavigateToRegister) { Text("Зарегистрируйтесь") }
}
}
} }
) {
Text("Войти")
} }
@Composable Button(onClick = onNavigateToRegister) {
private fun RowHeader() { Text("Зарегистрируйтесь")
Column(horizontalAlignment = Alignment.CenterHorizontally) { }
Icon(Icons.AutoMirrored.Filled.Login, contentDescription = null) }
Text("Добро пожаловать!") }
Text("Войдите в свой аккаунт", style = MaterialTheme.typography.bodyMedium) }
Spacer(Modifier.height(8.dp))
} }
} }
@@ -1,18 +1,16 @@
package ru.fromchat.ui.auth package ru.fromchat.ui.auth
import android.util.Log
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PersonAdd import androidx.compose.material.icons.filled.PersonAdd
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -28,11 +26,13 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.fromchat.api.ApiClient import ru.fromchat.api.ApiClient
import ru.fromchat.api.RegisterRequest import ru.fromchat.api.RegisterRequest
import ru.fromchat.ui.RowHeader
@Composable @Composable
fun RegisterScreen( fun RegisterScreen(
onRegistered: () -> Unit onRegistered: () -> Unit
) { ) {
Scaffold { innerPadding ->
var username by remember { mutableStateOf("") } var username by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") } var password by remember { mutableStateOf("") }
var confirmPassword by remember { mutableStateOf("") } var confirmPassword by remember { mutableStateOf("") }
@@ -41,22 +41,24 @@ fun RegisterScreen(
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(innerPadding)
.padding(16.dp), .padding(16.dp),
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Card(modifier = Modifier.padding(16.dp)) { Column(
Column(modifier = Modifier.padding(16.dp)) { modifier = Modifier.padding(16.dp),
Column(horizontalAlignment = Alignment.CenterHorizontally) { horizontalAlignment = Alignment.CenterHorizontally,
Icon(Icons.Default.PersonAdd, contentDescription = null) verticalArrangement = Arrangement.spacedBy(8.dp)
Text("Регистрация") ) {
Text("Создайте новый аккаунт", style = MaterialTheme.typography.bodyMedium) RowHeader(
Spacer(Modifier.height(8.dp)) icon = Icons.Filled.PersonAdd,
} title = "Register",
subtitle = "Create a new account"
)
if (alert != null) { if (alert != null) {
Text(text = alert!!, color = MaterialTheme.colorScheme.error) Text(text = alert!!, color = MaterialTheme.colorScheme.error)
Spacer(Modifier.height(8.dp))
} }
OutlinedTextField( OutlinedTextField(
@@ -65,7 +67,7 @@ fun RegisterScreen(
label = { Text("Имя пользователя") }, label = { Text("Имя пользователя") },
singleLine = true singleLine = true
) )
Spacer(Modifier.height(8.dp))
OutlinedTextField( OutlinedTextField(
value = password, value = password,
onValueChange = { password = it }, onValueChange = { password = it },
@@ -73,7 +75,7 @@ fun RegisterScreen(
singleLine = true, singleLine = true,
visualTransformation = PasswordVisualTransformation() visualTransformation = PasswordVisualTransformation()
) )
Spacer(Modifier.height(8.dp))
OutlinedTextField( OutlinedTextField(
value = confirmPassword, value = confirmPassword,
onValueChange = { confirmPassword = it }, onValueChange = { confirmPassword = it },
@@ -82,8 +84,9 @@ fun RegisterScreen(
visualTransformation = PasswordVisualTransformation() visualTransformation = PasswordVisualTransformation()
) )
Spacer(Modifier.height(12.dp)) Button(
Button(onClick = { onClick = {
// Checks
if (username.isBlank() || password.isBlank() || confirmPassword.isBlank()) { if (username.isBlank() || password.isBlank() || confirmPassword.isBlank()) {
alert = "Пожалуйста, заполните все поля" alert = "Пожалуйста, заполните все поля"
return@Button return@Button
@@ -100,15 +103,27 @@ fun RegisterScreen(
alert = "Пароль должен быть от 5 до 50 символов" alert = "Пароль должен быть от 5 до 50 символов"
return@Button return@Button
} }
// Send the register request
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
try { try {
ApiClient.register(RegisterRequest(username, password, confirmPassword)) ApiClient.register(
RegisterRequest(
username,
password,
confirmPassword
)
)
onRegistered() onRegistered()
} catch (e: Exception) { } catch (e: Exception) {
Log.d("RegisterScreen", "Error while registering:", e)
alert = "Ошибка при регистрации" alert = "Ошибка при регистрации"
} }
} }
}) { Text("Зарегистрироваться") } }
) {
Text("Зарегистрироваться")
}
} }
} }
} }
@@ -67,6 +67,7 @@ fun BaseChat(
if (composing.isNotBlank()) { if (composing.isNotBlank()) {
// Note: server schema for public chat messages is not specified in the repo. // Note: server schema for public chat messages is not specified in the repo.
// We send a generic WebSocketMessage to match frontend type contract. // We send a generic WebSocketMessage to match frontend type contract.
// TODO correct the payload
val payload = WebSocketMessage( val payload = WebSocketMessage(
type = "public_chat_message", type = "public_chat_message",
data = buildJsonObject { data = buildJsonObject {