Лабораторная 3. Финал.

This commit is contained in:
Артем Харламов 2024-02-10 18:07:05 +04:00
parent 7ec106a409
commit 6316b927b7
25 changed files with 1135 additions and 274 deletions

View File

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

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">
<application
android:name=".database.App"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"

Binary file not shown.

View File

@ -1,6 +1,7 @@
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
@ -19,13 +20,20 @@ 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
@ -33,20 +41,54 @@ 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?){
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),
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)
},

View File

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

View File

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

View File

@ -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? {

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

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

View File

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

View File

@ -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<Parcel> {
return listOf(
Parcel("183475195719", "Чехол", "Иванов И.И.", "Sample text"),
Parcel("746350135109", "Защитное стекло", "Сидоров Ю.А.", "Sample text"),
Parcel("390459038506", "Игрушка", "Дмитриенко Е.В.", "Sample text")
)
}

View File

@ -2,11 +2,15 @@
<string name="app_name">PMU_2023</string>
<string name="track_number">Номер отслеживания</string>
<string name="parcel_name">Название</string>
<string name="seller">Продавец</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>