瀏覽代碼

create profile

Bobarik31p 2 天之前
父節點
當前提交
11d2770f82

+ 2 - 1
app/build.gradle.kts

@@ -1,6 +1,7 @@
 plugins {
     alias(libs.plugins.android.application)
     alias(libs.plugins.jetbrains.kotlin.android)
+    id ("kotlinx-serialization")
 }
 
 android {
@@ -76,7 +77,7 @@ dependencies {
     implementation(libs.androidx.navigation.ui)
     implementation(libs.androidx.navigation.dynamic.features.fragment)
     implementation(libs.supabase.gotrue.kt)
-
+    implementation (libs.datetime)
 
 
 

+ 15 - 9
app/src/main/java/com/example/tasks/MainActivity.kt

@@ -1,21 +1,27 @@
 package com.example.tasks
 
 import android.os.Bundle
+import android.util.Log
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
 import androidx.activity.enableEdgeToEdge
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import com.example.tasks.components.Constants
+import com.example.tasks.model.Gender
+import com.example.tasks.model.User
 import com.example.tasks.navigation.Navigation
-import com.example.tasks.screens.SignIn
-import com.example.tasks.screens.Start
 import com.example.tasks.ui.theme.TasksTheme
 import com.example.tasks.viewModels.AuthViewModel
+import io.github.jan.supabase.postgrest.from
+import io.github.jan.supabase.postgrest.postgrest
+import io.github.jan.supabase.postgrest.query.Columns
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
 
 class MainActivity : ComponentActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {

+ 4 - 1
app/src/main/java/com/example/tasks/components/Constants.kt

@@ -3,6 +3,7 @@ package com.example.tasks.components
 import io.github.jan.supabase.createSupabaseClient
 import io.github.jan.supabase.gotrue.Auth
 import io.github.jan.supabase.postgrest.Postgrest
+import io.github.jan.supabase.postgrest.PropertyConversionMethod
 
 
 object Constants {
@@ -11,6 +12,8 @@ object Constants {
         supabaseKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNxbWV4bnRkYnhmZ3BuZmpzYWZtIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MjU1NTc3NjUsImV4cCI6MjA0MTEzMzc2NX0.KoVVxzNbQN22qweOIqsu9SCLxQAqX1R69p2R5pKxrDw"
     ) {
         install(Auth)
-        install(Postgrest)
+        install(Postgrest){
+            propertyConversionMethod = PropertyConversionMethod.SERIAL_NAME
+        }
     }
 }

+ 9 - 0
app/src/main/java/com/example/tasks/model/Gender.kt

@@ -0,0 +1,9 @@
+package com.example.tasks.model
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class Gender(
+    val id: Int,
+    val Title: String,
+)

+ 10 - 9
app/src/main/java/com/example/tasks/model/User.kt

@@ -1,16 +1,17 @@
 package com.example.tasks.model
 
+import kotlinx.serialization.SerialName
 import kotlinx.serialization.Serializable
-import java.sql.Date
-import java.util.UUID
 
 @Serializable
 data class User (
-    val id: Int,
-    val first_name: String,
-    val last_name:String,
-    val patronymic:String?,
-    val date_of_birth: Date,
-    val gender: Int,
-    val UID: UUID
+    val id: Int? = null,
+    @SerialName("created_at")
+    val created_at:String? = null,
+    val FirstName: String = "",
+    val LastName:String= "",
+    val Patronymic:String? = null,
+    val DateOfBirth: String = "",
+    val Gender: Int? = null ,
+    val UID: String = ""
 )

+ 5 - 2
app/src/main/java/com/example/tasks/navigation/Navigation.kt

@@ -1,18 +1,21 @@
 package com.example.tasks.navigation
 
+import CreateProfile
+import android.os.Build
+import androidx.annotation.RequiresApi
 import androidx.compose.runtime.Composable
 import androidx.navigation.NavType
 import androidx.navigation.compose.NavHost
 import androidx.navigation.compose.composable
 import androidx.navigation.compose.rememberNavController
 import androidx.navigation.navArgument
-import com.example.tasks.screens.CreateProfile
 import com.example.tasks.screens.EnterOTP
 import com.example.tasks.screens.Profile
 import com.example.tasks.screens.SignIn
 import com.example.tasks.screens.Start
 import com.example.tasks.viewModels.AuthViewModel
 
+@RequiresApi(Build.VERSION_CODES.O)
 @Composable
 fun Navigation(viewModel: AuthViewModel) {
     val navController = rememberNavController()
@@ -40,7 +43,7 @@ fun Navigation(viewModel: AuthViewModel) {
         }
         composable(Screen.CreateProfile.route)
         {
-            CreateProfile()
+            CreateProfile(navController,viewModel)
 
         }
         composable(Screen.Profile.route)

+ 1 - 1
app/src/main/java/com/example/tasks/navigation/Screen.kt

@@ -5,7 +5,7 @@ sealed class Screen(val route:String) {
     object Start: Screen("start")
     object SignIn:Screen("sinIn")
     object EnterOTP: Screen("enterOTP")
-    object  CreateProfile: Screen("createProfile")
+    object CreateProfile: Screen("createProfile")
     object Profile:Screen("profile")
 
     fun withArg(vararg args: String): String {

+ 479 - 6
app/src/main/java/com/example/tasks/screens/CreateProfile.kt

@@ -1,12 +1,485 @@
-package com.example.tasks.screens
-
+import android.os.Build
+import android.widget.Toast
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.BorderStroke
+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.Column
+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.offset
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.DateRange
+import androidx.compose.material.icons.filled.Face
+import androidx.compose.material.icons.filled.KeyboardArrowDown
+import androidx.compose.material.icons.filled.KeyboardArrowUp
+import androidx.compose.material.icons.filled.Person
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.Text
+import androidx.compose.material3.TextFieldDefaults
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.AbsoluteAlignment
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
+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 androidx.compose.ui.unit.toSize
+import androidx.navigation.NavController
+import com.example.tasks.model.UserState
+import com.example.tasks.navigation.Screen
+import com.example.tasks.screens.LoadingComponent
+import com.example.tasks.viewModels.AuthViewModel
+import com.vanpra.composematerialdialogs.MaterialDialog
+import com.vanpra.composematerialdialogs.datetime.date.datepicker
+import com.vanpra.composematerialdialogs.rememberMaterialDialogState
+import java.time.LocalDate
+import java.time.format.DateTimeFormatter
 
+@RequiresApi(Build.VERSION_CODES.O)
 @Composable
-fun CreateProfile() {
-    Column {
-        Text(text = "криейт профиль")
+fun CreateProfile(navController: NavController, viewModel: AuthViewModel) {
+    val context = LocalContext.current
+    val enabled = remember { mutableStateOf(true) }
+    val dateDialogState = rememberMaterialDialogState()
+    val userState by viewModel.userState
+    val flag = remember { mutableStateOf(false) }
+    val surnameFlag = remember { mutableStateOf(false) }
+    val nameFlag = remember { mutableStateOf(false) }
+    val dateOfBirthFlag = remember { mutableStateOf(false) }
+    val genderFlag = remember { mutableStateOf(false) }
+    var pickedDate by remember { mutableStateOf(LocalDate.now()) }
+    val name = remember { mutableStateOf("") }
+    val surname = remember { mutableStateOf("") }
+    val patronymic = remember { mutableStateOf("") }
+    var expanded by remember {
+        mutableStateOf(false)
+    }
+    var currentUserState by remember { mutableStateOf("") }
+    val list = listOf("Мужской", "Женский")
+    var selectedItem by remember {
+        mutableStateOf("")
+    }
+    var textFiledSize by remember {
+        mutableStateOf(Size.Zero)
+    }
+    val icon = if (expanded) {
+        Icons.Filled.KeyboardArrowUp
+    } else {
+        Icons.Filled.KeyboardArrowDown
+    }
+
+    val formattedDate by remember {
+        derivedStateOf { DateTimeFormatter.ofPattern("dd.MM.yyyy").format(pickedDate) }
+    }
+    val formattedDateFromBase by remember {
+        derivedStateOf { DateTimeFormatter.ofPattern("yyyy-MM-dd").format(pickedDate) }
+    }
+    if(!surnameFlag.value && !nameFlag.value && !dateOfBirthFlag.value && !genderFlag.value){
+        enabled.value = false
+    }
+    Spacer(modifier = Modifier.height(20.dp))
+    Box(
+        modifier = Modifier
+            .fillMaxSize()
+            .background(MaterialTheme.colorScheme.background)
+    ) {
+        Column(
+            modifier = Modifier
+                .fillMaxWidth()
+                .padding(30.dp)
+                .padding(top = 40.dp),
+            horizontalAlignment = Alignment.Start,
+            verticalArrangement = Arrangement.Center
+        ) {
+
+            Text(
+                "Создание профиля",
+                fontWeight = FontWeight.Bold,
+                fontSize = 27.sp,
+                color = MaterialTheme.colorScheme.onBackground,
+                modifier = Modifier.padding(bottom = 30.dp)
+            )
+            Spacer(modifier = Modifier.height(20.dp))
+            Column{
+                OutlinedTextField(value = surname.value,
+                    onValueChange = { it -> surname.value = it },
+                    leadingIcon = { Icon(Icons.Filled.Person, contentDescription = "Фамилия") },
+                    colors = TextFieldDefaults.colors(
+                        focusedContainerColor = Color(0XFFF5F5F9),
+                        focusedIndicatorColor = Color(0xFFEBEBEB),
+                        focusedTextColor = Color.Black,
+                        disabledIndicatorColor = Color.Transparent,
+                        unfocusedIndicatorColor = Color.Transparent,
+                        cursorColor = Color(0XFF578FFF),
+                        focusedSupportingTextColor = Color(0xFF00000)
+                    ),
+                    modifier = Modifier
+                        .fillMaxWidth(1f)
+                        .background(Color(0XFFF5F5F9))
+                        .height(height = 56.dp)
+                        .width(width = 320.dp),
+                    isError = surnameFlag.value,
+                    placeholder = {
+                        Text(
+                            modifier = Modifier.fillMaxWidth(),
+                            text = "Фамилия",
+                            fontWeight = FontWeight.Normal,
+                            fontSize = 15.sp,
+                            color = Color(0XFF939396)
+                        )
+                    }
+                )
+
+                if (surname.value.isEmpty()) {
+                    surnameFlag.value = true
+                    Text("Введите фамилию", color = Color.Red, fontSize = 10.sp)
+                }
+                else{
+                    surnameFlag.value = false
+                }
+
+            }
+            Spacer(modifier = Modifier.height(20.dp))
+            Column {
+                OutlinedTextField(value = name.value, onValueChange = { it -> name.value = it },
+                    leadingIcon = { Icon(Icons.Filled.Person, contentDescription = "Имя") },
+                    colors = TextFieldDefaults.colors(
+                        focusedContainerColor = Color(0XFFF5F5F9),
+                        focusedIndicatorColor = Color(0xFFEBEBEB),
+                        focusedTextColor = Color.Black,
+                        disabledIndicatorColor = Color.Transparent,
+                        unfocusedIndicatorColor = Color.Transparent,
+                        cursorColor = Color(0XFF578FFF),
+                        focusedSupportingTextColor = Color(0xFF00000)
+                    ),
+                    modifier = Modifier
+                        .fillMaxWidth(1f)
+                        .background(Color(0XFFF5F5F9))
+                        .height(height = 56.dp)
+                        .width(width = 320.dp),
+                    isError = nameFlag.value,
+
+                    placeholder = {
+                        Text(
+                            modifier = Modifier.fillMaxWidth(),
+                            text = "Имя",
+                            fontWeight = FontWeight.Normal,
+                            fontSize = 15.sp,
+                            color = Color(0XFF939396)
+                        )
+                    }
+                )
+
+                if (name.value.isEmpty()) {
+                    nameFlag.value = true
+                    Text("Введите имя", color = Color.Red, fontSize = 10.sp)
+                }
+                else{
+                    nameFlag.value = false
+                }
+
+            }
+            Spacer(modifier = Modifier.height(20.dp))
+            Column {
+                OutlinedTextField(value = patronymic.value,
+                    onValueChange = { it -> patronymic.value = it },
+                    leadingIcon = { Icon(Icons.Filled.Person, contentDescription = "Отчечство") },
+                    colors = TextFieldDefaults.colors(
+                        focusedContainerColor = Color(0XFFF5F5F9),
+                        focusedIndicatorColor = Color(0xFFEBEBEB),
+                        focusedTextColor = Color.Black,
+                        disabledIndicatorColor = Color.Transparent,
+                        unfocusedIndicatorColor = Color.Transparent,
+                        cursorColor = Color(0XFF578FFF),
+                        focusedSupportingTextColor = Color(0xFF00000)
+                    ),
+                    modifier = Modifier
+                        .fillMaxWidth(1f)
+                        .background(Color(0XFFF5F5F9))
+                        .height(height = 56.dp)
+                        .width(width = 320.dp),
+                    placeholder = {
+                        Text(
+                            modifier = Modifier.fillMaxWidth(),
+                            text = "Отчетсво",
+                            fontWeight = FontWeight.Normal,
+                            fontSize = 15.sp,
+                            color = Color(0XFF939396)
+                        )
+                    }
+                )
+
+
+            }
+
+            Spacer(modifier = Modifier.height(20.dp))
+
+            val padding = 10.dp
+            Column(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .align(Alignment.Start)
+                    .clip(RoundedCornerShape(10.dp))
+
+            ) {
+                Button(
+                    onClick = { dateDialogState.show() }, modifier = Modifier
+                        .fillMaxWidth(1f)
+                        .height(height = 56.dp)
+                        .width(width = 320.dp),
+                    shape = RoundedCornerShape(size = 10.dp),
+                    border = if (dateOfBirthFlag.value) {
+                        BorderStroke(1.dp, Color.Red)
+                    } else {
+                        BorderStroke(0.dp, Color.Transparent)
+                    },
+                    colors = ButtonDefaults.buttonColors(
+                        containerColor = Color(0XFFF5F5F9),
+                        contentColor = Color(0XFF40484d)
+                    )
+                ) {
+                    Icon(
+                        Icons.Filled.DateRange,
+                        contentDescription = "Дата рождения",
+                        modifier = Modifier
+                            .offset(x = -padding)
+                            .padding(end = 2.dp)
+                    )
+                    if (pickedDate == LocalDate.now()) {
+                        Text(
+                            "Дата рождения",
+                            fontSize = 15.sp,
+                            fontWeight = FontWeight.Normal,
+                            color = Color(0XFF939396),
+                            modifier = Modifier.fillMaxWidth(),
+                            textAlign = TextAlign.Start
+                        )
+                    } else {
+                        Text(
+                            formattedDate.toString(),
+                            fontSize = 15.sp,
+                            fontWeight = FontWeight.Normal,
+                            color = Color.Black,
+                            modifier = Modifier.fillMaxWidth(),
+                            textAlign = TextAlign.Start
+                        )
+                    }
+
+                }
+                if (pickedDate == LocalDate.now()) {
+                    dateOfBirthFlag.value = true
+                    Text("Введите дату рождения", color = Color.Red, fontSize = 10.sp)
+                }
+                else{
+                    dateOfBirthFlag.value = false
+                }
+
+            }
+            Spacer(modifier = Modifier.height(20.dp))
+
+            Column(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .clip(RoundedCornerShape(10.dp))
+
+            ) {
+
+                OutlinedTextField(value = selectedItem,
+                    onValueChange = {
+                        selectedItem = it
+                    },
+                    leadingIcon = {
+                        Icon(
+                            Icons.Filled.Face,
+                            contentDescription = "Пол"
+                        )
+                    },
+                    enabled = false,
+                    colors = TextFieldDefaults.colors(
+                        focusedContainerColor = Color(0XFFF5F5F9),
+                        focusedIndicatorColor = Color(0xFFEBEBEB),
+                        focusedTextColor = Color(0XFF578FFF),
+                        disabledIndicatorColor = Color.Transparent,
+                        unfocusedIndicatorColor = Color.Transparent,
+                        cursorColor = Color(0XFF578FFF),
+                        focusedSupportingTextColor = Color(0xFF00000)
+                    ),
+                    modifier = Modifier
+                        .fillMaxWidth(1f)
+                        .background(Color(0XFFF5F5F9))
+                        .height(height = 56.dp)
+                        .width(width = 320.dp)
+                        .clickable { expanded = !expanded }
+                        .onGloballyPositioned { coordinates ->
+                            textFiledSize = coordinates.size.toSize()
+                        },
+                    isError = genderFlag.value,
+                    trailingIcon = {
+                        Icon(
+                            icon,
+                            contentDescription = "")
+                    },
+                    placeholder = {
+                        Text(
+                            modifier = Modifier.fillMaxWidth(),
+                            text = "Пол",
+                            fontWeight = FontWeight.Normal,
+                            fontSize = 15.sp,
+                            color = Color(0XFF939396)
+                        )
+                    }
+                )
+
+
+                DropdownMenu(
+                    expanded = expanded,
+                    onDismissRequest = { expanded = false },
+                    modifier = Modifier
+                        .width(with(LocalDensity.current) { textFiledSize.width.toDp() })
+                        .background(Color(0XFFF5F5F9))
+                ) {
+                    list.forEach { label ->
+                        DropdownMenuItem(text = {
+                            Text(
+                                text = label,
+                                fontSize = 15.sp,
+                                fontWeight = FontWeight.Normal
+                            )
+                        }, onClick = {
+                            selectedItem = label
+                            expanded = false
+
+                        })
+                    }
+
+
+                }
+
+                if (selectedItem == "") {
+                    genderFlag.value = true
+                    Text("Выберете пол", color = Color.Red, fontSize = 10.sp)
+                }
+                else{
+                    genderFlag.value = false
+                }
+            }
+            Spacer(modifier = Modifier.height(30.dp))
+            Box(
+                modifier = Modifier
+                    .clip(RoundedCornerShape(10.dp))
+
+            ) {
+                Button(
+                    modifier = Modifier
+                        .width(width = 500.dp)
+                        .height(height = 56.dp),
+                    onClick = {
+                        viewModel.addUser(
+                            name = name.value,
+                            surname = surname.value,
+                            patronymic = patronymic.value,
+                            date_of_birth = formattedDateFromBase,
+                            gender = selectedItem
+                        )
+                        flag.value = true
+
+                    },
+                    shape = RoundedCornerShape(size = 10.dp),
+                    enabled = enabled.value,
+                    colors = ButtonDefaults.buttonColors(
+                        containerColor = Color(0xFF92DCE5),
+                        contentColor = Color.White
+                    )
+                ) {
+                    Text(
+                        text = "Создать",
+                        fontSize = 20.sp,
+                        fontWeight = FontWeight.W900,
+                    )
+                }
+            }
+
+        }
+
+        if (flag.value) {
+            when (userState) {
+                is UserState.Loading -> {
+                    LoadingComponent()
+                }
+
+                is UserState.Success -> {
+                    val message = (userState as UserState.Success).message
+                    currentUserState = message
+
+                    navController.navigate(Screen.Profile.route)
+                    flag.value = false
+                }
+
+                is UserState.Error -> {
+                    val message = (userState as UserState.Error).message
+                    currentUserState = message
+                    Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
+                    flag.value = false
+                }
+            }
+
+            if (currentUserState.isNotEmpty()) {
+                println(currentUserState)
+            }
+        }
     }
-}
+
+    MaterialDialog(
+        dialogState = dateDialogState,
+        buttons = {
+            positiveButton(text = "Ok")
+            negativeButton("cancel")
+        })
+    {
+        datepicker(
+            initialDate = LocalDate.now(),
+            allowedDateValidator = {
+                it.year <= LocalDate.now().year
+            }
+
+
+        ) {
+            pickedDate = it
+
+        }
+    }
+}
+
+
+
+
+
+
+
+

+ 90 - 96
app/src/main/java/com/example/tasks/screens/EnterOTP.kt

@@ -1,7 +1,5 @@
 package com.example.tasks.screens
 
-import android.health.connect.datatypes.units.Length
-import android.util.Log
 import android.widget.Toast
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
@@ -74,22 +72,14 @@ import kotlinx.coroutines.delay
 import kotlinx.coroutines.withContext
 
 @Composable
-fun EnterOTP(navController: NavController,email:String,viewModel: AuthViewModel) {
-    var users by remember { mutableStateOf<List<User>>(listOf()) }
+fun EnterOTP(navController: NavController, email: String, viewModel: AuthViewModel) {
     val userState by viewModel.userState
     var currentUserState by remember { mutableStateOf("") }
     val focusManager = LocalFocusManager.current
-    var flag = remember { mutableStateOf(false) }
+    val flag = remember { mutableStateOf(false) }
     val context = LocalContext.current
     val keyboardController = LocalSoftwareKeyboardController.current
-    LaunchedEffect(Unit) {
-        withContext(Dispatchers.IO) {
-             users = Constants.supabase.from("Users")
-                .select(columns = Columns.list("UID")){
-                    filter { User::UID eq viewModel.userID
-                }}.decodeList<User>()
-        }
-    }
+
     val textList = listOf(
         remember {
             mutableStateOf(
@@ -163,22 +153,30 @@ fun EnterOTP(navController: NavController,email:String,viewModel: AuthViewModel)
             }
     )
     {
-        Row(modifier = Modifier
-            .fillMaxWidth()
-            .padding(top = 40.dp, start = 20.dp),
+        Row(
+            modifier = Modifier
+                .fillMaxWidth()
+                .padding(top = 40.dp, start = 20.dp),
             horizontalArrangement = Arrangement.Start,
-            verticalAlignment = Alignment.Top) {
-            Button(onClick = {navController.navigate(Screen.SignIn.route)},
+            verticalAlignment = Alignment.Top
+        ) {
+            Button(
+                onClick = { navController.navigate(Screen.SignIn.route) },
                 shape = RoundedCornerShape(size = 8.dp),
                 colors = ButtonDefaults.buttonColors(
                     containerColor = Color(0xFFF5F5F9)
                 ),
                 modifier = Modifier
                     .width(32.dp)
-                    .height(32.dp),contentPadding = PaddingValues(1.dp)
+                    .height(32.dp), contentPadding = PaddingValues(1.dp)
             )
             {
-                Icon(imageVector = Icons.AutoMirrored.Filled.KeyboardArrowLeft, contentDescription = "Назад",tint = Color.Black,modifier = Modifier.size(20.dp))
+                Icon(
+                    imageVector = Icons.AutoMirrored.Filled.KeyboardArrowLeft,
+                    contentDescription = "Назад",
+                    tint = Color.Black,
+                    modifier = Modifier.size(20.dp)
+                )
             }
         }
     }
@@ -194,7 +192,7 @@ fun EnterOTP(navController: NavController,email:String,viewModel: AuthViewModel)
             modifier = Modifier
                 .align(Alignment.CenterHorizontally)
         ) {
-            ContentView(textList,requesterList)
+            ContentView(textList, requesterList)
         }
         Spacer(modifier = Modifier.height(30.dp))
         Column(
@@ -212,8 +210,7 @@ fun EnterOTP(navController: NavController,email:String,viewModel: AuthViewModel)
                     timer -= 1
                 }
             }
-            if(timer!=0)
-            {
+            if (timer != 0) {
                 Text(
                     text = "Отправить код повторно можно",
                     fontSize = 15.sp,
@@ -225,13 +222,12 @@ fun EnterOTP(navController: NavController,email:String,viewModel: AuthViewModel)
                     color = Color(0xFF939396)
                 )
 
-            }
-            else {
+            } else {
                 Text(
                     text = "Отправить код заново",
                     fontSize = 15.sp,
                     color = Color(0xFF939396),
-                    modifier = Modifier.clickable { viewModel.onSignInEmailCode(context,email)}
+                    modifier = Modifier.clickable { viewModel.onSignInEmailCode(context, email) }
                 )
             }
 
@@ -239,9 +235,11 @@ fun EnterOTP(navController: NavController,email:String,viewModel: AuthViewModel)
 
         Button(
             onClick = {
+                viewModel.checkForRegistration()
                 val token = token(textList)
                 viewModel.verifyOTP(email, token)
-                flag.value = true },
+                flag.value = true
+            },
             Modifier
                 .fillMaxWidth()
                 .height(50.dp),
@@ -256,71 +254,69 @@ fun EnterOTP(navController: NavController,email:String,viewModel: AuthViewModel)
             Text(text = "Далее", fontSize = 14.sp)
 
         }
-       if(flag.value){
-           when (userState) {
-               is UserState.Loading -> {
-                   LoadingComponent()
-               }
-
-               is UserState.Success -> {
-                   val message = (userState as UserState.Success).message
-                   currentUserState = message
-                   if(users.isNotEmpty()){
-                       navController.navigate(Screen.Profile.route)
-                   }
-                   else{
-                       navController.navigate(Screen.CreateProfile.route)
-                   }
-
-                   flag.value = false
-               }
-
-               is UserState.Error -> {
-                   val message = (userState as UserState.Error).message
-                   currentUserState = message
-                   Toast.makeText(context,"Неверный код",Toast.LENGTH_SHORT).show()
-                   flag.value = false
-               }
-           }
-
-           if (currentUserState.isNotEmpty()) {
-               println(currentUserState)
-           }
-       }
+        if (flag.value) {
+            when (userState) {
+                is UserState.Loading -> {
+                    LoadingComponent()
+                }
+
+                is UserState.Success -> {
+                    val message = (userState as UserState.Success).message
+                    currentUserState = message
+
+                    if (viewModel.users.isNotEmpty()) {
+                        navController.navigate(Screen.Profile.route)
+                    } else {
+                        navController.navigate(Screen.CreateProfile.route)
+                    }
+
+                    flag.value = false
+                }
+
+                is UserState.Error -> {
+                    val message = (userState as UserState.Error).message
+                    currentUserState = message
+                    Toast.makeText(context, "Неверный код", Toast.LENGTH_SHORT).show()
+                    flag.value = false
+                }
+            }
+
+            if (currentUserState.isNotEmpty()) {
+                println(currentUserState)
+            }
+        }
 
     }
 
 }
+
 @Composable
 fun LoadingComponent() {
-    Column(modifier = Modifier.fillMaxSize(),
+    Column(
+        modifier = Modifier.fillMaxSize(),
         verticalArrangement = Arrangement.Center,
-        horizontalAlignment = Alignment.CenterHorizontally) {
+        horizontalAlignment = Alignment.CenterHorizontally
+    ) {
         CircularProgressIndicator()
     }
 }
-private fun token ( textList: List<MutableState<TextFieldValue>>):String{
+
+private fun token(textList: List<MutableState<TextFieldValue>>): String {
     var code = ""
-    for(text in textList)
-    {
+    for (text in textList) {
         code += text.value.text
     }
     return code
 }
 
 
-
-
 fun nextFocus(
     textList: List<MutableState<TextFieldValue>>,
-    requesterList: List<FocusRequester>)
-{
-    for(index in textList.indices)
-    {
-        if(textList[index].value.text == "")
-        {
-            if(index<textList.size)
-            {
+    requesterList: List<FocusRequester>
+) {
+    for (index in textList.indices) {
+        if (textList[index].value.text == "") {
+            if (index < textList.size) {
                 requesterList[index].requestFocus()
                 break
             }
@@ -330,11 +326,10 @@ fun nextFocus(
 
 @Composable
 fun inputWiew(
-    value:TextFieldValue,
-    onValueChange: (value:TextFieldValue) -> Unit,
+    value: TextFieldValue,
+    onValueChange: (value: TextFieldValue) -> Unit,
     focusRequester: FocusRequester
-)
-{
+) {
     BasicTextField(
         readOnly = false,
         value = value,
@@ -350,11 +345,11 @@ fun inputWiew(
             .border(1.dp, Color(0xFFEBEBEB)),
         singleLine = true,
         maxLines = 1,
-        decorationBox = {
-                innerTextField ->
-            Box(modifier = Modifier
-                .width(40.dp)
-                .height(40.dp),
+        decorationBox = { innerTextField ->
+            Box(
+                modifier = Modifier
+                    .width(40.dp)
+                    .height(40.dp),
                 contentAlignment = Alignment.Center,
             )
             {
@@ -368,7 +363,10 @@ fun inputWiew(
             fontSize = 20.sp,
             textAlign = TextAlign.Center
         ),
-        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
+        keyboardOptions = KeyboardOptions(
+            keyboardType = KeyboardType.Number,
+            imeAction = ImeAction.Done
+        ),
         keyboardActions = KeyboardActions(
             onDone = null
         )
@@ -379,8 +377,7 @@ fun inputWiew(
 fun ContentView(
     textList: List<MutableState<TextFieldValue>>,
     requesterList: List<FocusRequester>,
-)
-{
+) {
 
 
     Surface {
@@ -395,15 +392,12 @@ fun ContentView(
                     .padding(top = 50.dp)
                     .align(Alignment.Center)
             ) {
-                for(i in textList.indices)
-                {
+                for (i in textList.indices) {
                     inputWiew(
                         value = textList[i].value,
-                        onValueChange = {newValue ->
-                            if(textList[i].value.text!="")
-                            {
-                                if(newValue.text=="")
-                                {
+                        onValueChange = { newValue ->
+                            if (textList[i].value.text != "") {
+                                if (newValue.text == "") {
                                     textList[i].value = TextFieldValue(
                                         text = "",
                                         selection = TextRange(0)
@@ -415,14 +409,14 @@ fun ContentView(
                                 text = newValue.text,
                                 selection = TextRange(newValue.text.length)
                             )
-                            nextFocus(textList,requesterList)},
-                        focusRequester = requesterList[i])
+                            nextFocus(textList, requesterList)
+                        },
+                        focusRequester = requesterList[i]
+                    )
 
                 }
 
 
-
-
             }
         }
     }

+ 8 - 5
app/src/main/java/com/example/tasks/screens/SignIn.kt

@@ -22,24 +22,27 @@ import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.navigation.NavController
 import com.example.tasks.components.CustomEmail
-import com.example.tasks.components.CustomPassword
 import com.example.tasks.navigation.Screen
 import com.example.tasks.viewModels.AuthViewModel
 
 @Composable
-fun SignIn(navController:NavController, viewModel: AuthViewModel) {
+fun SignIn(navController: NavController, viewModel: AuthViewModel) {
     val context = LocalContext.current
     val email = remember { mutableStateOf("") }
     Column(
-        modifier = Modifier.fillMaxSize().padding(10.dp),
+        modifier = Modifier
+            .fillMaxSize()
+            .padding(10.dp),
         verticalArrangement = Arrangement.Center,
         horizontalAlignment = Alignment.CenterHorizontally
     ) {
         CustomEmail(search = email.value, onValueChange = { email.value = it })
         Spacer(Modifier.height(30.dp))
         Button(
-            onClick = { viewModel.onSignInEmailCode(context,email.value)
-                      navController.navigate(Screen.EnterOTP.withArg(email.value))},
+            onClick = {
+                viewModel.onSignInEmailCode(context, email.value)
+                navController.navigate(Screen.EnterOTP.withArg(email.value))
+            },
             Modifier
                 .fillMaxWidth()
                 .height(50.dp),

+ 68 - 45
app/src/main/java/com/example/tasks/viewModels/AuthViewModel.kt

@@ -8,29 +8,29 @@ import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import com.example.tasks.components.Constants
 import com.example.tasks.components.SharedPreferenceHelper
+import com.example.tasks.model.User
 import com.example.tasks.model.UserState
 import io.github.jan.supabase.gotrue.OtpType
 import io.github.jan.supabase.gotrue.auth
-import io.github.jan.supabase.gotrue.providers.builtin.Email
 import io.github.jan.supabase.gotrue.providers.builtin.OTP
+import io.github.jan.supabase.postgrest.from
 import kotlinx.coroutines.launch
 
 
 class AuthViewModel : ViewModel() {
     private val _userState = mutableStateOf<UserState>(UserState.Loading)
     val userState: State<UserState> = _userState
-    var userID = ""
+    var users = listOf<User>()
     fun onSignInEmailCode(context: Context, emailUser: String) {
         viewModelScope.launch {
             try {
                 _userState.value = UserState.Loading
-                 Constants.supabase.auth.signInWith(OTP) {
+                Constants.supabase.auth.signInWith(OTP) {
                     email = emailUser
                     createUser = false
                 }
                 saveToken(context)
-                userID = Constants.supabase.auth.currentUserOrNull()!!.id
-                _userState.value = UserState.Success("Successful sign in")
+
 
             } catch (e: Exception) {
                 _userState.value = UserState.Error("Error: ${e.message}")
@@ -40,6 +40,23 @@ class AuthViewModel : ViewModel() {
         }
     }
 
+    fun checkForRegistration() {
+        viewModelScope.launch {
+            try {
+
+                users = Constants.supabase.from("Users")
+                    .select() {
+                        filter {
+                            User::UID eq Constants.supabase.auth.currentUserOrNull()!!.id
+                        }
+                    }
+                    .decodeList<User>()
+            } catch (e: Exception) {
+                println(e.message)
+            }
+        }
+    }
+
     private fun saveToken(context: Context) {
         viewModelScope.launch {
             val accessToken = Constants.supabase.auth.currentAccessTokenOrNull()
@@ -91,61 +108,67 @@ class AuthViewModel : ViewModel() {
         }
     }
 
-    fun onSignInEmailPassword(emailUser: String, passwordUser: String) {
-        viewModelScope.launch {
-            try {
-                val user = Constants.supabase.auth.signInWith(Email) {
-                    email = emailUser
-                    password = passwordUser
-                }
-                println(user.toString())
-                println(Constants.supabase.auth.currentUserOrNull()!!.id)
-                println("Success")
-            } catch (e: Exception) {
-                println("Error")
-                println(e.message.toString())
-            }
-        }
-    }
 
-    fun onSignUpEmail(emailUser: String, passwordUser: String) {
+    fun isUserLoggedIn(context: Context) {
         viewModelScope.launch {
             try {
-                var user = Constants.supabase.auth.signUpWith(Email) {
-                    email = emailUser
-                    password = passwordUser
+                val token = getToken(context)
+                if (token.isNullOrEmpty()) {
+                    _userState.value = UserState.Error("User is not logged in")
+                } else {
+                    Constants.supabase.auth.retrieveUser(token)
+                    Constants.supabase.auth.refreshCurrentSession()
+                    saveToken(context)
+                    _userState.value = UserState.Success("User is logged in")
                 }
-                println(user.toString())
-                println(Constants.supabase.auth.currentUserOrNull()!!.id)
-                println("Success")
+
             } catch (e: Exception) {
-                println("Error")
-                println(e.message.toString())
+                _userState.value = UserState.Error("Error: ${e.message}")
             }
-
         }
     }
 
-
-    fun isUserLoggedIn(context: Context){
+    fun addUser(
+        name: String,
+        surname: String,
+        patronymic: String,
+        date_of_birth: String,
+        gender: String
+    ) {
         viewModelScope.launch {
             try {
-                val token = getToken(context)
-                if (token.isNullOrEmpty()){
-                    _userState.value = UserState.Error("User is not logged in")
-                }
-                else
-                {
-                    Constants.supabase.auth.retrieveUser(token)
-                    Constants.supabase.auth.refreshCurrentSession()
-                    saveToken(context)
-                    _userState.value = UserState.Success("User is logged in")
+                _userState.value = UserState.Loading
+                if (gender == "Женский") {
+                    Constants.supabase.from("Users").insert(
+                        User(
+                            LastName = surname,
+                            FirstName = name,
+                            DateOfBirth = date_of_birth,
+                            Gender = 1,
+                            UID = Constants.supabase.auth.currentUserOrNull()!!.id,
+                            Patronymic = patronymic
+                        )
+                    )
+                } else {
+                    Constants.supabase.from("Users").insert(
+                        User(
+                            LastName = surname,
+                            FirstName = name,
+                            DateOfBirth = date_of_birth,
+                            Gender = 2,
+                            UID = Constants.supabase.auth.currentUserOrNull()!!.id,
+                            Patronymic = patronymic
+                        )
+                    )
                 }
+                _userState.value = UserState.Success("The user has been successfully added")
 
-            }
-            catch (e:Exception){
+            } catch (e: Exception) {
                 _userState.value = UserState.Error("Error: ${e.message}")
+
             }
+
         }
+
     }
 }

+ 1 - 0
build.gradle.kts

@@ -2,4 +2,5 @@
 plugins {
     alias(libs.plugins.android.application) apply false
     alias(libs.plugins.jetbrains.kotlin.android) apply false
+    id ("org.jetbrains.kotlin.plugin.serialization") version "1.6.21"
 }

+ 2 - 0
gradle/libs.versions.toml

@@ -1,6 +1,7 @@
 [versions]
 agp = "8.5.2"
 bom = "2.6.1"
+datetime = "0.8.1-rc"
 kotlin = "1.9.0"
 coreKtx = "1.13.1"
 junit = "4.13.2"
@@ -23,6 +24,7 @@ androidx-navigation-dynamic-features-fragment = { module = "androidx.navigation:
 androidx-navigation-fragment = { module = "androidx.navigation:navigation-fragment", version.ref = "navigationCompose" }
 androidx-navigation-ui = { module = "androidx.navigation:navigation-ui", version.ref = "navigationCompose" }
 bom = { module = "io.github.jan-tennert.supabase:bom", version.ref = "bom" }
+datetime = { module = "io.github.vanpra.compose-material-dialogs:datetime", version.ref = "datetime" }
 gotrue-kt = { module = "io.github.jan-tennert.supabase:gotrue-kt" }
 junit = { group = "junit", name = "junit", version.ref = "junit" }
 androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }