Compare commits

...

5 Commits
master ... lab3

26 changed files with 1551 additions and 3 deletions

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

BIN
Layout/DeliveryApp.fig Normal file

Binary file not shown.

View File

@ -1,6 +1,7 @@
plugins { plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id("kotlin-kapt")
} }
android { android {
@ -18,6 +19,11 @@ android {
vectorDrawables { vectorDrawables {
useSupportLibrary = true useSupportLibrary = true
} }
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
}
}
} }
buildTypes { buildTypes {
@ -46,8 +52,14 @@ android {
} }
} }
dependencies { 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") implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation("androidx.activity:activity-compose:1.7.0") implementation("androidx.activity:activity-compose:1.7.0")
@ -63,4 +75,12 @@ dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4") androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest") debugImplementation("androidx.compose.ui:ui-test-manifest")
// Room
val room_version = "2.5.1"
implementation("androidx.room:room-ktx:$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")
} }

View File

@ -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')"
]
}
}

View File

@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<application <application
android:name=".database.App"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"

Binary file not shown.

View File

@ -0,0 +1,141 @@
package com.example.pmu_2023.Forms
import android.content.res.Configuration
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
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.padding
import androidx.compose.foundation.layout.size
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.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.Observer
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController
import com.example.pmu_2023.Greeting
import com.example.pmu_2023.database.AppDatabase
import com.example.pmu_2023.database.MainViewModel
import com.example.pmu_2023.logic.model.User
import com.example.pmu_2023.ui.theme.MainBlue
import com.example.pmu_2023.ui.theme.PMU_2023Theme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.withContext
import androidx.lifecycle.viewModelScope
import com.example.pmu_2023.MainActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@Composable
fun Login(
navController: NavController?,
mainViewModel: MainViewModel
){
var LoginText by rememberSaveable { mutableStateOf("")}
var PassText by rememberSaveable { mutableStateOf("")}
var data by remember { mutableStateOf<User?>(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),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
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),
fontSize = 15.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)
.clickable { navController?.navigate("registration") },
textAlign = TextAlign.End
)
Spacer(Modifier.size(20.dp))
Button(
onClick = {
isLoading = true
},
shape = RoundedCornerShape(15.dp)
) {
Text(
text = "Войти",
fontSize = 22.sp
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Login_Field(value: String, onInputChanged: (String) -> Unit, name: String, label: String){
Column (modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)) {
Text(
text = name,
color = Color.White,
fontSize = 18.sp
)
TextField(
value = value,
onValueChange = onInputChanged,
placeholder = {
Text(text = label)
},
modifier = Modifier
.fillMaxWidth(),
shape = RoundedCornerShape(15.dp)
)
}
}

View File

@ -0,0 +1,310 @@
package com.example.pmu_2023.Forms
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
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.NavigationDrawerItem
import androidx.compose.material3.NavigationDrawerItemDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
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
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
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.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
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Topbar(
navController: NavHostController,
currentScreen: Screen?,
drawerState: DrawerState,
scope: CoroutineScope,
mainViewModel: MainViewModel
) {
TopAppBar(
colors = TopAppBarDefaults.smallTopAppBarColors(
containerColor = MaterialTheme.colorScheme.primary,
titleContentColor = MaterialTheme.colorScheme.onPrimary,
),
title = {
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(currentScreen?.resourceId ?: R.string.app_name),
textAlign = TextAlign.Center
)
},
navigationIcon = {
if (
navController.previousBackStackEntry != null
&& (currentScreen == null || !currentScreen.showInDrawer)
) {
IconButton(onClick = { navController.navigateUp() }) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = null,
tint = MaterialTheme.colorScheme.onPrimary
)
}
}
else if(
currentScreen != Screen.Login
&& currentScreen != Screen.Registration
) {
IconButton(onClick = {
scope.launch {
drawerState.open()
}
}) {
Icon(
imageVector = Icons.Default.Menu,
contentDescription = "Menu",
tint = MaterialTheme.colorScheme.onPrimary
)
}
}
},
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
)
}
}
}
)
}
@Composable
fun Navhost(
navController: NavHostController,
innerPadding: PaddingValues,
mainViewModel: MainViewModel,
modifier: Modifier = Modifier
) {
NavHost(
navController,
startDestination = Screen.Login.route,
modifier.padding(innerPadding)
) {
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"), 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(
mainViewModel: MainViewModel = viewModel(factory = MainViewModel.factory)
) {
val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
val currentScreen = currentDestination?.route?.let { Screen.getItem(it) }
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(
label = {
Text(stringResource(item.resourceId))
},
selected = index == selectedItemIndex,
onClick = {
val userId = item.route.replace("{id}", mainViewModel.curUid.value.toString())
navController.navigate(userId){
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
selectedItemIndex = index
scope.launch {
drawerState.close()
}
},
icon = {
Icon(
imageVector = if (index == selectedItemIndex) {
item.selectedIcon
} else item.unselectedIcon,
contentDescription = stringResource(item.resourceId)
)
},
modifier = Modifier
.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, mainViewModel)
},
) {innerPadding ->
Navhost(navController, innerPadding, mainViewModel)
}
}
}
@Preview
@Composable
fun MainFormPreview() {
PMU_2023Theme {
Surface(
color = MaterialTheme.colorScheme.background
) {
MainContent()
}
}
}

View File

@ -0,0 +1,113 @@
package com.example.pmu_2023.Forms
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
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
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
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?,
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(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(20.dp)
) {
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 = {
val newUser = User(NameText, PassText, AddressText, PhoneText)
mainViewModel.insertUser(newUser)
navController?.navigate("login")
},
shape = RoundedCornerShape(15.dp)
)
{
Text(
text = "Зарегистрироваться",
fontSize = 22.sp
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Registr_Field(value: String, onInputChanged: (String) -> Unit, name: String, label: String){
Column (modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)) {
OutlinedTextField(
value = value,
onValueChange = onInputChanged,
label = {
Text(text = label)
},
modifier = Modifier
.fillMaxWidth(),
shape = RoundedCornerShape(15.dp)
)
}
}

View File

@ -0,0 +1,56 @@
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
enum class Screen(
val route: String,
@StringRes val resourceId: Int,
val selectedIcon: ImageVector = Icons.Filled.Favorite,
val unselectedIcon: ImageVector = Icons.Filled.Favorite,
val showInDrawer: Boolean = true
) {
ParcelList(
"parcel-list/{id}", R.string.parcel_list_title, Icons.Filled.List, Icons.Outlined.List
),
Login(
"login", R.string.login_title
),
Registration(
"registration", R.string.registration_title
),
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? {
val findRoute = route.split("/").first()
return values().find { value -> value.route.startsWith(findRoute) }
}
}
}

View File

@ -10,6 +10,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import com.example.pmu_2023.Forms.MainContent
import com.example.pmu_2023.ui.theme.PMU_2023Theme import com.example.pmu_2023.ui.theme.PMU_2023Theme
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@ -19,7 +20,7 @@ class MainActivity : ComponentActivity() {
PMU_2023Theme { PMU_2023Theme {
// A surface container using the 'background' color from the theme // A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) { Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
Greeting("Android") MainContent()
} }
} }
} }

View File

@ -0,0 +1,7 @@
package com.example.pmu_2023.database
import android.app.Application
class App : Application() {
val database by lazy { AppDatabase.createDataBase(this) }
}

View File

@ -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()
}
}
}

View File

@ -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<Int?>(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<List<Parcel>> {
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 <T : ViewModel> create(
modelClass: Class<T>,
extras: CreationExtras): T {
val database = (checkNotNull(extras[APPLICATION_KEY]) as App).database
return MainViewModel(database) as T
}
}
}
}

View File

@ -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)
)
}

View File

@ -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<Parcel>()}
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<Parcel?>(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
)
}
}
}
}
}

View File

@ -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<Parcel?>(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)
)
}
}
}

View File

@ -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<Parcel?>(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
)
}
}
}

View File

@ -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<User?>(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
)
}
}
}
}
}

View File

@ -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<List<Parcel>>
@Query("select * from parcels where parcelId = :id")
suspend fun getById(id: Int?): Parcel?
}

View File

@ -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<UserWithParcels>
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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<Parcel>
)

View File

@ -8,4 +8,6 @@ val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4) val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71) val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260) val Pink40 = Color(0xFF7D5260)
val MainBlue = Color(0xFF6583D2)

View File

@ -1,3 +1,16 @@
<resources> <resources>
<string name="app_name">PMU_2023</string> <string name="app_name">PMU_2023</string>
<string name="track_number">Номер отслеживания</string>
<string name="parcel_name">Название</string>
<string name="status">Статус</string>
<string name="description">Описание</string>
<string name="client">Заказчик</string>
<string name="parcel_list_title">Список посылок</string>
<string name="parcel_view_title">Информация о посылке</string>
<string name="login_title">Авторизация</string>
<string name="registration_title">Регистрация</string>
<string name="parcel_create_title">Добавить посылку</string>
<string name="parcel_update_title">Изменить посылку</string>
<string name="user_view_title">Профиль пользователя</string>
<string name="quit_title">Выход</string>
</resources> </resources>