From 6316b927b704317538b176da522fefa904b58892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D0=B5=D0=BC=20=D0=A5=D0=B0=D1=80=D0=BB?= =?UTF-8?q?=D0=B0=D0=BC=D0=BE=D0=B2?= Date: Sat, 10 Feb 2024 18:07:05 +0400 Subject: [PATCH] =?UTF-8?q?=D0=9B=D0=B0=D0=B1=D0=BE=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=BD=D0=B0=D1=8F=203.=20=D0=A4=D0=B8=D0=BD=D0=B0?= =?UTF-8?q?=D0=BB.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 22 ++- .../2.json | 108 +++++++++++ app/src/main/AndroidManifest.xml | 1 + app/src/main/assets/database/example.db | Bin 0 -> 20480 bytes .../java/com/example/pmu_2023/Forms/Login.kt | 69 +++++-- .../com/example/pmu_2023/Forms/MainForm.kt | 142 +++++++++++++-- .../example/pmu_2023/Forms/Registration.kt | 85 ++++----- .../java/com/example/pmu_2023/Forms/Screen.kt | 16 +- .../java/com/example/pmu_2023/database/App.kt | 7 + .../example/pmu_2023/database/AppDatabase.kt | 39 ++++ .../pmu_2023/database/MainViewModel.kt | 69 +++++++ .../pmu_2023/logic/composeui/CreateParcel.kt | 80 ++++++++ .../pmu_2023/logic/composeui/ParcelList.kt | 171 ++++++++++++++++++ .../pmu_2023/logic/composeui/ParcelView.kt | 83 +++++++++ .../pmu_2023/logic/composeui/UpdateParcel.kt | 84 +++++++++ .../logic/composeui/UserProfileView.kt | 92 ++++++++++ .../example/pmu_2023/logic/dao/ParcelDao.kt | 27 +++ .../com/example/pmu_2023/logic/dao/UserDao.kt | 33 ++++ .../example/pmu_2023/logic/model/Parcel.kt | 40 ++++ .../com/example/pmu_2023/logic/model/User.kt | 37 ++++ .../pmu_2023/logic/model/UserWithParcels.kt | 15 ++ .../pmu_2023/parcel/composeui/ParcelList.kt | 88 --------- .../pmu_2023/parcel/composeui/ParcelView.kt | 76 -------- .../example/pmu_2023/parcel/model/Parcel.kt | 19 -- app/src/main/res/values/strings.xml | 6 +- 25 files changed, 1135 insertions(+), 274 deletions(-) create mode 100644 app/schemas/com.example.pmu_2023.database.AppDatabase/2.json create mode 100644 app/src/main/assets/database/example.db create mode 100644 app/src/main/java/com/example/pmu_2023/database/App.kt create mode 100644 app/src/main/java/com/example/pmu_2023/database/AppDatabase.kt create mode 100644 app/src/main/java/com/example/pmu_2023/database/MainViewModel.kt create mode 100644 app/src/main/java/com/example/pmu_2023/logic/composeui/CreateParcel.kt create mode 100644 app/src/main/java/com/example/pmu_2023/logic/composeui/ParcelList.kt create mode 100644 app/src/main/java/com/example/pmu_2023/logic/composeui/ParcelView.kt create mode 100644 app/src/main/java/com/example/pmu_2023/logic/composeui/UpdateParcel.kt create mode 100644 app/src/main/java/com/example/pmu_2023/logic/composeui/UserProfileView.kt create mode 100644 app/src/main/java/com/example/pmu_2023/logic/dao/ParcelDao.kt create mode 100644 app/src/main/java/com/example/pmu_2023/logic/dao/UserDao.kt create mode 100644 app/src/main/java/com/example/pmu_2023/logic/model/Parcel.kt create mode 100644 app/src/main/java/com/example/pmu_2023/logic/model/User.kt create mode 100644 app/src/main/java/com/example/pmu_2023/logic/model/UserWithParcels.kt delete mode 100644 app/src/main/java/com/example/pmu_2023/parcel/composeui/ParcelList.kt delete mode 100644 app/src/main/java/com/example/pmu_2023/parcel/composeui/ParcelView.kt delete mode 100644 app/src/main/java/com/example/pmu_2023/parcel/model/Parcel.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 20e3155..141425e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") + id("kotlin-kapt") } android { @@ -18,6 +19,11 @@ android { vectorDrawables { useSupportLibrary = true } + kapt { + arguments { + arg("room.schemaLocation", "$projectDir/schemas") + } + } } buildTypes { @@ -46,6 +52,12 @@ android { } } +tasks.withType(type = org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask::class) { + kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString() + +} + + dependencies { implementation("androidx.navigation:navigation-compose:2.6.0") implementation("androidx.core:core-ktx:1.9.0") @@ -65,10 +77,10 @@ dependencies { debugImplementation("androidx.compose.ui:ui-test-manifest") // Room - val room_version = "2.5.2" - implementation("androidx.room:room-runtime:$room_version") - annotationProcessor("androidx.room:room-compiler:$room_version") - kapt("androidx.room:room-compiler:$room_version") + val room_version = "2.5.1" implementation("androidx.room:room-ktx:$room_version") - implementation("androidx.room:room-paging:$room_version") + kapt ("androidx.room:room-compiler:$room_version") + implementation ("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0") + + implementation ("androidx.compose.runtime:runtime-livedata:1.0.0-beta01") } \ No newline at end of file diff --git a/app/schemas/com.example.pmu_2023.database.AppDatabase/2.json b/app/schemas/com.example.pmu_2023.database.AppDatabase/2.json new file mode 100644 index 0000000..7f64c8b --- /dev/null +++ b/app/schemas/com.example.pmu_2023.database.AppDatabase/2.json @@ -0,0 +1,108 @@ +{ + "formatVersion": 1, + "database": { + "version": 2, + "identityHash": "92c4ab5b3a31c5bee1cd30524bdd2448", + "entities": [ + { + "tableName": "users", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER PRIMARY KEY AUTOINCREMENT, `fio` TEXT NOT NULL, `password` TEXT NOT NULL, `address` TEXT NOT NULL, `phone` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "fio", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "phone", + "columnName": "phone", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "userId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "parcels", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`parcelId` INTEGER PRIMARY KEY AUTOINCREMENT, `parcel_name` TEXT NOT NULL, `track_number` TEXT NOT NULL, `status` TEXT NOT NULL, `description` TEXT NOT NULL, `userOwnerId` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "parcelId", + "columnName": "parcelId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "parcel_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "trackNumber", + "columnName": "track_number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userOwnerId", + "columnName": "userOwnerId", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "parcelId" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '92c4ab5b3a31c5bee1cd30524bdd2448')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e143e76..3cafc38 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools"> hIMmeJy$bI)tpn!MLGq(m*US(+p{OPC11ISG`p;&vYL`jy+5ZZflgnJKA=pD zdIELJFf)aKC$o^%(%SL`5?w1+0-mgPHLENvQdymwrO;3J@j>JL7*ZL523TOSU){eJ(UoR8IVZas5zWT$98oT!po z%`RpZXc6YMg=}avv?PuACnv?V!zogrnzM|Xb)%f;E8kglbuC?wa-yu4j0VvjI!LagXv05uu$^*>!3NCJzyY^z|_Uqa)N2Bgz>?Ig3c~y{qlkd_47YKj= z2!H?xfB*=900@8p2!H?xfIu&S`Na9jAp6qZVL#gU*iWo!-&NQ{m4&4dVVqQ#>$gkA zva+IHQ6teI_@R>UF`!PrU zAJCD1LP`fIC7{V3(fR%zey*>u&sFwm+wxzX{J%>l|1l{MWcMjcpwY?>P}qHyKCS+b zKmRA1F5lmR{H;7o4_qJs0w4eaAOHd&00JNY0w4eaAn@NHuq3&Kcix&xi|hfV;qTa= zP{iD1`>YwCj?KiA)6ry@J*8N@$)4D|_BK0ERh50so>FrEmJ?n#*`C7XJlf`I{E{xZ zh0yqF+Cv^GOP_S#QLg@ebS4&$khf$!O4fVSbdSP(CqP$toXTliDWF?(null)} + var isLoading by remember { mutableStateOf(false)} + if (isLoading){ + LaunchedEffect(Unit){ + val newData = withContext(Dispatchers.IO){ + mainViewModel.getUserByNameAndPass(LoginText, PassText) + } + data = newData + val userId = Screen.ParcelList.route.replace("{id}", data?.userId.toString()) + isLoading = false + navController?.navigate(userId) + } + } Column ( - modifier = Modifier.fillMaxSize().padding(all = 10.dp), + modifier = Modifier + .fillMaxSize() + .padding(all = 10.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - Login_Field(name = "Email", label = "Введите адрес электронной почты...") - Login_Field(name = "Password", label = "Введите пароль...") + Login_Field(value = LoginText, onInputChanged = {LoginText = it} ,name = "Email", label = "Введите логин...") + Login_Field(value = PassText, onInputChanged = {PassText = it} ,name = "Password", label = "Введите пароль...") Text( text = "Регистрация", style = TextStyle(textDecoration = TextDecoration.Underline), @@ -58,13 +100,12 @@ fun Login(navController: NavController?){ textAlign = TextAlign.End ) Spacer(Modifier.size(20.dp)) + Button( - onClick = { navController?.navigate("parcel-list") }, - shape = RoundedCornerShape(15.dp), - colors = ButtonDefaults.buttonColors( - containerColor = Color.White, - contentColor = Color.Black - ) + onClick = { + isLoading = true + }, + shape = RoundedCornerShape(15.dp) ) { Text( text = "Войти", @@ -76,9 +117,7 @@ fun Login(navController: NavController?){ @OptIn(ExperimentalMaterial3Api::class) @Composable -fun Login_Field(name: String, label: String){ - - var sampletext by remember { mutableStateOf("") } +fun Login_Field(value: String, onInputChanged: (String) -> Unit, name: String, label: String){ Column (modifier = Modifier .fillMaxWidth() @@ -89,8 +128,8 @@ fun Login_Field(name: String, label: String){ fontSize = 18.sp ) TextField( - value = sampletext, - onValueChange = { sampletext = it}, + value = value, + onValueChange = onInputChanged, placeholder = { Text(text = label) }, diff --git a/app/src/main/java/com/example/pmu_2023/Forms/MainForm.kt b/app/src/main/java/com/example/pmu_2023/Forms/MainForm.kt index 72372fc..2cd9829 100644 --- a/app/src/main/java/com/example/pmu_2023/Forms/MainForm.kt +++ b/app/src/main/java/com/example/pmu_2023/Forms/MainForm.kt @@ -1,12 +1,20 @@ package com.example.pmu_2023.Forms -import android.content.res.Configuration +import android.util.Log +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues 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.material.icons.Icons +import androidx.compose.material.icons.filled.AccountBox +import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Menu import androidx.compose.material3.DrawerState import androidx.compose.material3.DrawerValue @@ -27,13 +35,22 @@ import androidx.compose.material3.rememberDrawerState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController import androidx.navigation.NavType @@ -43,8 +60,13 @@ import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument import com.example.pmu_2023.R -import com.example.pmu_2023.parcel.composeui.ParcelList -import com.example.pmu_2023.parcel.composeui.ParcelView +import com.example.pmu_2023.database.MainViewModel +import com.example.pmu_2023.logic.composeui.CreateParcel +import com.example.pmu_2023.logic.composeui.ParcelList +import com.example.pmu_2023.logic.composeui.ParcelView +import com.example.pmu_2023.logic.composeui.UpdateParcel +import com.example.pmu_2023.logic.composeui.UserProfileView +import com.example.pmu_2023.logic.model.User import com.example.pmu_2023.ui.theme.PMU_2023Theme import com.example.pmu_2023.ui.theme.PurpleGrey80 import kotlinx.coroutines.CoroutineScope @@ -57,7 +79,8 @@ fun Topbar( navController: NavHostController, currentScreen: Screen?, drawerState: DrawerState, - scope: CoroutineScope + scope: CoroutineScope, + mainViewModel: MainViewModel ) { TopAppBar( colors = TopAppBarDefaults.smallTopAppBarColors( @@ -65,7 +88,11 @@ fun Topbar( titleContentColor = MaterialTheme.colorScheme.onPrimary, ), title = { - Text(stringResource(currentScreen?.resourceId ?: R.string.app_name)) + Text( + modifier = Modifier.fillMaxWidth(), + text = stringResource(currentScreen?.resourceId ?: R.string.app_name), + textAlign = TextAlign.Center + ) }, navigationIcon = { if ( @@ -98,6 +125,21 @@ fun Topbar( } }, + actions = { + if(currentScreen == Screen.ParcelList) { + IconButton(onClick = { + val userId = Screen.CreateParcel.route.replace("{id}", mainViewModel.curUid.value.toString()) + navController.navigate(userId) + } + ) { + Icon( + imageVector = Icons.Filled.Add, + contentDescription = "Add Parcel", + tint = MaterialTheme.colorScheme.onPrimary + ) + } + } + } ) } @@ -105,29 +147,54 @@ fun Topbar( @Composable fun Navhost( navController: NavHostController, - innerPadding: PaddingValues, modifier: - Modifier = Modifier + innerPadding: PaddingValues, + mainViewModel: MainViewModel, + modifier: Modifier = Modifier ) { NavHost( navController, startDestination = Screen.Login.route, modifier.padding(innerPadding) ) { - composable(Screen.ParcelList.route) { ParcelList(navController) } - composable(Screen.Login.route) { Login(navController) } - composable(Screen.Registration.route) { Registration(navController) } + composable(Screen.ParcelList.route, + arguments = listOf(navArgument("id") { type = NavType.IntType }) + ) { backStackEntry -> + backStackEntry.arguments?.let { ParcelList(navController, it.getInt("id"), mainViewModel) } + } + composable(Screen.Login.route) { Login(navController, mainViewModel) } + composable(Screen.Registration.route) { Registration(navController, mainViewModel) } composable( Screen.ParcelView.route, arguments = listOf(navArgument("id") { type = NavType.IntType }) ) { backStackEntry -> - backStackEntry.arguments?.let { ParcelView(it.getInt("id")) } + backStackEntry.arguments?.let { ParcelView(it.getInt("id"), mainViewModel) } + } + composable( + Screen.CreateParcel.route, + arguments = listOf(navArgument("id") { type = NavType.IntType }) + ) { backStackEntry -> + backStackEntry.arguments?.let { CreateParcel(it.getInt("id"), mainViewModel) } + } + composable( + Screen.UpdateParcel.route, + arguments = listOf(navArgument("id") { type = NavType.IntType }) + ) { backStackEntry -> + backStackEntry.arguments?.let { UpdateParcel(it.getInt("id"), mainViewModel) } + } + composable( + Screen.UserProfileView.route, + arguments = listOf(navArgument("id") { type = NavType.IntType }) + ) { backStackEntry -> + backStackEntry.arguments?.let { UserProfileView(it.getInt("id"), mainViewModel) } } } } @OptIn(ExperimentalMaterial3Api::class) @Composable -fun MainContent() { +fun MainContent( + mainViewModel: MainViewModel = viewModel(factory = MainViewModel.factory) +) { val navController = rememberNavController() val navBackStackEntry by navController.currentBackStackEntryAsState() val currentDestination = navBackStackEntry?.destination @@ -136,10 +203,33 @@ fun MainContent() { val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) val scope = rememberCoroutineScope() var selectedItemIndex by rememberSaveable { mutableStateOf(0) } + ModalNavigationDrawer( gesturesEnabled = false, drawerContent = { ModalDrawerSheet { + Column( + modifier = Modifier + .fillMaxWidth() + .height(100.dp) + .drawBehind { + drawLine( + Color.Black, + Offset(0f, size.height), + Offset(size.width, size.height), + 5f + ) + } + .background(PurpleGrey80), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Меню", + fontSize = 24.sp, + fontWeight = FontWeight.Bold + ) + } Spacer(modifier = Modifier.height(16.dp)) Screen.DrawerItems.forEachIndexed { index, item -> NavigationDrawerItem( @@ -148,7 +238,8 @@ fun MainContent() { }, selected = index == selectedItemIndex, onClick = { - navController.navigate(item.route){ + val userId = item.route.replace("{id}", mainViewModel.curUid.value.toString()) + navController.navigate(userId){ popUpTo(navController.graph.findStartDestination().id) { saveState = true } @@ -172,16 +263,37 @@ fun MainContent() { .padding(NavigationDrawerItemDefaults.ItemPadding) ) } + NavigationDrawerItem( + label = { + Text(stringResource(R.string.quit_title)) + }, + selected = 2 == selectedItemIndex, + onClick = { + navController.navigate("login") + selectedItemIndex = 2 + scope.launch { + drawerState.close() + } + }, + icon = { + Icon( + imageVector = Icons.Filled.Close, + contentDescription = stringResource(R.string.quit_title) + ) + }, + modifier = Modifier + .padding(NavigationDrawerItemDefaults.ItemPadding) + ) } }, drawerState = drawerState ) { Scaffold( topBar = { - Topbar(navController, currentScreen, drawerState, scope) + Topbar(navController, currentScreen, drawerState, scope, mainViewModel) }, ) {innerPadding -> - Navhost(navController, innerPadding) + Navhost(navController, innerPadding, mainViewModel) } } } diff --git a/app/src/main/java/com/example/pmu_2023/Forms/Registration.kt b/app/src/main/java/com/example/pmu_2023/Forms/Registration.kt index b90e561..89993b1 100644 --- a/app/src/main/java/com/example/pmu_2023/Forms/Registration.kt +++ b/app/src/main/java/com/example/pmu_2023/Forms/Registration.kt @@ -25,10 +25,12 @@ import androidx.compose.material3.TextFieldColors import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -40,13 +42,23 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController +import com.example.pmu_2023.database.MainViewModel +import com.example.pmu_2023.logic.model.Parcel +import com.example.pmu_2023.logic.model.User import com.example.pmu_2023.ui.theme.MainBlue +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext @Composable -fun Registration(navController: NavController?){ - val list = listOf("Поставщик", "Покупатель") - val expanded = remember { mutableStateOf(false) } - val currentValue = remember { mutableStateOf(list[0]) } +fun Registration( + navController: NavController?, + mainViewModel: MainViewModel +){ + var NameText by rememberSaveable { mutableStateOf("")} + var PassText by rememberSaveable { mutableStateOf("")} + var AddressText by rememberSaveable { mutableStateOf("")} + var PhoneText by rememberSaveable { mutableStateOf("")} + Column ( modifier = Modifier .fillMaxSize(), @@ -58,42 +70,18 @@ fun Registration(navController: NavController?){ .fillMaxWidth() .padding(20.dp) ) { - Row( - modifier = Modifier - .clickable { expanded.value = !expanded.value } - .border(width = 1.dp, color = Color.White, shape = RoundedCornerShape(15.dp)) - ) { - Text(modifier = Modifier.padding(15.dp), text = currentValue.value, fontSize = 18.sp) - Icon(modifier = Modifier.padding(15.dp), imageVector = Icons.Filled.ArrowDropDown, contentDescription = null) - - - DropdownMenu(expanded = expanded.value, onDismissRequest = { - expanded.value = false - }) { - - list.forEach { - DropdownMenuItem( - text = { - Text( - text = it, - fontSize = 18.sp) - }, - onClick = { - currentValue.value = it - expanded.value = false - }) - } - } - } - Registr_Field(label = "ФИО") - Registr_Field(label = "Номер телефона") - Registr_Field(label = "Логин") - Registr_Field(label = "Пароль") + Registr_Field(value = NameText, onInputChanged = {NameText = it} ,name = "Email", label = "Придумайте логин...") + Registr_Field(value = PassText, onInputChanged = {PassText = it} ,name = "Password", label = "Придумайте пароль...") + Registr_Field(value = AddressText, onInputChanged = {AddressText = it} ,name = "Password", label = "Введите адрес...") + Registr_Field(value = PhoneText, onInputChanged = {PhoneText = it} ,name = "Password", label = "Введите номер телефона...") } Button( - onClick = {navController?.navigate("parcel-list")}, - shape = RoundedCornerShape(15.dp), - colors = ButtonDefaults.buttonColors(containerColor = Color.White, contentColor = Color.Black) + onClick = { + val newUser = User(NameText, PassText, AddressText, PhoneText) + mainViewModel.insertUser(newUser) + navController?.navigate("login") + }, + shape = RoundedCornerShape(15.dp) ) { Text( @@ -106,31 +94,20 @@ fun Registration(navController: NavController?){ @OptIn(ExperimentalMaterial3Api::class) @Composable -fun Registr_Field(label: String){ - - var sample_text by remember { mutableStateOf("") } +fun Registr_Field(value: String, onInputChanged: (String) -> Unit, name: String, label: String){ Column (modifier = Modifier .fillMaxWidth() .padding(top = 10.dp)) { OutlinedTextField( - value = sample_text, - onValueChange = { sample_text = it }, + value = value, + onValueChange = onInputChanged, label = { - Text( - text = label, - fontSize = 18.sp) + Text(text = label) }, modifier = Modifier .fillMaxWidth(), - shape = RoundedCornerShape(15.dp), - colors = TextFieldDefaults.outlinedTextFieldColors( -// focusedBorderColor = Color.White, -// unfocusedBorderColor = Color.White, - // focusedLabelColor = Color.White, - // unfocusedLabelColor = Color.Black, - // textColor = Color.White - ) + shape = RoundedCornerShape(15.dp) ) } } \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/Forms/Screen.kt b/app/src/main/java/com/example/pmu_2023/Forms/Screen.kt index bc83cd3..0ae9257 100644 --- a/app/src/main/java/com/example/pmu_2023/Forms/Screen.kt +++ b/app/src/main/java/com/example/pmu_2023/Forms/Screen.kt @@ -2,9 +2,13 @@ package com.example.pmu_2023.Forms import androidx.annotation.StringRes import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccountBox +import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.List +import androidx.compose.material.icons.outlined.AccountBox +import androidx.compose.material.icons.outlined.Close import androidx.compose.material.icons.outlined.List import androidx.compose.ui.graphics.vector.ImageVector import com.example.pmu_2023.R @@ -17,7 +21,7 @@ enum class Screen( val showInDrawer: Boolean = true ) { ParcelList( - "parcel-list", R.string.parcel_list_title, Icons.Filled.List, Icons.Outlined.List + "parcel-list/{id}", R.string.parcel_list_title, Icons.Filled.List, Icons.Outlined.List ), Login( "login", R.string.login_title @@ -27,11 +31,21 @@ enum class Screen( ), ParcelView( "parcel-view/{id}", R.string.parcel_view_title, showInDrawer = false + ), + CreateParcel( + "parcel-create/{id}", R.string.parcel_create_title, showInDrawer = false + ), + UpdateParcel( + "parcel-update/{id}", R.string.parcel_update_title, showInDrawer = false + ), + UserProfileView( + "user-view/{id}", R.string.user_view_title, Icons.Filled.AccountBox, Icons.Outlined.AccountBox ); companion object { val DrawerItems = listOf( ParcelList, + UserProfileView ) fun getItem(route: String): Screen? { diff --git a/app/src/main/java/com/example/pmu_2023/database/App.kt b/app/src/main/java/com/example/pmu_2023/database/App.kt new file mode 100644 index 0000000..25f213c --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/database/App.kt @@ -0,0 +1,7 @@ +package com.example.pmu_2023.database + +import android.app.Application + +class App : Application() { + val database by lazy { AppDatabase.createDataBase(this) } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/database/AppDatabase.kt b/app/src/main/java/com/example/pmu_2023/database/AppDatabase.kt new file mode 100644 index 0000000..8393820 --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/database/AppDatabase.kt @@ -0,0 +1,39 @@ +package com.example.pmu_2023.database + +import android.content.Context +import androidx.room.AutoMigration +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.sqlite.db.SupportSQLiteDatabase +import com.example.pmu_2023.logic.dao.ParcelDao +import com.example.pmu_2023.logic.dao.UserDao +import com.example.pmu_2023.logic.model.Parcel +import com.example.pmu_2023.logic.model.User +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +@Database( + entities = [User::class, Parcel::class], + version = 2, + exportSchema = true +) +abstract class AppDatabase : RoomDatabase() { + + abstract val userDao: UserDao + abstract val parcelDao: ParcelDao + + companion object { + private const val DB_NAME: String = "pmy-db" + + fun createDataBase(context: Context): AppDatabase { + return Room.databaseBuilder( + context, + AppDatabase::class.java, + DB_NAME + ).createFromAsset("database/example.db") + .build() + } + } +} diff --git a/app/src/main/java/com/example/pmu_2023/database/MainViewModel.kt b/app/src/main/java/com/example/pmu_2023/database/MainViewModel.kt new file mode 100644 index 0000000..f2169cd --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/database/MainViewModel.kt @@ -0,0 +1,69 @@ +package com.example.pmu_2023.database + +import android.util.Log +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.CreationExtras +import com.example.pmu_2023.logic.model.Parcel +import com.example.pmu_2023.logic.model.User +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.launch + +class MainViewModel(val database: AppDatabase) : ViewModel() { + + //User Logic + + var curUid = mutableStateOf(null) + suspend fun getUserByNameAndPass(name: String, password: String): User? { + val getUser = database.userDao.getByLogin(name, password) + curUid.value = getUser?.userId + return getUser + } + + suspend fun getUserById(id: Int?): User?{ + return database.userDao.getById(id) + } + + fun insertUser(user: User) = viewModelScope.launch { + database.userDao.insert(user) + } + + //Parcel Logic + suspend fun getParcelById(id: Int?): Parcel?{ + return database.parcelDao.getById(id) + } + + fun getParcelsById(id: Int?): Flow> { + return database.parcelDao.getAllByUid(id) + } + + fun deleteParcel(parcel: Parcel?) = viewModelScope.launch { + database.parcelDao.delete(parcel) + } + + fun insertParcel(parcel: Parcel) = viewModelScope.launch { + database.parcelDao.insert(parcel) + } + + fun updateParcel(parcel: Parcel) = viewModelScope.launch { + database.parcelDao.update(parcel) + } + + companion object{ + val factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory{ + @Suppress("UNCHECKED_CAST") + override fun create( + modelClass: Class, + extras: CreationExtras): T { + val database = (checkNotNull(extras[APPLICATION_KEY]) as App).database + return MainViewModel(database) as T + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/logic/composeui/CreateParcel.kt b/app/src/main/java/com/example/pmu_2023/logic/composeui/CreateParcel.kt new file mode 100644 index 0000000..973818a --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/logic/composeui/CreateParcel.kt @@ -0,0 +1,80 @@ +package com.example.pmu_2023.logic.composeui + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +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.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.pmu_2023.R +import com.example.pmu_2023.database.MainViewModel +import com.example.pmu_2023.logic.model.Parcel + +@Composable +fun CreateParcel( + id: Int, + mainViewModel: MainViewModel +) { + + var NameText by rememberSaveable { mutableStateOf("") } + var TrackText by rememberSaveable { mutableStateOf("") } + var StatusText by rememberSaveable { mutableStateOf("") } + var DescriptionText by rememberSaveable { mutableStateOf("") } + + Column( + Modifier + .fillMaxWidth() + .padding(all = 10.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Input_Field(value = NameText, onInputChanged = {NameText = it}, label = stringResource(id = R.string.parcel_name) ) + Input_Field(value = TrackText, onInputChanged = {TrackText = it}, label = stringResource(id = R.string.track_number)) + Input_Field(value = StatusText, onInputChanged = {StatusText = it}, label = stringResource(id = R.string.status)) + Input_Field(value = DescriptionText, onInputChanged = {DescriptionText = it}, label = stringResource(id = R.string.description)) + + Button( + onClick = { + val newParcel = Parcel(NameText, TrackText, StatusText, DescriptionText, id) + mainViewModel.insertParcel(newParcel) + }, + Modifier.padding(10.dp), + shape = RoundedCornerShape(15.dp) + ) { + Text( + text = "Создать", + fontSize = 22.sp + ) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun Input_Field(value: String, onInputChanged: (String) -> Unit, label: String){ + OutlinedTextField( + modifier = Modifier + .fillMaxWidth() + .padding(top = 10.dp), + value = value, + onValueChange = onInputChanged, + label = { + Text(label) + }, + shape = RoundedCornerShape(15.dp) + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/logic/composeui/ParcelList.kt b/app/src/main/java/com/example/pmu_2023/logic/composeui/ParcelList.kt new file mode 100644 index 0000000..7838cc7 --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/logic/composeui/ParcelList.kt @@ -0,0 +1,171 @@ +package com.example.pmu_2023.logic.composeui + +import android.util.Log +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.detectHorizontalDragGestures +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Edit +import androidx.compose.material.icons.outlined.Edit +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.collectAsState +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 androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import com.example.pmu_2023.Forms.Screen +import com.example.pmu_2023.database.MainViewModel +import com.example.pmu_2023.logic.model.Parcel +import com.example.pmu_2023.logic.model.User +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.withContext + +@Composable +fun RowScope.TableCell( + text: String, + weight: Float +) { + Text( + text = text, + Modifier + .weight(weight) + .padding(8.dp) + ) +} +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ParcelList(navController: NavController?, + id: Int, + mainViewModel: MainViewModel +) { + val itemsList = remember { mutableStateListOf()} + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + mainViewModel.getParcelsById(id).collect {data -> + itemsList.clear() + itemsList.addAll(data) + + } + } + } + + val openDialog = remember { mutableStateOf(false) } + var isDeleteParcel by remember { mutableStateOf(null)} + + if (openDialog.value) { + AlertDialog( + onDismissRequest = { + openDialog.value = false + }, + title = { Text(text = "Подтверждение действия") }, + text = { Text("Удалить выбранный элемент?") }, + confirmButton = { + Button( + onClick = { + openDialog.value = false + mainViewModel.deleteParcel(isDeleteParcel) + } + ) { + Text("OK", fontSize = 22.sp) + } + } + ) + } + + LazyColumn(modifier = Modifier + .fillMaxSize() + .padding(16.dp) ) + { + item { + Row( + Modifier + .background(Color.Gray) + .drawBehind { + + drawLine( + Color.Black, + Offset(0f, size.height), + Offset(size.width, size.height), + 4f + ) + }) { + TableCell(text = "№", weight = .1f) + TableCell(text = "Название", weight = .3f) + TableCell(text = "Номер отслеживания", weight = .6f) + } + } + + itemsIndexed(itemsList) + {index, item -> + val parcelViewId = Screen.ParcelView.route.replace("{id}", item.parcelId.toString()) + val parcelUpdId = Screen.UpdateParcel.route.replace("{id}", item.parcelId.toString()) + Row(Modifier + .fillMaxWidth() + .clickable { + navController?.navigate(parcelViewId) + } + .pointerInput(Unit) { + detectHorizontalDragGestures { change, dragAmount -> + isDeleteParcel = item + openDialog.value = true + } + } + .drawBehind { + drawLine( + Color.Black, + Offset(0f, size.height), + Offset(size.width, size.height), + 3f + ) + }, + verticalAlignment = Alignment.CenterVertically + ){ + TableCell(text = (index+1).toString(), weight = .1f) + TableCell(text = item.name, weight = .3f) + TableCell(text = item.trackNumber, weight = .5f) + IconButton( + onClick = { + navController?.navigate(parcelUpdId) + }, + Modifier.weight(.1f) + ) { + Icon( + imageVector = Icons.Filled.Edit, + contentDescription = "Edit", + tint = Color.Black + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/logic/composeui/ParcelView.kt b/app/src/main/java/com/example/pmu_2023/logic/composeui/ParcelView.kt new file mode 100644 index 0000000..7de560d --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/logic/composeui/ParcelView.kt @@ -0,0 +1,83 @@ +package com.example.pmu_2023.logic.composeui + +import com.example.pmu_2023.ui.theme.PMU_2023Theme + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.example.pmu_2023.Forms.Screen +import com.example.pmu_2023.R +import com.example.pmu_2023.database.MainViewModel +import com.example.pmu_2023.logic.model.Parcel +import com.example.pmu_2023.logic.model.User +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ParcelView( + id: Int, + mainViewModel: MainViewModel +) { + var parcel by remember { mutableStateOf(null) } + LaunchedEffect(Unit){ + val newData = withContext(Dispatchers.IO){ + mainViewModel.getParcelById(id) + } + parcel = newData + } + Column( + Modifier + .fillMaxWidth() + .padding(all = 10.dp) + ) { + parcel?.let { + OutlinedTextField(modifier = Modifier.fillMaxWidth(), + value = it.trackNumber, onValueChange = {}, readOnly = true, + label = { + Text(stringResource(id = R.string.track_number )) + }, + shape = RoundedCornerShape(15.dp) + ) + OutlinedTextField(modifier = Modifier.fillMaxWidth(), + value = it.name, onValueChange = {}, readOnly = true, + label = { + Text(stringResource(id = R.string.parcel_name )) + }, + shape = RoundedCornerShape(15.dp) + ) + OutlinedTextField(modifier = Modifier.fillMaxWidth(), + value = it.description, onValueChange = {}, readOnly = true, + label = { + Text(stringResource(id = R.string.description )) + }, + shape = RoundedCornerShape(15.dp) + ) + OutlinedTextField(modifier = Modifier.fillMaxWidth(), + value = it.status, onValueChange = {}, readOnly = true, + label = { + Text(stringResource(id = R.string.status )) + }, + shape = RoundedCornerShape(15.dp) + ) + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/logic/composeui/UpdateParcel.kt b/app/src/main/java/com/example/pmu_2023/logic/composeui/UpdateParcel.kt new file mode 100644 index 0000000..8c725f9 --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/logic/composeui/UpdateParcel.kt @@ -0,0 +1,84 @@ +package com.example.pmu_2023.logic.composeui + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +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.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.pmu_2023.Forms.Screen +import com.example.pmu_2023.R +import com.example.pmu_2023.database.MainViewModel +import com.example.pmu_2023.logic.model.Parcel +import com.example.pmu_2023.logic.model.User +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +@Composable +fun UpdateParcel( + id: Int, + mainViewModel: MainViewModel +) { + var NameText by rememberSaveable { mutableStateOf("") } + var TrackText by rememberSaveable { mutableStateOf("") } + var StatusText by rememberSaveable { mutableStateOf("") } + var DescriptionText by rememberSaveable { mutableStateOf("") } + + var data by remember { mutableStateOf(null)} + + LaunchedEffect(Unit){ + val newData = withContext(Dispatchers.IO){ + mainViewModel.getParcelById(id) + } + data = newData + + NameText = newData?.name.toString() + TrackText = newData?.trackNumber.toString() + StatusText = newData?.status.toString() + DescriptionText = newData?.description.toString() + } + + + Column( + Modifier + .fillMaxWidth() + .padding(all = 10.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Input_Field(value = NameText, onInputChanged = {NameText = it}, label = stringResource(id = R.string.parcel_name) ) + Input_Field(value = TrackText, onInputChanged = {TrackText = it}, label = stringResource(id = R.string.track_number)) + Input_Field(value = StatusText, onInputChanged = {StatusText = it}, label = stringResource(id = R.string.status)) + Input_Field(value = DescriptionText, onInputChanged = {DescriptionText = it}, label = stringResource(id = R.string.description)) + + Button( + onClick = { + val newParcel = Parcel(id, NameText, TrackText, StatusText, DescriptionText, data!!.userOwnerId) + mainViewModel.updateParcel(newParcel) + }, + Modifier.padding(10.dp), + shape = RoundedCornerShape(15.dp) + ) { + Text( + text = "Сохранить изменения", + fontSize = 22.sp + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/logic/composeui/UserProfileView.kt b/app/src/main/java/com/example/pmu_2023/logic/composeui/UserProfileView.kt new file mode 100644 index 0000000..431b124 --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/logic/composeui/UserProfileView.kt @@ -0,0 +1,92 @@ +package com.example.pmu_2023.logic.composeui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.Alignment.Companion.Center +import androidx.compose.ui.Alignment.Companion.CenterHorizontally +import androidx.compose.ui.Alignment.Companion.CenterStart +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.example.pmu_2023.R +import com.example.pmu_2023.database.MainViewModel +import com.example.pmu_2023.logic.model.Parcel +import com.example.pmu_2023.logic.model.User +import com.example.pmu_2023.ui.theme.Purple80 +import com.example.pmu_2023.ui.theme.PurpleGrey80 +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun UserProfileView( + id: Int, + mainViewModel: MainViewModel +){ + var user by remember { mutableStateOf(null) } + LaunchedEffect(Unit){ + val newData = withContext(Dispatchers.IO){ + mainViewModel.getUserById(id) + } + user = newData + } + Column( + modifier = Modifier + .fillMaxSize() + ) { + Box(modifier = Modifier + .fillMaxSize() + .padding(10.dp) + .clip(RoundedCornerShape(10.dp)) + .background(PurpleGrey80) + ){ + Column(Modifier + .padding(15.dp) + ) { + user?.let { + OutlinedTextField(modifier = Modifier.fillMaxWidth(), + value = it.name, onValueChange = {}, readOnly = true, + label = { + Text("Имя") + }, + shape = RectangleShape + ) + OutlinedTextField(modifier = Modifier.fillMaxWidth(), + value = it.address, onValueChange = {}, readOnly = true, + label = { + Text("Адрес") + }, + shape = RectangleShape + ) + OutlinedTextField(modifier = Modifier.fillMaxWidth(), + value = it.phone, onValueChange = {}, readOnly = true, + label = { + Text("Номер телефона") + }, + shape = RectangleShape + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/logic/dao/ParcelDao.kt b/app/src/main/java/com/example/pmu_2023/logic/dao/ParcelDao.kt new file mode 100644 index 0000000..ca71cf1 --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/logic/dao/ParcelDao.kt @@ -0,0 +1,27 @@ +package com.example.pmu_2023.logic.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.example.pmu_2023.logic.model.Parcel +import com.example.pmu_2023.logic.model.User +import kotlinx.coroutines.flow.Flow + +@Dao +interface ParcelDao { + @Insert + suspend fun insert(parcel: Parcel) + + @Update + suspend fun update(parcel: Parcel) + + @Delete + suspend fun delete(parcel: Parcel?) + + @Query("select * from parcels where userOwnerId = :uid") + fun getAllByUid(uid: Int?): Flow> + @Query("select * from parcels where parcelId = :id") + suspend fun getById(id: Int?): Parcel? +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/logic/dao/UserDao.kt b/app/src/main/java/com/example/pmu_2023/logic/dao/UserDao.kt new file mode 100644 index 0000000..8a60668 --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/logic/dao/UserDao.kt @@ -0,0 +1,33 @@ +package com.example.pmu_2023.logic.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Transaction +import androidx.room.Update +import com.example.pmu_2023.logic.model.User +import com.example.pmu_2023.logic.model.UserWithParcels +import kotlinx.coroutines.flow.Flow + +@Dao +interface UserDao { + @Insert + suspend fun insert(user: User) + + @Update + suspend fun update(user: User) + + @Delete + suspend fun delete(user: User) + + @Query("SELECT * FROM users WHERE fio = :name AND password = :passwd") + suspend fun getByLogin(name: String, passwd: String): User? + + @Query("SELECT * FROM users WHERE userId = :id") + suspend fun getById(id: Int?): User? + + @Transaction + @Query("SELECT * FROM users") + fun getUserWithParcels(): List +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/logic/model/Parcel.kt b/app/src/main/java/com/example/pmu_2023/logic/model/Parcel.kt new file mode 100644 index 0000000..33f3349 --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/logic/model/Parcel.kt @@ -0,0 +1,40 @@ +package com.example.pmu_2023.logic.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.Ignore +import androidx.room.PrimaryKey + +@Entity(tableName = "parcels") +data class Parcel( + @PrimaryKey(autoGenerate = true,) + val parcelId: Int?, + @ColumnInfo(name = "parcel_name") + val name: String, + @ColumnInfo(name = "track_number") + val trackNumber: String, + val status: String, + val description: String, + val userOwnerId: Int +){ + @Ignore + constructor( + name: String, + trackNumber: String, + status: String, + description: String, + userOwnerId: Int + ) : this(null, name, trackNumber, status, description, userOwnerId) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as Parcel + if (parcelId != other.parcelId) return false + return true + } + + override fun hashCode(): Int { + return parcelId ?: -1 + } +} diff --git a/app/src/main/java/com/example/pmu_2023/logic/model/User.kt b/app/src/main/java/com/example/pmu_2023/logic/model/User.kt new file mode 100644 index 0000000..b96b3db --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/logic/model/User.kt @@ -0,0 +1,37 @@ +package com.example.pmu_2023.logic.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.Ignore +import androidx.room.PrimaryKey + +@Entity(tableName = "users") +data class User( + @PrimaryKey(autoGenerate = true) + val userId: Int?, + @ColumnInfo(name = "fio") + val name: String, + val password: String, + val address: String, + val phone: String +){ + @Ignore + constructor( + name: String, + password: String, + address: String, + phone: String + ) : this(null, name, password, address, phone) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + other as User + if (userId != other.userId) return false + return true + } + + override fun hashCode(): Int { + return userId ?: -1 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/logic/model/UserWithParcels.kt b/app/src/main/java/com/example/pmu_2023/logic/model/UserWithParcels.kt new file mode 100644 index 0000000..7c6f4d9 --- /dev/null +++ b/app/src/main/java/com/example/pmu_2023/logic/model/UserWithParcels.kt @@ -0,0 +1,15 @@ +package com.example.pmu_2023.logic.model + +import androidx.room.Embedded +import androidx.room.Relation + + +data class UserWithParcels ( + @Embedded + val user: User, + @Relation( + parentColumn = "userId", + entityColumn = "userOwnerId" + ) + val parcels: List +) \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/parcel/composeui/ParcelList.kt b/app/src/main/java/com/example/pmu_2023/parcel/composeui/ParcelList.kt deleted file mode 100644 index d2fd16e..0000000 --- a/app/src/main/java/com/example/pmu_2023/parcel/composeui/ParcelList.kt +++ /dev/null @@ -1,88 +0,0 @@ -package com.example.pmu_2023.parcel.composeui - -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.Button -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawBehind -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.navigation.NavController -import com.example.pmu_2023.Forms.Screen -import com.example.pmu_2023.parcel.model.getParcels - -@Composable -fun RowScope.TableCell( - text: String, - weight: Float -) { - Text( - text = text, - Modifier - .weight(weight) - .padding(8.dp) - ) -} -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun ParcelList(navController: NavController?) { - LazyColumn(modifier = Modifier.fillMaxSize().padding(16.dp) ) - { - item { - Row(Modifier - .background(Color.Gray) - .drawBehind { - - drawLine( - Color.Black, - Offset(0f, size.height), - Offset(size.width, size.height), - 4f - ) - }) { - TableCell(text = "№", weight = .1f) - TableCell(text = "Название", weight = .3f) - TableCell(text = "Номер отслеживания", weight = .6f) - } - } - - itemsIndexed(getParcels() - ){index, item -> - val parcelId = Screen.ParcelView.route.replace("{id}", index.toString()) - Row(Modifier - .fillMaxWidth() - .clickable { - navController?.navigate(parcelId)} - .drawBehind { - drawLine( - Color.Black, - Offset(0f, size.height), - Offset(size.width, size.height), - 3f - )}, - verticalAlignment = Alignment.CenterVertically - ){ - TableCell(text = (index+1).toString(), weight = .1f) - TableCell(text = item.name, weight = .3f) - TableCell(text = item.track_number, weight = .6f) - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/parcel/composeui/ParcelView.kt b/app/src/main/java/com/example/pmu_2023/parcel/composeui/ParcelView.kt deleted file mode 100644 index 845a097..0000000 --- a/app/src/main/java/com/example/pmu_2023/parcel/composeui/ParcelView.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.example.pmu_2023.parcel.composeui - -import com.example.pmu_2023.parcel.model.getParcels -import com.example.pmu_2023.ui.theme.PMU_2023Theme - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.TextFieldDefaults -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.example.pmu_2023.ui.theme.MainBlue -import com.example.pmu_2023.R - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun ParcelView(id: Int) { - val parcel = getParcels()[id] - Column( - Modifier - .fillMaxWidth() - .padding(all = 10.dp) - ) { - OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = parcel.track_number, onValueChange = {}, readOnly = true, - label = { - Text(stringResource(id = R.string.track_number )) - }, - shape = RoundedCornerShape(15.dp) - ) - OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = parcel.name, onValueChange = {}, readOnly = true, - label = { - Text(stringResource(id = R.string.parcel_name )) - }, - shape = RoundedCornerShape(15.dp) - ) - OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = parcel.seller, onValueChange = {}, readOnly = true, - label = { - Text(stringResource(id = R.string.seller )) - }, - shape = RoundedCornerShape(15.dp) - ) - OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = parcel.description, onValueChange = {}, readOnly = true, - label = { - Text(stringResource(id = R.string.description )) - }, - shape = RoundedCornerShape(15.dp) - ) - } -} -@Preview -@Composable -fun ParcelViewPreview() { - PMU_2023Theme { - Surface( - color = MaterialTheme.colorScheme.background - ) { - ParcelView(id = 0) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/pmu_2023/parcel/model/Parcel.kt b/app/src/main/java/com/example/pmu_2023/parcel/model/Parcel.kt deleted file mode 100644 index 5e0bf47..0000000 --- a/app/src/main/java/com/example/pmu_2023/parcel/model/Parcel.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.example.pmu_2023.parcel.model - -import com.example.pmu_2023.R -import java.io.Serializable - -data class Parcel( - val track_number: String, - val name: String, - val seller: String, - val description: String -) : Serializable - -fun getParcels(): List { - return listOf( - Parcel("183475195719", "Чехол", "Иванов И.И.", "Sample text"), - Parcel("746350135109", "Защитное стекло", "Сидоров Ю.А.", "Sample text"), - Parcel("390459038506", "Игрушка", "Дмитриенко Е.В.", "Sample text") - ) -} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 02869fc..53c43de 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,11 +2,15 @@ PMU_2023 Номер отслеживания Название - Продавец + Статус Описание Заказчик Список посылок Информация о посылке Авторизация Регистрация + Добавить посылку + Изменить посылку + Профиль пользователя + Выход \ No newline at end of file