diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index af7c6d3..cc9f46b 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -21,11 +21,16 @@ kotlin { sourceSets { val desktopMain by getting + + val commonMain by getting { + resources.srcDir("src/commonMain/composeResources") + } androidMain.dependencies { implementation(compose.preview) implementation(libs.androidx.activity.compose) implementation(libs.androidx.lifecycle.viewmodel) + implementation("io.ktor:ktor-client-okhttp:2.3.2") } commonMain.dependencies { val voyagerVersion = "1.1.0-beta02" @@ -40,10 +45,20 @@ kotlin { implementation("cafe.adriel.voyager:voyager-screenmodel:$voyagerVersion") implementation(compose.preview) implementation(libs.androidx.lifecycle.viewmodel) + implementation("media.kamel:kamel-image:0.7.0") + implementation("io.ktor:ktor-client-core:2.3.2") + implementation("io.ktor:ktor-client-cio:2.3.2") + implementation("io.ktor:ktor-client-okhttp:2.3.2") + + repositories { + google() + mavenCentral() + } } desktopMain.dependencies { implementation(compose.desktop.currentOs) implementation(libs.kotlinx.coroutines.swing) + implementation("io.ktor:ktor-client-okhttp:2.3.2") } } } diff --git a/composeApp/src/androidMain/kotlin/org/example/project/ViewModel/DatePickerField.kt b/composeApp/src/androidMain/kotlin/org/example/project/ViewModel/DatePickerField.kt new file mode 100644 index 0000000..a922927 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/org/example/project/ViewModel/DatePickerField.kt @@ -0,0 +1,80 @@ +//package org.example.project.ViewModel +// +//import android.app.DatePickerDialog +//import android.widget.DatePicker +//import androidx.compose.material.OutlinedTextField +//import androidx.compose.material.Text +//import androidx.compose.material.icons.Icons +//import androidx.compose.material.icons.filled.DateRange +//import androidx.compose.runtime.* +//import androidx.compose.ui.platform.LocalContext +//import androidx.compose.ui.Modifier +//import androidx.compose.foundation.clickable +//import androidx.compose.material.Icon +//import java.util.* +// +//@Composable +//actual fun DatePickerField( +// onDateSelected: (String) -> Unit, +// trigger: Boolean, +// onDismissRequest: () -> Unit +//) { +//// val context = LocalContext.current +//// val calendar = Calendar.getInstance() +//// +//// val datePickerDialog = remember { +//// DatePickerDialog( +//// context, +//// { _: DatePicker, year: Int, month: Int, dayOfMonth: Int -> +//// val formatted = "%02d.%02d.%04d".format(dayOfMonth, month + 1, year) +//// onDateSelected(formatted) +//// }, +//// calendar.get(Calendar.YEAR), +//// calendar.get(Calendar.MONTH), +//// calendar.get(Calendar.DAY_OF_MONTH) +//// ) +//// } +//// +//// OutlinedTextField( +//// value = selectedDate, +//// onValueChange = {}, +//// label = { Text("Выберите дату") }, +//// trailingIcon = { Icon(Icons.Default.DateRange, contentDescription = null) }, +//// readOnly = true, +//// modifier = modifier.clickable { datePickerDialog.show() } +//// ) +//} + +package org.example.project.ViewModel + +import android.app.DatePickerDialog +import android.widget.DatePicker +import androidx.compose.runtime.* +import androidx.compose.ui.platform.LocalContext +import java.util.* + +@Composable +actual fun DatePickerField( + onDateSelected: (String) -> Unit, + trigger: Boolean, + onDismissRequest: () -> Unit +) { + val context = LocalContext.current + + if (trigger) { + LaunchedEffect(Unit) { + val calendar = Calendar.getInstance() + DatePickerDialog( + context, + { _: DatePicker, year: Int, month: Int, dayOfMonth: Int -> + val formatted = "%02d.%02d.%04d".format(dayOfMonth, month + 1, year) + onDateSelected(formatted) + onDismissRequest() + }, + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH) + ).show() + } + } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/org/example/project/ViewModel/GetPath.kt b/composeApp/src/androidMain/kotlin/org/example/project/ViewModel/GetPath.kt new file mode 100644 index 0000000..a9216f7 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/org/example/project/ViewModel/GetPath.kt @@ -0,0 +1,61 @@ +//package org.example.project.ViewModel +// +//import androidx.compose.runtime.Composable +// +//@Composable +//actual fun GetPath(onPathSelected: (String) -> Unit){ +// +//} + +package org.example.project.ViewModel + +import android.app.Activity +import android.content.Intent +import android.net.Uri +import android.provider.OpenableColumns +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.runtime.* +import androidx.compose.ui.platform.LocalContext +import java.io.File +import java.io.FileOutputStream + +@Composable +actual fun GetPath(onPathSelected: (String) -> Unit) { + val context = LocalContext.current + var launched by remember { mutableStateOf(false) } + + val launcher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.GetContent(), + onResult = { uri: Uri? -> + if (uri != null) { + val inputStream = context.contentResolver.openInputStream(uri) + val fileName = getFileName(context.contentResolver, uri) ?: "temp_image.jpg" + val file = File(context.cacheDir, fileName) + val outputStream = FileOutputStream(file) + inputStream?.copyTo(outputStream) + inputStream?.close() + outputStream.close() + onPathSelected(file.absolutePath) + } + } + ) + + LaunchedEffect(Unit) { + if (!launched) { + launched = true + launcher.launch("image/*") + } + } +} + +fun getFileName(contentResolver: android.content.ContentResolver, uri: Uri): String? { + val returnCursor = contentResolver.query(uri, null, null, null, null) + returnCursor?.use { + val nameIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME) + if (it.moveToFirst()) { + return it.getString(nameIndex) + } + } + return null +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/org/example/project/ViewModel/ImageFromPath.kt b/composeApp/src/androidMain/kotlin/org/example/project/ViewModel/ImageFromPath.kt new file mode 100644 index 0000000..7aef5a2 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/org/example/project/ViewModel/ImageFromPath.kt @@ -0,0 +1,71 @@ +package org.example.project.ViewModel + +import android.graphics.BitmapFactory +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.painter.BitmapPainter +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.imageResource +import org.example.project.R +import java.io.File + + +@Composable +actual fun ImageFromPath(path: String, modifier: Modifier) { + val imageBitmap: ImageBitmap? = when { + path.isEmpty() -> { + ImageBitmap.imageResource(id = R.drawable.basic_photo) + } + + else -> { + val file = File(path) + if (file.exists()) { + val bitmap = BitmapFactory.decodeFile(file.absolutePath) + bitmap?.asImageBitmap() + } else null + } + } + + if (imageBitmap != null) { + Image( + painter = BitmapPainter(imageBitmap), + contentDescription = null, + modifier = modifier, + contentScale = ContentScale.Crop + ) + } else { + Box(modifier = modifier.fillMaxSize()) + } +} + +//@Composable +//actual fun ImageFromPath(path: String, modifier: Modifier) { +// // Попытка загрузить изображение из локального пути +// if (path == ""){ +// path = +// } +// +// val file = File(path) +// val imageBitmap: ImageBitmap? = if (file.exists()) { +// val bitmap = BitmapFactory.decodeFile(file.absolutePath) +// bitmap?.asImageBitmap() +// } else { +// null +// } +// +// if (imageBitmap != null) { +// Image( +// painter = BitmapPainter(imageBitmap), +// contentDescription = null, +// modifier = modifier, +// contentScale = ContentScale.Crop +// ) +// } else { +// Box(modifier = modifier.fillMaxSize()) +// } +//} \ No newline at end of file diff --git a/composeApp/src/androidMain/res/drawable/basic_photo.png b/composeApp/src/androidMain/res/drawable/basic_photo.png new file mode 100644 index 0000000..854f363 Binary files /dev/null and b/composeApp/src/androidMain/res/drawable/basic_photo.png differ diff --git a/composeApp/src/commonMain/composeResources/drawable/basicPhoto.png b/composeApp/src/commonMain/composeResources/drawable/basicPhoto.png new file mode 100644 index 0000000..854f363 Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/basicPhoto.png differ diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/DatePickerField.kt b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/DatePickerField.kt new file mode 100644 index 0000000..cc03f17 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/DatePickerField.kt @@ -0,0 +1,23 @@ +package org.example.project.ViewModel + +import androidx.compose.foundation.clickable +import androidx.compose.material.OutlinedTextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.material.Text +import androidx.compose.ui.Modifier +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.Icon +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.DateRange +import java.util.Calendar + +@Composable +expect fun DatePickerField( + onDateSelected: (String) -> Unit, + trigger: Boolean, + onDismissRequest: () -> Unit +) diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/FieldWithDropdown.kt b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/FieldWithDropdown.kt new file mode 100644 index 0000000..acd2645 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/FieldWithDropdown.kt @@ -0,0 +1,106 @@ +package org.example.project.ViewModel + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +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.text.style.TextAlign +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp + +@Composable +fun FieldWithDropdown( + label: String, + options: List, + selectedOption: String, + onOptionSelected: (String) -> Unit, + fontSize: TextUnit, + labelWidth: Float +) { + var expanded by remember { mutableStateOf(false) } + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxWidth() + ) { + Box(modifier = Modifier.weight(labelWidth)) { + Text( + text = label, + color = Color.DarkGray, + textAlign = TextAlign.Start, + fontSize = fontSize, + ) + } + + Box( + modifier = Modifier + .weight(1f) + .fillMaxWidth() + .background(Color.White, shape = RoundedCornerShape(4.dp)) + .border( + width = 1.dp, + color = Color(0xFFCCCCCC), + shape = RoundedCornerShape(4.dp) + ) + .clickable { expanded = true } + .padding(12.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = selectedOption.ifEmpty { "..." }, + fontSize = fontSize, + color = if (selectedOption.isEmpty()) Color.LightGray else Color.Black + ) + + Icon( + imageVector = Icons.Default.ArrowDropDown, + contentDescription = "Dropdown Arrow", + tint = Color.Gray + ) + } + + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier + .background(Color.White) + .fillMaxWidth() + ) { + options.forEach { option -> + DropdownMenuItem( + onClick = { + onOptionSelected(option) + expanded = false + } + ) { + Text(option, fontSize = fontSize, color = Color.Black) + } + } + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/FieldWithLabel.kt b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/FieldWithLabel.kt new file mode 100644 index 0000000..b60e002 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/FieldWithLabel.kt @@ -0,0 +1,73 @@ +package org.example.project.ViewModel + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material.OutlinedTextField +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.text.style.TextAlign +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp + +@Composable +fun FieldWithLabel( + label: String, + value: String, + onValueChange: (String) -> Unit, + placeholder: String, + fontSize: TextUnit, + labelWidth: Float, + enabled: Boolean = true, +) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxWidth() + ) { + Box(modifier = Modifier.weight(labelWidth)) { + Text( + text = label, + color = Color.DarkGray, + textAlign = TextAlign.Start, + fontSize = fontSize, + modifier = Modifier + ) + } + + OutlinedTextField( + value = value, + onValueChange = onValueChange, + placeholder = { + if (placeholder.isNotEmpty()) { + Text( + text = placeholder, + fontSize = fontSize, + color = Color.LightGray + ) + } + }, + textStyle = androidx.compose.ui.text.TextStyle( + fontSize = fontSize, + color = Color.Black + ), + enabled = enabled, + colors = androidx.compose.material.TextFieldDefaults.outlinedTextFieldColors( + backgroundColor = Color.White, + cursorColor = Color.Black, + textColor = Color.Black, + placeholderColor = Color.LightGray, + focusedBorderColor = Color(0xFFCCCCCC), + unfocusedBorderColor = Color(0xFFCCCCCC), + disabledBorderColor = Color(0xFFCCCCCC) + ), + modifier = Modifier.weight(1f).wrapContentWidth().fillMaxWidth() + ) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/FieldWithLabelInt.kt b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/FieldWithLabelInt.kt new file mode 100644 index 0000000..bc5409c --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/FieldWithLabelInt.kt @@ -0,0 +1,86 @@ +package org.example.project.ViewModel + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.OutlinedTextField +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.text.input.KeyboardType +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp + +@Composable +fun FieldWithLabelInt( + label: String, + value: Int, + onValueChange: (Int) -> Unit, + placeholder: String, + fontSize: TextUnit, + labelWidth: Float, + enabled: Boolean = true, +) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxWidth() + ) { + Box(modifier = Modifier.weight(labelWidth)) { + Text( + text = label, + color = Color.DarkGray, + textAlign = TextAlign.Start, + fontSize = fontSize, + ) + } + + OutlinedTextField( + value = value.toString(), + onValueChange = { newValue -> + val intValue = newValue.toIntOrNull() + if (intValue != null) { + onValueChange(intValue) + } + }, + placeholder = { + if (placeholder.isNotEmpty()) { + Text( + text = placeholder, + fontSize = fontSize, + color = Color.LightGray + ) + } + }, + textStyle = androidx.compose.ui.text.TextStyle( + fontSize = fontSize, + color = Color.Black + ), + enabled = enabled, + colors = androidx.compose.material.TextFieldDefaults.outlinedTextFieldColors( + backgroundColor = Color.White, + cursorColor = Color.Black, + textColor = Color.Black, + placeholderColor = Color.LightGray, + focusedBorderColor = Color(0xFFCCCCCC), + unfocusedBorderColor = Color(0xFFCCCCCC), + disabledBorderColor = Color(0xFFCCCCCC) + ), + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Done + ), + modifier = Modifier + .weight(1f) + .wrapContentWidth() + .fillMaxWidth() + ) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/GetPath.kt b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/GetPath.kt new file mode 100644 index 0000000..efbcb70 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/GetPath.kt @@ -0,0 +1,7 @@ +package org.example.project.ViewModel + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +expect fun GetPath(onPathSelected: (String) -> Unit) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/ImageFromPath.kt b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/ImageFromPath.kt new file mode 100644 index 0000000..eafe1ae --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ViewModel/ImageFromPath.kt @@ -0,0 +1,18 @@ +package org.example.project.ViewModel + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.remember +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale +import io.kamel.image.asyncPainterResource +import io.kamel.core.Resource +import io.kamel.core.getOrNull + +@Composable +expect fun ImageFromPath(path: String = "", modifier: Modifier = Modifier) diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/ConfirmRunner.kt b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/ConfirmRunner.kt new file mode 100644 index 0000000..a51a8df --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/ConfirmRunner.kt @@ -0,0 +1,217 @@ +package org.example.project.ui.Screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +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.sp +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import org.example.project.ViewModel.TimerViewModel + +class ConfirmRunnerScreen(private val timerViewModel: TimerViewModel) : + Screen { + + @Composable + override fun Content() { + val navigator = LocalNavigator.currentOrThrow + + Scaffold( + topBar = { ConfirmRunnerTopBar() }, + bottomBar = { ConfirmRunnerBottomBar(timerViewModel = timerViewModel) } + ) { paddingValues -> + + Box( + modifier = Modifier.padding(paddingValues) + ) { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + .padding(horizontal = 100.dp) + ) { + val fontSizeFirst = (maxWidth.value / 30).sp + val fontSizeSecond = (maxWidth.value / 40).sp + + Column( + modifier = Modifier + .fillMaxWidth().padding(bottom = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Spacer(modifier = Modifier.weight(0.2f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "Спасибо за вашу регистрацию в качестве бегуна!", + color = Color.Gray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.2f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "Спасибо за вашу регистрацию в качестве бегуна в Marathon Skills 2016!\n С вами свяжутся по поводу оплаты.", + color = Color.Black, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.2f)) + + Button( + onClick = { navigator.push(InfoRunnerScreen(timerViewModel)) }, + modifier = Modifier + .fillMaxWidth() + .height(48.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + shape = RoundedCornerShape(15.dp) + ) { + Text("Ок", fontSize = fontSizeSecond) + } + + Spacer(modifier = Modifier.weight(1f)) + } + } + } + } + } + + @Composable + private fun ConfirmRunnerTopBar() { + val navigator = LocalNavigator.currentOrThrow + + Box { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + ) { + val fontSizeButton = (maxWidth.value / 50).sp + val fontSizeText = (maxWidth.value / 25).sp + + Row( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + + Button( + onClick = { }, + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + elevation = null, + shape = RoundedCornerShape(15.dp), + modifier = Modifier + .wrapContentWidth() + + ) { + Text( + text = "Назад", + color = Color.Black, + fontSize = fontSizeButton + ) + } + + Spacer(modifier = Modifier.width(24.dp)) + + Text( + text = "MARATHON SKILLS 2016", + style = MaterialTheme.typography.h6, + modifier = Modifier.weight(1f), + textAlign = TextAlign.Left, + fontWeight = FontWeight.Bold, + fontSize = fontSizeText, + color = Color.White + ) + + Spacer(modifier = Modifier.width(64.dp)) + + Button( + onClick = { navigator.push(MainScreen()) }, + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + elevation = null, + shape = RoundedCornerShape(15.dp), + modifier = Modifier + .wrapContentWidth() + + ) { + Text( + text = "Logout", + color = Color.Black, + fontSize = fontSizeButton + ) + } + } + } + } + } + + + @Composable + private fun ConfirmRunnerBottomBar(timerViewModel: TimerViewModel) { + val remainingTime = timerViewModel.remainingTime.collectAsState().value + Box { + BoxWithConstraints( + modifier = Modifier + .align(Alignment.Center) + ) { + val fontSize = (maxWidth.value / 50).sp + + Column( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = remainingTime, + color = Color.White, + fontSize = fontSize + ) + } + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/ConfirmSponsor.kt b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/ConfirmSponsor.kt new file mode 100644 index 0000000..d181f73 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/ConfirmSponsor.kt @@ -0,0 +1,235 @@ +package org.example.project.ui.Screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +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.sp +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import org.example.project.ViewModel.TimerViewModel + +class ConfirmSponsorScreen(private val timerViewModel: TimerViewModel, private val sumSpons: String, private val runner: String, private val blagot: String) : + Screen { + + @Composable + override fun Content() { + val navigator = LocalNavigator.currentOrThrow + + Scaffold( + topBar = { ConfirmSponsorTopBar() }, + bottomBar = { ConfirmSponsorBottomBar(timerViewModel = timerViewModel) } + ) { paddingValues -> + + Box( + modifier = Modifier.padding(paddingValues) + ) { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + .padding(horizontal = 100.dp) + ) { + val fontSize = (maxWidth.value / 60).sp + val fontSizeFirst = (maxWidth.value / 30).sp + val fontSizeSecond = (maxWidth.value / 40).sp + val fontSizeThird = (maxWidth.value / 50).sp + val fontSizeFourth = (maxWidth.value / 10).sp + val fontSizeFiveth = (maxWidth.value / 20).sp + + Column( + modifier = Modifier + .fillMaxWidth().padding(bottom = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "Спасибо за вашу спонсорскую поддержку!", + color = Color.Gray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "Спасибо за поддержку бегуна в Marathon Skills 2016! Ваше пожертвование пойдёт в его благотворительную организацию", + color = Color.Black, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = runner, + color = Color.Black, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = blagot, + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFiveth, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = sumSpons, + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFourth, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Button( + onClick = { navigator.push(MainScreen()) }, + modifier = Modifier + .fillMaxWidth() + .height(48.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + shape = RoundedCornerShape(15.dp) + ) { + Text("Назад", fontSize = fontSizeSecond) + } + } + } + } + } + } + + @Composable + private fun ConfirmSponsorTopBar() { + val navigator = LocalNavigator.currentOrThrow + + Box { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + ) { + val fontSizeButton = (maxWidth.value / 50).sp + val fontSizeText = (maxWidth.value / 25).sp + + Row( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + + Button( + onClick = { }, + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + elevation = null, + shape = RoundedCornerShape(15.dp), + modifier = Modifier + .wrapContentWidth() + + ) { + Text( + text = "Назад", + color = Color.Black, + fontSize = fontSizeButton + ) + } + + Spacer(modifier = Modifier.width(24.dp)) + + Text( + text = "MARATHON SKILLS 2016", + style = MaterialTheme.typography.h6, + modifier = Modifier.weight(1f), + textAlign = TextAlign.Left, + fontWeight = FontWeight.Bold, + fontSize = fontSizeText, + color = Color.White + ) + } + } + } + } + + + + @Composable + private fun ConfirmSponsorBottomBar(timerViewModel: TimerViewModel) { + val remainingTime = timerViewModel.remainingTime.collectAsState().value + Box { + BoxWithConstraints( + modifier = Modifier + .align(Alignment.Center) + ) { + val fontSize = (maxWidth.value / 50).sp + + Column( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = remainingTime, + color = Color.White, + fontSize = fontSize + ) + } + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/ForSponsor.kt b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/ForSponsor.kt new file mode 100644 index 0000000..f9ab453 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/ForSponsor.kt @@ -0,0 +1,464 @@ +package org.example.project.ui.Screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.DateRange +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +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.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import org.example.project.ViewModel.FieldWithDropdown +import org.example.project.ViewModel.FieldWithLabel +import org.example.project.ViewModel.TimerViewModel + +class ForSponsorScreen(private val timerViewModel: TimerViewModel) : Screen { + + @Composable + override fun Content() { + val navigator = LocalNavigator.currentOrThrow + + Scaffold( + topBar = { ForSponsorTopBar() }, + bottomBar = { ForSposnorBottomBar(timerViewModel = timerViewModel) } + ) { paddingValues -> + + Box( + modifier = Modifier.padding(paddingValues) + ) { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + .padding(horizontal = 100.dp) + ) { + val fontSize = (maxWidth.value / 60).sp + val fontSizeFirst = (maxWidth.value / 30).sp + val fontSizeSecond = (maxWidth.value / 40).sp + val fontSizeThird = (maxWidth.value / 50).sp + val fontSizeFourth = (maxWidth.value / 10).sp + val labelWidth = 0.5f + var fio by remember { mutableStateOf("") } + val runners = listOf( + "bob", + "bobby", + "baby" + ) + var runner by remember { mutableStateOf("") } + var cardName by remember { mutableStateOf("") } + var cardNum by remember { mutableStateOf("") } + var srokM by remember { mutableStateOf("") } + var srokY by remember { mutableStateOf("") } + var cvc by remember { mutableStateOf("") } + var sumChangStr by remember { mutableStateOf("10")} + var sumChang by remember { mutableStateOf(sumChangStr.toInt()) } + var sumSpons by remember { mutableStateOf(0)} + + Column( + modifier = Modifier + .fillMaxWidth().padding(bottom = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = "Спонсор бегуна", + color = Color.DarkGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(Modifier.weight(0.1f)) + + Text( + text = "Пожалуйста выберите бегуна, которого вы хотели бы спонсировать и сумму, которую вы хотели бы спонсировать. Спасибо за вашу поддержку бегунов и их благотворительных учреждений.", + color = Color.DarkGray, + textAlign = TextAlign.Center, + fontSize = fontSizeSecond, + modifier = Modifier.fillMaxWidth(), + ) + + Spacer(Modifier.weight(0.2f)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + Column(modifier = Modifier.weight(1f),) { + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "Информация о спонсоре", + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + FieldWithLabel( + label = "Ваше имя:", + value = fio, + onValueChange = { fio = it }, + placeholder = "Ваше имя", + fontSize = fontSizeSecond, + labelWidth = labelWidth, + ) + + Spacer(modifier = Modifier.weight(0.1f)) + + FieldWithDropdown( + label = "Бегун:", + options = runners, + selectedOption = runner, + onOptionSelected = { runner = it }, + fontSize = fontSizeSecond, + labelWidth = labelWidth + ) + + Spacer(modifier = Modifier.weight(0.1f)) + + FieldWithLabel( + label = "Карта:", + value = cardName, + onValueChange = { cardName = it }, + placeholder = "Владелец карты", + fontSize = fontSizeSecond, + labelWidth = labelWidth, + ) + + Spacer(modifier = Modifier.weight(0.1f)) + + FieldWithLabel( + label = "Номер карты#:", + value = cardNum, + onValueChange = { cardNum = it }, + placeholder = "...", + fontSize = fontSizeSecond, + labelWidth = labelWidth, + ) + + Spacer(modifier = Modifier.weight(0.1f)) + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = "Срок действия:", + fontSize = fontSizeSecond, + color = Color.Black, + modifier = Modifier.weight(labelWidth) + ) + + OutlinedTextField( + value = srokM, + onValueChange = { srokM = it }, + placeholder = { Text("MM", fontSize = fontSizeSecond) }, + textStyle = androidx.compose.ui.text.TextStyle( + fontSize = fontSizeSecond, + color = Color.Black + ), + modifier = Modifier + .weight((1f - labelWidth) / 2) + .padding(end = 4.dp), + singleLine = true + ) + + OutlinedTextField( + value = srokY, + onValueChange = { srokY = it }, + placeholder = { Text("YY", fontSize = fontSizeSecond) }, + textStyle = androidx.compose.ui.text.TextStyle( + fontSize = fontSizeSecond, + color = Color.Black + ), + modifier = Modifier + .weight((1f - labelWidth) / 2) + .padding(start = 4.dp), + singleLine = true + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + FieldWithLabel( + label = "CVC:", + value = cvc, + onValueChange = { cvc = it }, + placeholder = "...", + fontSize = fontSizeSecond, + labelWidth = labelWidth, + ) + } + + Column(modifier = Modifier.weight(1f),) { + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "Благотворительность", + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "blagot...", + color = Color.Black, + textAlign = TextAlign.Center, + fontSize = fontSizeSecond, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.5f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "Сумма пожертвования", + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "$" + sumSpons.toString(), + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFourth, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + Button( + modifier = Modifier + .weight(0.2f) + .aspectRatio(1f), + onClick = { + sumSpons -= sumChang + }, + shape = RoundedCornerShape(8.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + ) { + Text("-", fontSize = fontSizeSecond) + } + + OutlinedTextField( + value = sumChangStr, + onValueChange = { + sumChangStr = it + sumChang = it.toIntOrNull() ?: 0 + }, + placeholder = { Text("...", fontSize = fontSizeSecond) }, + textStyle = androidx.compose.ui.text.TextStyle( + fontSize = fontSizeSecond, + color = Color.Black, + textAlign = TextAlign.Center + ), + modifier = Modifier + .weight(0.6f) + .padding(horizontal = 4.dp), + singleLine = true + ) + + Button( + modifier = Modifier + .weight(0.2f) + .aspectRatio(1f), + onClick = { + sumSpons += sumChang + }, + shape = RoundedCornerShape(8.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + ) { + Text("+", fontSize = fontSizeSecond) + } + } + + Spacer(modifier = Modifier.weight(0.5f)) + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceEvenly, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + Button( + onClick = { navigator.push(ConfirmSponsorScreen(timerViewModel, sumSpons.toString(), runner, "blagodat..."))}, + modifier = Modifier.weight(1f), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + shape = RoundedCornerShape(15.dp) + ) { + Text("Заплатить", fontSize = fontSizeThird) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Button( + onClick = { navigator.push(MainScreen()) }, + modifier = Modifier.weight(1f), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + shape = RoundedCornerShape(15.dp) + ) { + Text("Отмена", fontSize = fontSizeThird) + } + } + } + } + } + } + } + } + } + + @Composable + private fun ForSponsorTopBar() { + val navigator = LocalNavigator.currentOrThrow + + Box { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + ) { + val fontSizeButton = (maxWidth.value / 50).sp + val fontSizeText = (maxWidth.value / 25).sp + + Row( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + + Button( + onClick = { }, + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + elevation = null, + shape = RoundedCornerShape(15.dp), + modifier = Modifier + .wrapContentWidth() + + ) { + Text( + text = "Назад", + color = Color.Black, + fontSize = fontSizeButton + ) + } + + Spacer(modifier = Modifier.width(24.dp)) + + Text( + text = "MARATHON SKILLS 2016", + style = MaterialTheme.typography.h6, + modifier = Modifier.weight(1f), + textAlign = TextAlign.Left, + fontWeight = FontWeight.Bold, + fontSize = fontSizeText, + color = Color.White + ) + } + } + } + } + + + + @Composable + private fun ForSposnorBottomBar(timerViewModel: TimerViewModel) { + val remainingTime = timerViewModel.remainingTime.collectAsState().value + Box { + BoxWithConstraints( + modifier = Modifier + .align(Alignment.Center) + ) { + val fontSize = (maxWidth.value / 50).sp + + Column( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = remainingTime, + color = Color.White, + fontSize = fontSize + ) + } + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/InfoRunner.kt b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/InfoRunner.kt new file mode 100644 index 0000000..92aa58a --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/InfoRunner.kt @@ -0,0 +1,234 @@ +package org.example.project.ui.Screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import org.example.project.ViewModel.TimerViewModel + + +class InfoRunnerScreen(private val timerViewModel: TimerViewModel) : Screen { + + @Composable + override fun Content() { + val navigator = LocalNavigator.currentOrThrow + + Scaffold( + topBar = { InfoRunnerTopBar() }, + bottomBar = { InfoRunnerBottomBar(timerViewModel = timerViewModel) } + ) { paddingValues -> + + Box( + modifier = Modifier + .padding(paddingValues) + ) { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + .padding(horizontal = 100.dp) + ) { + val fontSize = (maxWidth.value / 25).sp + val fontSizeButton = (maxWidth.value / 40).sp + + Column( + modifier = Modifier + .padding(16.dp) + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = "Подробная информация", + color = Color.DarkGray, + textAlign = TextAlign.Center, + fontSize = fontSize, + ) + + Row( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + horizontalArrangement = Arrangement.SpaceEvenly, + verticalAlignment = Alignment.CenterVertically + ) { + Column( + modifier = Modifier + .weight(1f) + .padding(end = 8.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + InfoButton("Регистрация на марафон", fontSizeButton) + InfoButton("Редактирование профиля", fontSizeButton) + InfoButton("Контакты", fontSizeButton) + } + + Column( + modifier = Modifier + .weight(1f) + .padding(start = 8.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + InfoButton("Мои результаты", fontSizeButton) + InfoButton("Мои спонсоры", fontSizeButton) + } + } + } + } + } + } + } + + @Composable + private fun InfoButton(text: String, fontSize: TextUnit) { + Button( + onClick = { }, + modifier = Modifier + .fillMaxWidth() + .height(80.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + shape = RoundedCornerShape(15.dp) + ) { + Text(text = text, fontStyle = FontStyle.Italic, fontSize = fontSize, textAlign = TextAlign.Center) + } + } + + @Composable + private fun InfoRunnerTopBar() { + val navigator = LocalNavigator.currentOrThrow + + Box { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + ) { + val fontSizeButton = (maxWidth.value / 50).sp + val fontSizeText = (maxWidth.value / 25).sp + + Row( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + + Button( + onClick = { navigator.push(MainScreen()) }, + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + elevation = null, + shape = RoundedCornerShape(15.dp), + modifier = Modifier + .wrapContentWidth() + + ) { + Text( + text = "Назад", + color = Color.Black, + fontSize = fontSizeButton + ) + } + + Spacer(modifier = Modifier.width(24.dp)) + + Text( + text = "MARATHON SKILLS 2016", + style = MaterialTheme.typography.h6, + modifier = Modifier.weight(1f), + textAlign = TextAlign.Left, + fontWeight = FontWeight.Bold, + fontSize = fontSizeText, + color = Color.White + ) + + Spacer(modifier = Modifier.width(64.dp)) + + Button( + onClick = { navigator.push(MainScreen()) }, + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + elevation = null, + shape = RoundedCornerShape(15.dp), + modifier = Modifier + .wrapContentWidth() + + ) { + Text( + text = "Logout", + color = Color.Black, + fontSize = fontSizeButton + ) + } + } + } + } + } + + @Composable + private fun InfoRunnerBottomBar(timerViewModel: TimerViewModel) { + val remainingTime = timerViewModel.remainingTime.collectAsState().value + Box { + BoxWithConstraints( + modifier = Modifier + .align(Alignment.Center) + ) { + val fontSize = (maxWidth.value / 50).sp + + Column( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = remainingTime, + color = Color.White, + fontSize = fontSize + ) + } + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/Login.kt b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/Login.kt index a01febf..4c78cb1 100644 --- a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/Login.kt +++ b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/Login.kt @@ -38,6 +38,7 @@ import androidx.compose.ui.unit.sp import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow +import org.example.project.ViewModel.FieldWithLabel import org.example.project.ViewModel.TimerViewModel class LoginScreen(private val timerViewModel: TimerViewModel) : Screen { @@ -63,7 +64,7 @@ class LoginScreen(private val timerViewModel: TimerViewModel) : Screen { val fontSize = (maxWidth.value / 25).sp val fontSizeFirst = (maxWidth.value / 20).sp val fontSizeSecond = (maxWidth.value / 35).sp - val labelWidth = 120.dp + val labelWidth = 0.25f var email by remember { mutableStateOf("") } var password by remember { mutableStateOf("") } @@ -94,69 +95,25 @@ class LoginScreen(private val timerViewModel: TimerViewModel) : Screen { Spacer(Modifier.weight(0.25f)) - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center, - modifier = Modifier.fillMaxWidth() - ) { - Box(modifier = Modifier.width(labelWidth)) { - Text( - text = "Email:", - color = Color.DarkGray, - textAlign = TextAlign.Start, - fontSize = fontSize, - modifier = Modifier.padding(start = 40.dp), - ) - } - - TextField( - value = email, - onValueChange = { email = it }, - placeholder = { - Text( - text = "Enter your email address", - fontSize = fontSize, - color = Color.LightGray - ) - }, - textStyle = androidx.compose.ui.text.TextStyle( - fontSize = fontSize - ), - modifier = Modifier - .weight(1f) - ) - } + FieldWithLabel( + label = "Email:", + value = email, + onValueChange = { email = it }, + placeholder = "Enter your email address", + fontSize = fontSize, + labelWidth = labelWidth, + ) Spacer(Modifier.weight(0.25f)) - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center, - modifier = Modifier.fillMaxWidth() - ) { - Box(modifier = Modifier.width(labelWidth)) { - Text( - text = "Password:", - color = Color.DarkGray, - textAlign = TextAlign.Start, - fontSize = fontSize, - ) - } - - TextField( - value = password, - onValueChange = { password = it }, - placeholder = { - Text( - text = "Enter your password", - fontSize = fontSize, - color = Color.LightGray - ) - }, - modifier = Modifier - .weight(1f) - ) - } + FieldWithLabel( + label = "Password:", + value = password, + onValueChange = { password = it }, + placeholder = "Enter your password", + fontSize = fontSize, + labelWidth = labelWidth, + ) Spacer(Modifier.weight(0.25f)) @@ -165,7 +122,7 @@ class LoginScreen(private val timerViewModel: TimerViewModel) : Screen { horizontalArrangement = Arrangement.Center ) { Button( - onClick = { }, + onClick = { navigator.push(InfoRunnerScreen(timerViewModel))}, modifier = Modifier .fillMaxWidth() .weight(1f), @@ -184,7 +141,7 @@ class LoginScreen(private val timerViewModel: TimerViewModel) : Screen { Spacer(Modifier.weight(0.25f)) Button( - onClick = { }, + onClick = { navigator.push(MainScreen()) }, modifier = Modifier .fillMaxWidth() .weight(1f), diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/MainScreen.kt b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/MainScreen.kt index ab7aeac..27db258 100644 --- a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/MainScreen.kt +++ b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/MainScreen.kt @@ -65,7 +65,7 @@ class MainScreen : Screen { Spacer(modifier = Modifier.height(16.dp)) Button( - onClick = { }, + onClick = { navigator.push(ForSponsorScreen(timerViewModel))}, modifier = Modifier .fillMaxWidth() .weight(1f), diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/RegMaraphon.kt b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/RegMaraphon.kt new file mode 100644 index 0000000..ffe27c4 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/RegMaraphon.kt @@ -0,0 +1,415 @@ +package org.example.project.ui.Screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Checkbox +import androidx.compose.material.MaterialTheme +import androidx.compose.material.RadioButton +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +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.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import org.example.project.ViewModel.FieldWithDropdown +import org.example.project.ViewModel.FieldWithLabel +import org.example.project.ViewModel.FieldWithLabelInt +import org.example.project.ViewModel.TimerViewModel + +class RegMaraphonScreen(private val timerViewModel: TimerViewModel) : Screen { + + @Composable + override fun Content() { + val navigator = LocalNavigator.currentOrThrow + + Scaffold( + topBar = { RegMaraphonTopBar() }, + bottomBar = { RegMaraphonBottomBar(timerViewModel = timerViewModel) } + ) { paddingValues -> + + Box( + modifier = Modifier.padding(paddingValues) + ) { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + .padding(horizontal = 100.dp) + ) { + val fontSize = (maxWidth.value / 60).sp + val fontSizeFirst = (maxWidth.value / 30).sp + val fontSizeSecond = (maxWidth.value / 40).sp + val fontSizeThird = (maxWidth.value / 50).sp + val fontSizeFourth = (maxWidth.value / 10).sp + var finalSum by remember { mutableStateOf(0) } + var previousAddonPrice by remember { mutableStateOf(0) } + var checked1 by remember { mutableStateOf(false) } + var checked2 by remember { mutableStateOf(false) } + var checked3 by remember { mutableStateOf(false) } + val options = listOf( + "Вариант А($0): Номер бегуна + RFID браслет", + "Вариант B($20): вариант A + бейсболка + бутылка воды", + "Вариант C($45): Вариант B + футболка + сувенирный буклет" + ) + var blagi = listOf( + "Что-то", + "Ещё что-то" + ) + var selectedOption by remember { mutableStateOf(options[0]) } + var vznos by remember { mutableStateOf("")} + var sumVznos by remember { mutableStateOf(0)} + + Column( + modifier = Modifier + .fillMaxWidth().padding(bottom = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = "Регистрация на марафон", + color = Color.DarkGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(Modifier.weight(0.1f)) + + Text( + text = "Пожалуйста, заполните всю информацию, чтобы зарегестрироваться на Skills Marathon 2016 проводимом в Москве. Russia. С вами свяжутся после регистрации для уточнения оплаты и другой информации.", + color = Color.DarkGray, + textAlign = TextAlign.Center, + fontSize = fontSizeSecond, + modifier = Modifier.fillMaxWidth(), + ) + + Spacer(Modifier.weight(0.2f)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + Column(modifier = Modifier.weight(1f), ) { + Spacer(modifier = Modifier.weight(0.1f)) + + Text( + text = "Вид марафона", + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier + ) + + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox( + checked = checked1, + onCheckedChange = { isChecked -> + checked1 = isChecked + if (isChecked) { + finalSum += 145 + } else { + finalSum -= 145 + } + } + ) + Spacer(modifier = Modifier.width(8.dp)) + Text(text = "42km Полный марафон($145)", fontSize = fontSizeSecond) + } + + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox( + checked = checked2, + onCheckedChange = { isChecked -> + checked2 = isChecked + if (isChecked) { + finalSum += 75 + } else { + finalSum -= 75 + } + } + ) + Spacer(modifier = Modifier.width(8.dp)) + Text(text = "21km Поулмарафон($75)", fontSize = fontSizeSecond) + } + + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox( + checked = checked3, + onCheckedChange = { isChecked -> + checked3 = isChecked + if (isChecked) { + finalSum += 20 + } else { + finalSum -= 20 + } + } + ) + Spacer(modifier = Modifier.width(8.dp)) + Text(text = "5km Малая дистанция($20)", fontSize = fontSizeSecond) + } + + Text( + text = "Детали спонсорства", + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier + ) + + FieldWithDropdown( + label = "Взнос:", + options = blagi, + selectedOption = vznos, + onOptionSelected = { vznos = it }, + fontSize = fontSizeSecond, + labelWidth = 0.5f + ) + + Spacer(modifier = Modifier.weight(0.1f)) + + FieldWithLabelInt( + label = "Сумма взноса:", + value = sumVznos, + onValueChange = { sumVznos = it }, + placeholder = "$$$", + fontSize = fontSizeSecond, + labelWidth = 0.5f, + ) + + Spacer(modifier = Modifier.weight(0.1f)) + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceEvenly, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + Button( + onClick = { navigator.push(ConfirmRunnerScreen(timerViewModel))}, + modifier = Modifier.weight(1f), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + shape = RoundedCornerShape(15.dp) + ) { + Text("Регистрация", fontSize = fontSizeThird) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Button( + onClick = { navigator.push(MainScreen()) }, + modifier = Modifier.weight(1f), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + shape = RoundedCornerShape(15.dp) + ) { + Text("Отмена", fontSize = fontSizeThird) + } + } + } + + Column(modifier = Modifier.weight(1f)) { + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "Варианты комплектов", + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.align(Alignment.Center) + ) + } + + options.forEach { text -> + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + RadioButton( + selected = (text == selectedOption), + onClick = { + val newAddonPrice = when (text) { + options[0] -> 0 + options[1] -> 20 + options[2] -> 45 + else -> 0 + } + + finalSum = finalSum - previousAddonPrice + newAddonPrice + + previousAddonPrice = newAddonPrice + selectedOption = text + } + ) + Spacer(modifier = Modifier.weight(0.01f)) + Text(text = text, fontSize = fontSizeSecond) + } + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "Регистрационный взнос", + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFirst, + modifier = Modifier.align(Alignment.Center) + ) + } + + Spacer(modifier = Modifier.weight(0.1f)) + + Box(modifier = Modifier.fillMaxWidth()) { + Text( + text = "$" + finalSum.toString(), + color = Color.LightGray, + textAlign = TextAlign.Center, + fontSize = fontSizeFourth, + modifier = Modifier.align(Alignment.Center) + ) + } + } + } + } + } + } + } + } + + @Composable + private fun RegMaraphonTopBar() { + val navigator = LocalNavigator.currentOrThrow + + Box { + BoxWithConstraints( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Center) + ) { + val fontSizeButton = (maxWidth.value / 50).sp + val fontSizeText = (maxWidth.value / 25).sp + + Row( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + + Button( + onClick = { }, + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + elevation = null, + shape = RoundedCornerShape(15.dp), + modifier = Modifier + .wrapContentWidth() + + ) { + Text( + text = "Назад", + color = Color.Black, + fontSize = fontSizeButton + ) + } + + Spacer(modifier = Modifier.width(24.dp)) + + Text( + text = "MARATHON SKILLS 2016", + style = MaterialTheme.typography.h6, + modifier = Modifier.weight(1f), + textAlign = TextAlign.Left, + fontWeight = FontWeight.Bold, + fontSize = fontSizeText, + color = Color.White + ) + + Spacer(modifier = Modifier.width(64.dp)) + + Button( + onClick = { navigator.push(MainScreen()) }, + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + elevation = null, + shape = RoundedCornerShape(15.dp), + modifier = Modifier + .wrapContentWidth() + + ) { + Text( + text = "Logout", + color = Color.Black, + fontSize = fontSizeButton + ) + } + } + } + } + } + + + + @Composable + private fun RegMaraphonBottomBar(timerViewModel: TimerViewModel) { + val remainingTime = timerViewModel.remainingTime.collectAsState().value + Box { + BoxWithConstraints( + modifier = Modifier + .align(Alignment.Center) + ) { + val fontSize = (maxWidth.value / 50).sp + + Column( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = remainingTime, + color = Color.White, + fontSize = fontSize + ) + } + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/RegRunner.kt b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/RegRunner.kt index 71a6a5e..52dfe42 100644 --- a/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/RegRunner.kt +++ b/composeApp/src/commonMain/kotlin/org/example/project/ui/Screens/RegRunner.kt @@ -1,23 +1,40 @@ package org.example.project.ui.Screens import androidx.compose.foundation.background +import androidx.compose.foundation.Image +import androidx.compose.ui.res.painterResource +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon +import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme +import androidx.compose.material.OutlinedTextField import androidx.compose.material.Scaffold import androidx.compose.material.Text import androidx.compose.material.TextField +import androidx.compose.material.contentColorFor +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.filled.DateRange import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -26,6 +43,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue 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.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -36,6 +54,11 @@ import androidx.compose.ui.unit.sp import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow +import org.example.project.ViewModel.DatePickerField +import org.example.project.ViewModel.FieldWithDropdown +import org.example.project.ViewModel.FieldWithLabel +import org.example.project.ViewModel.GetPath +import org.example.project.ViewModel.ImageFromPath import org.example.project.ViewModel.TimerViewModel class RegRunnerScreen(private val timerViewModel: TimerViewModel) : Screen { @@ -46,31 +69,53 @@ class RegRunnerScreen(private val timerViewModel: TimerViewModel) : Screen { Scaffold( topBar = { RegRunnerTopBar() }, - bottomBar = { RegRunnerBottomBar(timerViewModel = timerViewModel) } + bottomBar = { BottomSection(timerViewModel = timerViewModel) } ) { paddingValues -> Box( - modifier = Modifier.padding(paddingValues) + modifier = Modifier.padding(paddingValues).fillMaxSize() ) { BoxWithConstraints( modifier = Modifier .fillMaxWidth() .align(Alignment.Center) - .padding(horizontal = 100.dp) + .padding(horizontal = 10.dp) ) { - val fontSize = (maxWidth.value / 25).sp - val fontSizeFirst = (maxWidth.value / 20).sp - val fontSizeSecond = (maxWidth.value / 35).sp - val labelWidth = 120.dp + val fontSize = (maxWidth.value / 60).sp + val fontSizeFirst = (maxWidth.value / 30).sp + val fontSizeSecond = (maxWidth.value / 40).sp + val labelWidth = 0.5f var email by remember { mutableStateOf("") } var password by remember { mutableStateOf("") } + var secondPassword by remember { mutableStateOf("") } + var name by remember { mutableStateOf("") } + var surname by remember { mutableStateOf("") } + var gender by remember { mutableStateOf("") } + var country by remember { mutableStateOf("") } + var photoPath by remember { mutableStateOf("") } + var openPicker by remember { mutableStateOf(false) } + if (openPicker) { + GetPath { selected -> + photoPath = selected + openPicker = false + } + } + var showDatePicker by remember { mutableStateOf(false) } + var dateBirthday by remember { mutableStateOf("") } + if (showDatePicker) { + DatePickerField( + onDateSelected = { + dateBirthday = it + }, + trigger = true, + onDismissRequest = { showDatePicker = false } + ) + } Column( modifier = Modifier - .fillMaxWidth(), + .fillMaxWidth().padding(bottom = 16.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { - Spacer(Modifier.weight(0.25f)) - Text( text = "Регистрация бегуна", color = Color.DarkGray, @@ -79,7 +124,7 @@ class RegRunnerScreen(private val timerViewModel: TimerViewModel) : Screen { modifier = Modifier.fillMaxWidth() ) - Spacer(Modifier.weight(0.25f)) + Spacer(Modifier.weight(0.1f)) Text( text = "Пожалуйста, заполните всю информацию, чтобы зарегестрироваться в качестве участника", @@ -93,50 +138,224 @@ class RegRunnerScreen(private val timerViewModel: TimerViewModel) : Screen { Row( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(32.dp) + horizontalArrangement = Arrangement.spacedBy(16.dp) ) { - Column(modifier = Modifier.weight(1f)) { + Column(modifier = Modifier.weight(0.8f)) { + Spacer(modifier = Modifier.weight(0.1f)) + FieldWithLabel( label = "Email:", value = email, onValueChange = { email = it }, - placeholder = "Enter your email address", + placeholder = "Email", fontSize = fontSize, - labelWidth = labelWidth + labelWidth = labelWidth, ) Spacer(modifier = Modifier.weight(0.1f)) FieldWithLabel( - label = "Password:", + label = "Пароль:", value = password, onValueChange = { password = it }, - placeholder = "Enter your password", + placeholder = "Пароль", + fontSize = fontSize, + labelWidth = labelWidth, + ) + + Spacer(modifier = Modifier.weight(0.1f)) + + FieldWithLabel( + label = "Повторите пароль:", + value = secondPassword, + onValueChange = { secondPassword = it }, + placeholder = "Повторите пароль", + fontSize = fontSize, + labelWidth = labelWidth, + ) + + Spacer(modifier = Modifier.weight(0.1f)) + + FieldWithLabel( + label = "Имя:", + value = name, + onValueChange = { name = it }, + placeholder = "Имя", + fontSize = fontSize, + labelWidth = labelWidth, + ) + + Spacer(modifier = Modifier.weight(0.1f)) + + FieldWithLabel( + label = "Фамилия:", + value = surname, + onValueChange = { surname = it }, + placeholder = "Фамилия", + fontSize = fontSize, + labelWidth = labelWidth, + ) + + Spacer(modifier = Modifier.weight(0.1f)) + + FieldWithDropdown( + label = "Пол:", + options = listOf("Мужской", "Остальное"), + selectedOption = gender, + onOptionSelected = { gender = it }, fontSize = fontSize, labelWidth = labelWidth ) } Column(modifier = Modifier.weight(1f)) { - FieldWithLabel( - label = "Email:", - value = email, - onValueChange = { email = it }, - placeholder = "Enter your email address", - fontSize = fontSize, - labelWidth = labelWidth + ImageFromPath( + path = photoPath, + modifier = Modifier + .weight(0.4f) + .clip(RoundedCornerShape(8.dp)) + .border(1.dp, Color.Gray, RoundedCornerShape(8.dp)).align(Alignment.End) ) - Spacer(modifier = Modifier.weight(0.1f)) + Spacer(modifier = Modifier.weight(0.05f)) - FieldWithLabel( - label = "Password:", - value = password, - onValueChange = { password = it }, - placeholder = "Enter your password", - fontSize = fontSize, - labelWidth = labelWidth - ) + Column(modifier = Modifier.weight(0.3f)) { + Text( + text = "Фото файл:", + color = Color.DarkGray, + textAlign = TextAlign.Start, + fontSize = fontSize, + modifier = Modifier + ) + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxWidth() + ) { + + OutlinedTextField( + value = photoPath, + onValueChange = {photoPath = it}, + placeholder = { + Text( + text = "Photo_logo.jpg", + fontSize = fontSize, + color = Color.LightGray + ) + }, + textStyle = androidx.compose.ui.text.TextStyle( + fontSize = fontSize, + color = Color.Black + ), + enabled = true, + colors = androidx.compose.material.TextFieldDefaults.outlinedTextFieldColors( + backgroundColor = Color.White, + cursorColor = Color.Black, + textColor = Color.Black, + placeholderColor = Color.LightGray, + focusedBorderColor = Color(0xFFCCCCCC), + unfocusedBorderColor = Color(0xFFCCCCCC), + disabledBorderColor = Color(0xFFCCCCCC) + ), + modifier = Modifier.weight(0.6f).wrapContentWidth().fillMaxWidth() + ) + + Spacer(modifier = Modifier.weight(0.05f)) + + Button( + onClick = { openPicker = true}, + modifier = Modifier + .fillMaxWidth() + .weight(0.5f), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + shape = RoundedCornerShape(15.dp) + ) { + Text( + "Просмотр", + fontSize = fontSize + ) + } + } + + Spacer(modifier = Modifier.weight(0.05f)) + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, + modifier = Modifier.fillMaxWidth() + ) { + Box(modifier = Modifier.weight(labelWidth)) { + Text( + text = "Дата рождения", + color = Color.DarkGray, + textAlign = TextAlign.Start, + fontSize = fontSize, + modifier = Modifier + ) + } + + OutlinedTextField( + value = dateBirthday, + onValueChange = {dateBirthday = it}, + placeholder = { + Text( + text = "...", + fontSize = fontSize, + color = Color.LightGray + ) + }, + textStyle = androidx.compose.ui.text.TextStyle( + fontSize = fontSize, + color = Color.Black + ), + enabled = true, + colors = androidx.compose.material.TextFieldDefaults.outlinedTextFieldColors( + backgroundColor = Color.White, + cursorColor = Color.Black, + textColor = Color.Black, + placeholderColor = Color.LightGray, + focusedBorderColor = Color(0xFFCCCCCC), + unfocusedBorderColor = Color(0xFFCCCCCC), + disabledBorderColor = Color(0xFFCCCCCC) + ), + modifier = Modifier.weight(0.9f).wrapContentWidth() + ) + + Spacer(modifier = Modifier.weight(0.05f)) + + Box( + modifier = Modifier + .weight(0.5f) + .fillMaxWidth() + .clip(RoundedCornerShape(15.dp)) + .background(Color.LightGray) + .clickable { showDatePicker = true } + .padding(vertical = 8.dp), + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = Icons.Default.DateRange, + contentDescription = "Выбрать дату", + tint = Color.Black, + modifier = Modifier.size(24.dp) + ) + } + } + Spacer(modifier = Modifier.weight(0.05f)) + + FieldWithDropdown( + label = "Страна:", + options = listOf("Russia", "Other"), + selectedOption = country, + onOptionSelected = { country = it }, + fontSize = fontSize, + labelWidth = labelWidth + ) + } } } } @@ -145,48 +364,6 @@ class RegRunnerScreen(private val timerViewModel: TimerViewModel) : Screen { } } - @Composable - fun FieldWithLabel( - label: String, - value: String, - onValueChange: (String) -> Unit, - placeholder: String, - fontSize: TextUnit, - labelWidth: Dp, - enabled: Boolean = true - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth() - ) { - Box(modifier = Modifier.width(labelWidth)) { - Text( - text = label, - color = Color.DarkGray, - textAlign = TextAlign.Start, - fontSize = fontSize, - modifier = Modifier.padding(start = 40.dp), - ) - } - - TextField( - value = value, - onValueChange = onValueChange, - placeholder = { - if (placeholder.isNotEmpty()) { - Text( - text = placeholder, - fontSize = fontSize, - color = Color.LightGray - ) - } - }, - textStyle = androidx.compose.ui.text.TextStyle(fontSize = fontSize), - modifier = Modifier.weight(1f), - enabled = enabled - ) - } - } @Composable private fun RegRunnerTopBar() { @@ -250,27 +427,67 @@ class RegRunnerScreen(private val timerViewModel: TimerViewModel) : Screen { @Composable private fun RegRunnerBottomBar(timerViewModel: TimerViewModel) { val remainingTime = timerViewModel.remainingTime.collectAsState().value - Box { - BoxWithConstraints( - modifier = Modifier - .align(Alignment.Center) - ) { - val fontSize = (maxWidth.value / 50).sp - Column( - modifier = Modifier - .fillMaxWidth() - .background(Color.DarkGray) - .padding(8.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = remainingTime, - color = Color.White, - fontSize = fontSize - ) - } - } + Box( + modifier = Modifier + .fillMaxWidth() + .background(Color.DarkGray) + .padding(8.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = remainingTime, + color = Color.White, + fontSize = 16.sp + ) } } -} \ No newline at end of file + + @Composable + private fun BottomSection( + timerViewModel: TimerViewModel + ) { + val navigator = LocalNavigator.currentOrThrow + Column( + modifier = Modifier + .fillMaxWidth() + .background(Color.White) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceEvenly, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + Button( + onClick = { navigator.push(RegMaraphonScreen(timerViewModel)) }, + modifier = Modifier.weight(1f), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + shape = RoundedCornerShape(15.dp) + ) { + Text("Регистрация") + } + + Spacer(modifier = Modifier.width(16.dp)) + + Button( + onClick = { navigator.push(MainScreen()) }, + modifier = Modifier.weight(1f), + colors = ButtonDefaults.buttonColors( + backgroundColor = Color.LightGray, + contentColor = Color.Black + ), + shape = RoundedCornerShape(15.dp) + ) { + Text("Отмена") + } + } + + RegRunnerBottomBar(timerViewModel = timerViewModel) + } + } +} diff --git a/composeApp/src/desktopMain/kotlin/org/example/project/ViewModel/DatePickerField.kt b/composeApp/src/desktopMain/kotlin/org/example/project/ViewModel/DatePickerField.kt new file mode 100644 index 0000000..36155f4 --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/org/example/project/ViewModel/DatePickerField.kt @@ -0,0 +1,38 @@ +package org.example.project.ViewModel + +import androidx.compose.runtime.* +import java.text.SimpleDateFormat +import javax.swing.* +import java.util.* + +@Composable +actual fun DatePickerField( + onDateSelected: (String) -> Unit, + trigger: Boolean, + onDismissRequest: () -> Unit +) { + if (trigger) { + LaunchedEffect(Unit) { + val dialog = JDialog() + dialog.title = "Выбор даты" + val model = SpinnerDateModel() + val spinner = JSpinner(model) + val panel = JPanel() + val button = JButton("OK") + panel.add(spinner) + panel.add(button) + dialog.contentPane = panel + dialog.setSize(200, 100) + + button.addActionListener { + val date = model.date + val formatted = SimpleDateFormat("dd.MM.yyyy").format(date) + onDateSelected(formatted) + dialog.dispose() + onDismissRequest() + } + + dialog.isVisible = true + } + } +} \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/org/example/project/ViewModel/GetPath.kt b/composeApp/src/desktopMain/kotlin/org/example/project/ViewModel/GetPath.kt new file mode 100644 index 0000000..9880649 --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/org/example/project/ViewModel/GetPath.kt @@ -0,0 +1,29 @@ +package org.example.project.ViewModel + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import java.io.File +import javax.swing.JFileChooser + +@Composable +actual fun GetPath(onPathSelected: (String) -> Unit) { + LaunchedEffect(Unit) { + val selectedPath = withContext(Dispatchers.IO) { + val chooser = JFileChooser() + chooser.dialogTitle = "Выберите изображение" + chooser.fileSelectionMode = JFileChooser.FILES_ONLY + + val result = chooser.showOpenDialog(null) + if (result == JFileChooser.APPROVE_OPTION) { + val file: File = chooser.selectedFile + file.absolutePath + } else { + "" + } + } + + onPathSelected(selectedPath) + } +} \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/org/example/project/ViewModel/ImageFromPath.kt b/composeApp/src/desktopMain/kotlin/org/example/project/ViewModel/ImageFromPath.kt new file mode 100644 index 0000000..e47b3fa --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/org/example/project/ViewModel/ImageFromPath.kt @@ -0,0 +1,47 @@ +package org.example.project.ViewModel + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.painter.BitmapPainter +import androidx.compose.ui.graphics.toComposeImageBitmap +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import org.jetbrains.skia.Image +import java.io.File +import java.nio.file.Files + +@Composable +actual fun ImageFromPath(path: String, modifier: Modifier) { + val imageBitmap: ImageBitmap? = try { + if (path.isBlank()) { + // Загружаем из ресурсов + val resourceStream = Thread.currentThread().contextClassLoader.getResourceAsStream("drawable/basicPhoto.png") + val bytes = resourceStream.readAllBytes() + Image.makeFromEncoded(bytes).toComposeImageBitmap() + } else { + // Загружаем с абсолютного пути + val file = File(path) + if (file.exists()) { + val bytes = Files.readAllBytes(file.toPath()) + Image.makeFromEncoded(bytes).toComposeImageBitmap() + } else null + } + } catch (e: Exception) { + println("Ошибка загрузки изображения: ${e.message}") + null + } + + if (imageBitmap != null) { + Image( + painter = BitmapPainter(imageBitmap), + contentDescription = null, + modifier = modifier, + contentScale = ContentScale.Crop + ) + } else { + Box(modifier = modifier.fillMaxSize()) + } +} \ No newline at end of file