Лабораторная 2. Навигация.

This commit is contained in:
Артем Харламов 2024-01-31 23:02:09 +04:00
parent 8aef08d754
commit 7ec106a409
10 changed files with 613 additions and 39 deletions

View File

@ -47,7 +47,7 @@ android {
}
dependencies {
implementation("androidx.navigation:navigation-compose:2.6.0")
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation("androidx.activity:activity-compose:1.7.0")
@ -63,4 +63,12 @@ dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
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")
implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.room:room-paging:$room_version")
}

View File

@ -1,15 +1,21 @@
package com.example.pmu_2023.Forms
import android.content.res.Configuration
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
@ -27,53 +33,44 @@ 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.Greeting
import com.example.pmu_2023.ui.theme.MainBlue
@Preview
import com.example.pmu_2023.ui.theme.PMU_2023Theme
@Composable
fun Login(){
fun Login(navController: NavController?){
Column (
modifier = Modifier
.fillMaxSize()
.background(MainBlue),
modifier = Modifier.fillMaxSize().padding(all = 10.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
verticalArrangement = Arrangement.Center
) {
Login_Field(name = "Email", label = "Введите адрес электронной почты...")
Login_Field(name = "Password", label = "Введите пароль...")
Text(
text = "Авторизация",
fontSize = 40.sp,
fontWeight = FontWeight.Bold,
color = Color.White,
)
Column(
text = "Регистрация",
style = TextStyle(textDecoration = TextDecoration.Underline),
fontSize = 15.sp,
modifier = Modifier
.fillMaxWidth()
.padding(20.dp)
) {
Login_Field(name = "Email", label = "Введите адрес электронной почты...")
Login_Field(name = "Password", label = "Введите пароль...")
Text(
text = "Регистрация",
style = TextStyle(textDecoration = TextDecoration.Underline),
fontSize = 15.sp,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp),
textAlign = TextAlign.End
)
}
Button(
onClick = { /*TODO*/ },
shape = RoundedCornerShape(15.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color.White, contentColor = Color.Black)
.padding(top = 10.dp)
.clickable { navController?.navigate("registration") },
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
)
) {
Text(
text = "Войти",
fontSize = 22.sp
)
}
}
}
@ -81,7 +78,7 @@ fun Login(){
@Composable
fun Login_Field(name: String, label: String){
var sample_text by remember { mutableStateOf("") }
var sampletext by remember { mutableStateOf("") }
Column (modifier = Modifier
.fillMaxWidth()
@ -92,9 +89,9 @@ fun Login_Field(name: String, label: String){
fontSize = 18.sp
)
TextField(
value = sample_text,
onValueChange = { sample_text = it},
label = {
value = sampletext,
onValueChange = { sampletext = it},
placeholder = {
Text(text = label)
},
modifier = Modifier

View File

@ -0,0 +1,198 @@
package com.example.pmu_2023.Forms
import android.content.res.Configuration
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
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.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
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.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.parcel.composeui.ParcelList
import com.example.pmu_2023.parcel.composeui.ParcelView
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
) {
TopAppBar(
colors = TopAppBarDefaults.smallTopAppBarColors(
containerColor = MaterialTheme.colorScheme.primary,
titleContentColor = MaterialTheme.colorScheme.onPrimary,
),
title = {
Text(stringResource(currentScreen?.resourceId ?: R.string.app_name))
},
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
)
}
}
},
)
}
@Composable
fun Navhost(
navController: NavHostController,
innerPadding: PaddingValues, 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.ParcelView.route,
arguments = listOf(navArgument("id") { type = NavType.IntType })
) { backStackEntry ->
backStackEntry.arguments?.let { ParcelView(it.getInt("id")) }
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainContent() {
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 {
Spacer(modifier = Modifier.height(16.dp))
Screen.DrawerItems.forEachIndexed { index, item ->
NavigationDrawerItem(
label = {
Text(stringResource(item.resourceId))
},
selected = index == selectedItemIndex,
onClick = {
navController.navigate(item.route){
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)
)
}
}
},
drawerState = drawerState
) {
Scaffold(
topBar = {
Topbar(navController, currentScreen, drawerState, scope)
},
) {innerPadding ->
Navhost(navController, innerPadding)
}
}
}
@Preview
@Composable
fun MainFormPreview() {
PMU_2023Theme {
Surface(
color = MaterialTheme.colorScheme.background
) {
MainContent()
}
}
}

View File

@ -0,0 +1,136 @@
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.getValue
import androidx.compose.runtime.setValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
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.ui.theme.MainBlue
@Composable
fun Registration(navController: NavController?){
val list = listOf("Поставщик", "Покупатель")
val expanded = remember { mutableStateOf(false) }
val currentValue = remember { mutableStateOf(list[0]) }
Column (
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
Column(
modifier = Modifier
.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 = "Пароль")
}
Button(
onClick = {navController?.navigate("parcel-list")},
shape = RoundedCornerShape(15.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color.White, contentColor = Color.Black)
)
{
Text(
text = "Зарегистрироваться",
fontSize = 22.sp
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Registr_Field(label: String){
var sample_text by remember { mutableStateOf("") }
Column (modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)) {
OutlinedTextField(
value = sample_text,
onValueChange = { sample_text = it },
label = {
Text(
text = label,
fontSize = 18.sp)
},
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
)
)
}
}

View File

@ -0,0 +1,42 @@
package com.example.pmu_2023.Forms
import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons
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.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", 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
);
companion object {
val DrawerItems = listOf(
ParcelList,
)
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.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.pmu_2023.Forms.MainContent
import com.example.pmu_2023.ui.theme.PMU_2023Theme
class MainActivity : ComponentActivity() {
@ -19,7 +20,7 @@ class MainActivity : ComponentActivity() {
PMU_2023Theme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
Greeting("Android")
MainContent()
}
}
}

View File

@ -0,0 +1,88 @@
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

@ -0,0 +1,76 @@
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

@ -0,0 +1,19 @@
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

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