Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
c9c689dbbc | |||
2fa37312d6 | |||
c358c953ba | |||
2884f2b4eb | |||
4226f90712 | |||
ee980fe775 | |||
e63c1c1df0 | |||
e96160ad7d | |||
b46391b649 | |||
e903f1729c | |||
dc5cc2e862 | |||
0cc1d56a3a | |||
96d09edf51 | |||
36c001ca2e | |||
25cdd9b083 | |||
a11e81ab27 | |||
e3bc68c14c | |||
eb79619b6c | |||
9565e46d37 | |||
bce45a28f0 | |||
eb3bc2ea3d | |||
3e68677d23 | |||
d9cb297f65 | |||
0b8c882823 | |||
4b3c61ca06 | |||
1984f32b8a | |||
b622cb235b | |||
9c8d38f9f4 | |||
4df3eff3b1 | |||
61b1507973 | |||
cf8aefb83d | |||
62854ccff8 | |||
a9f21b28d2 |
@ -1,6 +1,9 @@
|
||||
import org.jetbrains.kotlin.kapt3.base.Kapt.kapt
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("kotlin-kapt")
|
||||
}
|
||||
|
||||
android {
|
||||
@ -30,11 +33,11 @@ android {
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
jvmTarget = "17"
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
@ -54,6 +57,27 @@ dependencies {
|
||||
implementation("androidx.navigation:navigation-compose:2.7.4")
|
||||
implementation("androidx.compose.material:material:1.5.4")
|
||||
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
|
||||
|
||||
implementation("androidx.room:room-ktx:2.6.0")
|
||||
kapt("androidx.room:room-compiler:2.6.0")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
|
||||
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.4.0")
|
||||
|
||||
val paging_version = "3.1.1"
|
||||
implementation ("androidx.paging:paging-runtime:$paging_version")
|
||||
// alternatively - without Android dependencies for tests
|
||||
testImplementation ("androidx.paging:paging-common:$paging_version")
|
||||
// optional - RxJava2 support
|
||||
implementation ("androidx.paging:paging-rxjava2:$paging_version")
|
||||
// optional - RxJava3 support
|
||||
implementation ("androidx.paging:paging-rxjava3:$paging_version")
|
||||
// optional - Guava ListenableFuture support
|
||||
implementation ("androidx.paging:paging-guava:$paging_version")
|
||||
// optional - Jetpack Compose integration
|
||||
implementation ("androidx.paging:paging-compose:1.0.0-alpha18")
|
||||
|
||||
|
||||
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")
|
||||
|
@ -8,6 +8,7 @@
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:name=".BicycleRentApplication"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.LabWork"
|
||||
|
@ -0,0 +1,14 @@
|
||||
package com.example.labwork
|
||||
|
||||
import android.app.Application
|
||||
import com.example.labwork.database.AppContainer
|
||||
import com.example.labwork.database.AppDataContainer
|
||||
|
||||
class BicycleRentApplication : Application() {
|
||||
lateinit var container: AppContainer
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
container = AppDataContainer(this)
|
||||
}
|
||||
}
|
@ -3,20 +3,30 @@ package com.example.labwork
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.example.labwork.button_navigation.MainScreen
|
||||
import com.example.labwork.database.AppDatabase
|
||||
import com.example.labwork.ui.theme.LabWorkTheme
|
||||
import com.example.labwork.viewmodel.AppViewModelProvider
|
||||
import com.example.labwork.viewmodel.BicycleViewModel
|
||||
import com.example.labwork.viewmodel.UserViewModel
|
||||
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
private val userViewModel: UserViewModel by viewModels()
|
||||
private val bicycleViewModel: BicycleViewModel by viewModels()
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent {
|
||||
LabWorkTheme {
|
||||
MainScreen()
|
||||
MainScreen(viewModel(factory = AppViewModelProvider.Factory), userViewModel = viewModel(factory = AppViewModelProvider.Factory))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,18 +4,33 @@ import android.annotation.SuppressLint
|
||||
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.example.labwork.database.DAO.BicycleDao
|
||||
import com.example.labwork.database.DAO.UserDao
|
||||
import com.example.labwork.repository.OfflineBicycleRepository
|
||||
import com.example.labwork.repository.OfflineUserRepository
|
||||
import com.example.labwork.viewmodel.AppViewModelProvider
|
||||
import com.example.labwork.viewmodel.BicycleViewModel
|
||||
import com.example.labwork.viewmodel.UserViewModel
|
||||
|
||||
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
|
||||
@Composable
|
||||
fun MainScreen() {
|
||||
fun MainScreen(bicycleViewModel: BicycleViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
userViewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val navController = rememberNavController()
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
SlideNavigation(navController = navController)
|
||||
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
SlideNavigation(navController = navController)
|
||||
}
|
||||
) {
|
||||
SlideGraph(navHostController = navController)
|
||||
SlideGraph(
|
||||
navHostController = navController,
|
||||
bicycleViewModel = bicycleViewModel,
|
||||
userViewModel = userViewModel
|
||||
)
|
||||
}
|
||||
}
|
@ -1,16 +1,44 @@
|
||||
package com.example.labwork.button_navigation
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
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.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.labwork.models.getItemProducts
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.paging.LoadState
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import com.example.labwork.pages.ListInfo
|
||||
import com.example.labwork.pages.ListProduct
|
||||
import com.example.labwork.pages.RegisteryOrLogin
|
||||
import com.example.labwork.pages.product.FormNewProduct
|
||||
import com.example.labwork.pages.product.ListProduct
|
||||
import com.example.labwork.pages.user.RegisteryOrLogin
|
||||
import com.example.labwork.ui.theme.LightBluePolitech
|
||||
import com.example.labwork.viewmodel.AppViewModelProvider
|
||||
import com.example.labwork.viewmodel.BicycleScreenViewModel
|
||||
import com.example.labwork.viewmodel.BicycleViewModel
|
||||
import com.example.labwork.viewmodel.UserViewModel
|
||||
|
||||
@Composable
|
||||
fun ScreenInfo() {
|
||||
@ -18,22 +46,58 @@ fun ScreenInfo() {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ScreenProfile() {
|
||||
RegisteryOrLogin()
|
||||
fun ScreenProfile(userViewModel: UserViewModel, navHostController: NavHostController, bicycleViewModel: BicycleViewModel) {
|
||||
RegisteryOrLogin(userViewModel, navHostController, bicycleViewModel)
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun ScreenListProduct() {
|
||||
LazyColumn(
|
||||
fun ScreenListProduct(
|
||||
bicycleViewModel: BicycleViewModel,
|
||||
navHostController: NavHostController,
|
||||
bicycleScreenViewModel: BicycleScreenViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val bicycles = bicycleScreenViewModel.bicycles.collectAsLazyPagingItems()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
bicycleViewModel.fetchBicycles()
|
||||
}
|
||||
|
||||
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxHeight().padding(bottom = 65.dp)
|
||||
) {
|
||||
itemsIndexed(
|
||||
getItemProducts()
|
||||
)
|
||||
{
|
||||
_, item ->
|
||||
ListProduct(item = item)
|
||||
FormNewProduct(bicycleViewModel, navHostController)
|
||||
|
||||
LazyColumn {
|
||||
items(count = bicycles.itemCount) { index ->
|
||||
val bicycle = bicycles[index]
|
||||
if (bicycle != null) {
|
||||
ListProduct(
|
||||
item = bicycle,
|
||||
bicycleViewModel = bicycleViewModel,
|
||||
navHostController = navHostController
|
||||
)
|
||||
}
|
||||
}
|
||||
bicycles.apply {
|
||||
when {
|
||||
loadState.refresh is LoadState.Loading -> {
|
||||
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = LightBluePolitech) }
|
||||
}
|
||||
loadState.append is LoadState.Loading -> {
|
||||
item { CircularProgressIndicator(modifier = Modifier.fillParentMaxSize(), color = LightBluePolitech) }
|
||||
}
|
||||
loadState.refresh is LoadState.Error -> {
|
||||
val err = bicycles.loadState.refresh as LoadState.Error
|
||||
item { Text(err.error.localizedMessage) }
|
||||
}
|
||||
loadState.append is LoadState.Error -> {
|
||||
val err = bicycles.loadState.append as LoadState.Error
|
||||
item { Text(err.error.localizedMessage) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,25 +2,33 @@ package com.example.labwork.button_navigation
|
||||
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import com.example.labwork.repository.OfflineBicycleRepository
|
||||
import com.example.labwork.repository.OfflineUserRepository
|
||||
import com.example.labwork.viewmodel.AppViewModelProvider
|
||||
import com.example.labwork.viewmodel.BicycleViewModel
|
||||
import com.example.labwork.viewmodel.UserViewModel
|
||||
|
||||
|
||||
@Composable
|
||||
fun SlideGraph(
|
||||
navHostController: NavHostController
|
||||
navHostController: NavHostController,
|
||||
bicycleViewModel: BicycleViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
userViewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
NavHost(navController = navHostController, startDestination = "Profile"){
|
||||
|
||||
composable("Profile"){
|
||||
ScreenProfile()
|
||||
NavHost(navController = navHostController, startDestination = "Profile") {
|
||||
composable("Profile") {
|
||||
ScreenProfile(userViewModel, bicycleViewModel = bicycleViewModel, navHostController = navHostController)
|
||||
}
|
||||
composable("Info"){
|
||||
composable("Info") {
|
||||
ScreenInfo()
|
||||
}
|
||||
composable("ListProduct"){
|
||||
ScreenListProduct()
|
||||
composable("ListProduct") {
|
||||
ScreenListProduct(bicycleViewModel, navHostController = navHostController)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.example.labwork.database
|
||||
|
||||
import android.content.Context
|
||||
import com.example.labwork.repository.BicycleRepository
|
||||
import com.example.labwork.repository.OfflineBicycleRepository
|
||||
import com.example.labwork.repository.OfflineUserRepository
|
||||
import com.example.labwork.repository.UserRepository
|
||||
|
||||
interface AppContainer {
|
||||
val userRepository: UserRepository
|
||||
val bicycleRepository: BicycleRepository
|
||||
}
|
||||
|
||||
class AppDataContainer(private val context: Context) : AppContainer {
|
||||
override val userRepository: UserRepository by lazy {
|
||||
OfflineUserRepository(AppDatabase.getInstance(context).userDao())
|
||||
}
|
||||
override val bicycleRepository: BicycleRepository by lazy {
|
||||
OfflineBicycleRepository(AppDatabase.getInstance(context).bicycleDao())
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TIMEOUT = 5000L
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.example.labwork.database
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.example.labwork.database.DAO.BicycleDao
|
||||
import com.example.labwork.database.DAO.UserDao
|
||||
import com.example.labwork.models.Bicycle
|
||||
import com.example.labwork.models.User
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
@Database(entities = [User::class, Bicycle::class], version = 1)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun userDao(): UserDao
|
||||
abstract fun bicycleDao(): BicycleDao
|
||||
|
||||
companion object {
|
||||
private var instance: AppDatabase? = null
|
||||
|
||||
fun getInstance(context: Context): AppDatabase {
|
||||
if (instance == null) {
|
||||
synchronized(AppDatabase::class) {
|
||||
instance = Room.databaseBuilder(
|
||||
context.applicationContext,
|
||||
AppDatabase::class.java,
|
||||
"my-database"
|
||||
)
|
||||
.addCallback(object : RoomDatabase.Callback() {
|
||||
override fun onCreate(db: SupportSQLiteDatabase) {
|
||||
super.onCreate(db)
|
||||
Executors.newSingleThreadExecutor().execute {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
populateDatabase(instance!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.build()
|
||||
}
|
||||
}
|
||||
return instance!!
|
||||
}
|
||||
|
||||
private suspend fun populateDatabase(database: AppDatabase) {
|
||||
val userDao = database.userDao()
|
||||
val bicycleDao = database.bicycleDao()
|
||||
|
||||
// Создание пользователей
|
||||
val user1 = User(null, "John Doe", "john.doe@example.com", "password123")
|
||||
val user2 = User(null, "Jane Smith", "jane.smith@example.com", "password456")
|
||||
|
||||
// Вставка пользователей в базу данных
|
||||
userDao.insertUser(user1)
|
||||
userDao.insertUser(user2)
|
||||
|
||||
// Создание велосипедов
|
||||
val bicycle1 = Bicycle(brand = "Trek", model = "Велосипед 1", color = "Black", userId = 1, id = null)
|
||||
val bicycle2 = Bicycle(brand = "Trek", model = "Велосипед 2", color = "Black", userId = null, id = null)
|
||||
val bicycle3 = Bicycle(brand = "Trek", model = "Велосипед 3", color = "Black", userId = 1, id = null)
|
||||
val bicycle4 = Bicycle(brand = "Trek", model = "Велосипед 4", color = "Black", userId = null, id = null)
|
||||
val bicycle5 = Bicycle(brand = "Trek", model = "Велосипед 5", color = "Black", userId = null, id = null)
|
||||
val bicycle6 = Bicycle(brand = "Trek", model = "Велосипед 6", color = "Black", userId = null, id = null)
|
||||
|
||||
// Вставка велосипедов в базу данных
|
||||
bicycleDao.insertBicycle(bicycle1)
|
||||
bicycleDao.insertBicycle(bicycle2)
|
||||
bicycleDao.insertBicycle(bicycle3)
|
||||
bicycleDao.insertBicycle(bicycle4)
|
||||
bicycleDao.insertBicycle(bicycle5)
|
||||
bicycleDao.insertBicycle(bicycle6)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,32 @@
|
||||
package com.example.labwork.database.DAO
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.example.labwork.models.Bicycle
|
||||
|
||||
@Dao
|
||||
interface BicycleDao {
|
||||
@Insert
|
||||
suspend fun insertBicycle(bicycle: Bicycle)
|
||||
|
||||
@Update
|
||||
suspend fun updateBicycle(bicycle: Bicycle)
|
||||
|
||||
@Delete
|
||||
suspend fun deleteBicycle(bicycle: Bicycle)
|
||||
|
||||
@Query("SELECT * FROM bicycles")
|
||||
suspend fun getAllBicycles(): List<Bicycle>
|
||||
|
||||
@Query("SELECT * FROM bicycles WHERE id = :bicycleId")
|
||||
suspend fun getBicycleById(bicycleId: Int?): Bicycle
|
||||
|
||||
@Query("SELECT * FROM bicycles WHERE userId = :userId")
|
||||
suspend fun getBicyclesByUserId(userId: Int): List<Bicycle>
|
||||
|
||||
@Query("SELECT * FROM bicycles ORDER BY id ASC LIMIT :limit OFFSET :offset")
|
||||
suspend fun getBicycles(limit: Int, offset: Int): List<Bicycle>
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.example.labwork.database.DAO
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.example.labwork.models.User
|
||||
|
||||
@Dao
|
||||
interface UserDao {
|
||||
@Insert
|
||||
suspend fun insertUser(user: User)
|
||||
|
||||
@Update
|
||||
suspend fun updateUser(user: User)
|
||||
|
||||
@Delete
|
||||
suspend fun deleteUser(user: User)
|
||||
|
||||
@Query("SELECT * FROM users")
|
||||
suspend fun getAllUsers(): List<User>
|
||||
|
||||
@Query("SELECT * FROM users WHERE id = :userId")
|
||||
suspend fun getUserById(userId: Int): User
|
||||
|
||||
@Query("SELECT * FROM users WHERE email = :email")
|
||||
suspend fun getUserByEmail(email: String): User
|
||||
|
||||
@Query("SELECT password FROM users WHERE email = :email")
|
||||
suspend fun getPasswordByEmail(email: String): String
|
||||
|
||||
@Query("SELECT * FROM users WHERE email = :email AND password = :password")
|
||||
suspend fun getUserByEmailAndPassword(email: String, password: String): User?
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.example.labwork.database.Paging
|
||||
|
||||
import android.util.Log
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.example.labwork.database.DAO.BicycleDao
|
||||
import com.example.labwork.models.Bicycle
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
class BicyclePagingSource(private val dao: BicycleDao,
|
||||
) : PagingSource<Int, Bicycle>() {
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Bicycle> {
|
||||
val page = params.key ?: 0
|
||||
|
||||
return try {
|
||||
Log.d("MainPagingSource", "load: $page")
|
||||
val entities = dao.getBicycles(params.loadSize, page * params.loadSize)
|
||||
if (page != 0) delay(2000)
|
||||
LoadResult.Page(
|
||||
data = entities,
|
||||
prevKey = if (page == 0) null else page - 1,
|
||||
nextKey = if (entities.isEmpty()) null else page + 1
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
LoadResult.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
override val jumpingSupported: Boolean = true
|
||||
|
||||
override fun getRefreshKey(state: PagingState<Int, Bicycle>): Int? {
|
||||
return state.anchorPosition?.let { anchorPosition ->
|
||||
val anchorPage = state.closestPageToPosition(anchorPosition)
|
||||
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
|
||||
}
|
||||
}
|
||||
}
|
19
app/src/main/java/com/example/labwork/models/Bicycle.kt
Normal file
19
app/src/main/java/com/example/labwork/models/Bicycle.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package com.example.labwork.models
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "bicycles",
|
||||
foreignKeys = [ForeignKey(entity = User::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["userId"],
|
||||
onDelete = ForeignKey.SET_NULL)])
|
||||
data class Bicycle(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int?,
|
||||
var brand: String,
|
||||
var model: String,
|
||||
var color: String,
|
||||
val userId: Int?
|
||||
)
|
@ -1,25 +0,0 @@
|
||||
package com.example.labwork.models
|
||||
|
||||
import com.example.labwork.R
|
||||
import java.io.Serializable
|
||||
|
||||
data class ItemProduct(
|
||||
val imageId: Int,
|
||||
val name: String,
|
||||
val about: String
|
||||
) : Serializable
|
||||
|
||||
fun getItemProducts(): List<ItemProduct> {
|
||||
return listOf(
|
||||
ItemProduct(R.drawable.baseline_menu_book,"Золотая рыбка","Старик трудолюбивый (трижды забрасывал невод), добрый (отпустил просящую о пощаде единственную добычу), покорный (не перечит жене). Появление волшебной рыбки проявило алчную натуру женщины: требовательную, грубую, жаждущую от корыта до возможности быть владычицей морскою."),
|
||||
ItemProduct(R.drawable.baseline_menu_book,"451° по Фаренгейту","Мастер мирового масштаба, совмещающий в литературе несовместимое. Создатель таких ярчайших шедевров, как \"Марсианские хроники\", \"451° по Фаренгейту"),
|
||||
ItemProduct(R.drawable.baseline_menu_book,"1984","Своеобразный антипод второй великой антиутопии XX века - \"О дивный новый мир\" Олдоса Хаксли. Что, в сущности, страшнее: доведенное до абсурда \"общество потребления\""),
|
||||
ItemProduct(R.drawable.baseline_menu_book,"Мастер и Маргарита","Один из самых загадочных и удивительных романов XX века. «Мастер и Маргарита» – визитная карточка Михаила Булгакова. Более десяти лет он работал над"),
|
||||
ItemProduct(R.drawable.baseline_menu_book,"Шантарам","Представляем читателю один из самых поразительных романов начала XXI века (в 2015 году получивший долгожданное продолжение – «Тень горы»)."),
|
||||
ItemProduct(R.drawable.baseline_menu_book,"Цветы для Элджернона","Сорок лет назад это считалось фантастикой. Сорок лет назад это читалось как фантастика."),
|
||||
ItemProduct(R.drawable.baseline_menu_book,"Три товарища","Трое друзей - Робби, отчаянный автогонщик Кестер и \"последний романтик\" Ленц прошли Первую мировую войну."),
|
||||
ItemProduct(R.drawable.baseline_menu_book,"Портрет Дориана Грея","«Портрет Дориана Грея» – одно из величайших произведений последних полутора столетий, роман, который пытались запретить, а автора осуждали"),
|
||||
ItemProduct(R.drawable.baseline_menu_book,"Маленький принц","«Маленький принц» — аллегорическая повесть, наиболее известное произведение Антуана де Сент-Экзюпери. ")
|
||||
|
||||
)
|
||||
}
|
15
app/src/main/java/com/example/labwork/models/User.kt
Normal file
15
app/src/main/java/com/example/labwork/models/User.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package com.example.labwork.models
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "users")
|
||||
data class User(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int?,
|
||||
var name: String,
|
||||
var email: String,
|
||||
var password: String,
|
||||
)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.example.labwork.pages
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
@ -55,7 +54,7 @@ fun ListInfo() {
|
||||
.shadow(16.dp, shape = RoundedCornerShape(8.dp))
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.logo_ulstu),
|
||||
painter = painterResource(id = R.drawable.baseline_directions_bike_24),
|
||||
contentDescription = "Menu Image",
|
||||
Modifier.fillMaxSize()
|
||||
)
|
||||
@ -90,7 +89,7 @@ fun ListInfo() {
|
||||
onClick = { selectedTab = 1 }
|
||||
) {
|
||||
Text(
|
||||
text = "Библиотека",
|
||||
text = "Аренда велосипедов",
|
||||
modifier = Modifier.padding(8.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
@ -110,7 +109,7 @@ fun ListInfo() {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
when (selectedTab) {
|
||||
0 -> InfoUniver()
|
||||
1 -> InfoBiblio()
|
||||
1 -> InfoBike()
|
||||
2 -> InfoProgrammer()
|
||||
}
|
||||
}
|
||||
@ -120,7 +119,9 @@ fun ListInfo() {
|
||||
@Composable
|
||||
fun InfoUniver() {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize().padding(bottom = 65.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(bottom = 65.dp),
|
||||
contentPadding = PaddingValues(16.dp)
|
||||
) {
|
||||
item {
|
||||
@ -210,9 +211,11 @@ fun InfoUniver() {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InfoBiblio() {
|
||||
fun InfoBike() {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize().padding(bottom = 65.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(bottom = 65.dp),
|
||||
contentPadding = PaddingValues(16.dp)
|
||||
) {
|
||||
item {
|
||||
@ -226,28 +229,26 @@ fun InfoBiblio() {
|
||||
Text("Технический университет подобным сокровищем обладает!",modifier = Modifier.padding(bottom = 16.dp))
|
||||
|
||||
Text(
|
||||
text = "Наша Научная библиотека соответствует всем современным требованиям технического вуза. Постоянно пополняющийся библиотечный фонд составляет более 1100 тыс. единиц хранения, формируется по специальностям (с учетом всех направлений учебного и научного процессов университета) изданиями, отвечающими требованиям программ высшей школы. В фонде имеются зарубежные издания, диссертации, авторефераты, документы на электронных носителях. Пользователям предоставляется доступ к электронным ресурсам удалённого доступа, входящим в состав электронно-библиотечной системы «ЭльбруС» УлГТУ."
|
||||
text = "Аренда велосипедов стала популярной и удобной системой передвижения в нашем университете. " +
|
||||
"Это новая и интересная инициатива, которая предоставляет возможность студентам и персоналу " +
|
||||
"университета арендовать велосипеды для своих транспортных нужд."
|
||||
,modifier = Modifier.padding(bottom = 16.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "К услугам читателей: зал каталогов, aвонементы научной и учебной литературы, общий читальный зал, отдел экономической и иностранной литературы. Выдача комплектов учебников первокурсникам, зал для аспирантов и преподавателей, зал периодических изданий, читальный зал машиностроительного факультета, читальный зал электронных ресурсов, отдел художественной литературы, научно-библиографический отдел, библиотека Института авиационных технологий и управления, Барышского колледжа — филиала УлГТУ."
|
||||
text = "Система аренды велосипедов в университете работает через специальное мобильное приложение, " +
|
||||
"которое позволяет зарегистрированным пользователям легко и быстро арендовать велосипеды. " +
|
||||
"Велосипеды предоставляются в зоне университета и пользуются большим спросом среди студентов, " +
|
||||
"которые хотят быстро и удобно перемещаться по территорий и её окрестности."
|
||||
,modifier = Modifier.padding(bottom = 16.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "Абонемент учебной литературы обеспечивает студентов и лицеистов учебниками и учебными пособиями в соответствии с учебными программами. Научные, научно-популярные и справочные издания для подготовки рефератов, докладов, курсовых и дипломных работ, а также издания по орган. Располагает богатым фондом справочных и информационных изданий. В отделе художественной литературы собраны книги на любой вкус: есть классическая русская и зарубежная, современная отечественная и иностранная литература; тематика книг - от фантастики, детективов, приключений и женских романов до серьезной, философской литературы. В отделе иностранной литературы хранятся учебные и научные издания на английском, немецком и французском языках. Читальный зал электронных ресурсов (медиатека) НБ УлГТУ располагает фондом CD, DVD по различным отраслям знаний. На территории Научной библиотеки размещены точки доступа в Интернет по технологии Wi-Fi. Право доступа в беспроводную локальной сети предоставляется всем желающим студентам и сотрудникам университета, имеющим учетную запись пользователя корпоративной сети университета."
|
||||
,modifier = Modifier.padding(bottom = 16.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "События библиотечной жизни оперативно отражаются на нашем сайте (http://lib.ulstu.ru), сайт также обеспечивает круглосуточный доступ пользователей к каталогам и базам данных библиотеки."
|
||||
,modifier = Modifier.padding(bottom = 16.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "Научная библиотека ведёт активную работу в помощь духовно-нравственному, патриотическому и эстетическому воспитанию своих читателей, используя различные формы и методы библиотечного обслуживания, такие как: книжные выставки, тематические обзоры, беседы, творческие встречи с интересными людьми, конкурсы и викторины."
|
||||
,modifier = Modifier.padding(bottom = 16.dp)
|
||||
text = "В целом, система аренды велосипедов в университете представляет собой инновационный и удобный способ транспортировки. " +
|
||||
"Она делает перемещение по университету более доступным, эффективным и приятным. " +
|
||||
"Кроме того, аренда велосипедов способствует здоровому образу жизни и позволяет студентам" +
|
||||
" в полной мере наслаждаться красотами университетского окружения.",
|
||||
modifier = Modifier.padding(bottom = 16.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
@ -255,7 +256,7 @@ fun InfoBiblio() {
|
||||
Text("Адреса электронной почты",
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold)
|
||||
Text(text = "rector@ulstu.ru")
|
||||
Text(text = "arendabike@ulstu.ru")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -263,7 +264,9 @@ fun InfoBiblio() {
|
||||
@Composable
|
||||
fun InfoProgrammer() {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize().padding(bottom = 65.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(bottom = 65.dp),
|
||||
contentPadding = PaddingValues(16.dp)
|
||||
) {
|
||||
item {
|
||||
|
@ -0,0 +1,247 @@
|
||||
package com.example.labwork.pages.product
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.material.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
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.graphics.Color
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.labwork.database.DAO.BicycleDao
|
||||
import com.example.labwork.models.Bicycle
|
||||
import com.example.labwork.ui.theme.LightBluePolitech
|
||||
import com.example.labwork.viewmodel.BicycleViewModel
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
@Composable
|
||||
fun FormNewProduct(
|
||||
bicycleViewModel: BicycleViewModel,
|
||||
navHostController: NavHostController
|
||||
) {
|
||||
val isFormVisible = remember { mutableStateOf(false) }
|
||||
var brand by remember { mutableStateOf("") }
|
||||
var model by remember { mutableStateOf("") }
|
||||
var color by remember { mutableStateOf("") }
|
||||
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(9.dp),
|
||||
onClick = {
|
||||
// Установите значение состояния открытия формы как true
|
||||
isFormVisible.value = true
|
||||
},
|
||||
shape = RoundedCornerShape(15.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Добавить",
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
if (isFormVisible.value) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
// Поле ввода для бренда
|
||||
TextField(
|
||||
value = brand,
|
||||
onValueChange = { brand = it },
|
||||
placeholder = { Text("Бренд") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White)
|
||||
)
|
||||
|
||||
// Поле ввода для модели
|
||||
TextField(
|
||||
value = model,
|
||||
onValueChange = { model = it },
|
||||
placeholder = { Text("Модель") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White)
|
||||
)
|
||||
|
||||
// Поле ввода для цвета
|
||||
TextField(
|
||||
value = color,
|
||||
onValueChange = { color = it },
|
||||
placeholder = { Text("Цвет") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White)
|
||||
)
|
||||
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(9.dp),
|
||||
onClick = {
|
||||
val newBicycle = Bicycle(null, brand, model, color, null)
|
||||
bicycleViewModel.insertBicycle(newBicycle)
|
||||
isFormVisible.value = false
|
||||
navHostController.navigate("ListProduct")
|
||||
},
|
||||
shape = RoundedCornerShape(15.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Принять",
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(9.dp),
|
||||
onClick = {
|
||||
isFormVisible.value = false
|
||||
navHostController.navigate("ListProduct")
|
||||
},
|
||||
shape = RoundedCornerShape(15.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Отменить",
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FormUpdateProduct(
|
||||
item: Bicycle,
|
||||
bicycleViewModel: BicycleViewModel,
|
||||
navHostController: NavHostController
|
||||
) {
|
||||
val isFormVisible = remember { mutableStateOf(false) }
|
||||
var brand by remember { mutableStateOf(item.brand) }
|
||||
var model by remember { mutableStateOf(item.model) }
|
||||
var color by remember { mutableStateOf(item.color) }
|
||||
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.padding(start = 9.dp, bottom = 9.dp)
|
||||
.size(height = 32.dp, width = 128.dp),
|
||||
onClick = {
|
||||
// Установите значение состояния открытия формы как true
|
||||
isFormVisible.value = true
|
||||
},
|
||||
shape = RoundedCornerShape(15.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Редактировать",
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
if (isFormVisible.value) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
// Поле ввода для бренда
|
||||
TextField(
|
||||
value = brand,
|
||||
onValueChange = { brand = it },
|
||||
placeholder = { Text("Бренд") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White)
|
||||
)
|
||||
|
||||
// Поле ввода для модели
|
||||
TextField(
|
||||
value = model,
|
||||
onValueChange = { model = it },
|
||||
placeholder = { Text("Модель") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White)
|
||||
)
|
||||
|
||||
// Поле ввода для цвета
|
||||
TextField(
|
||||
value = color,
|
||||
onValueChange = { color = it },
|
||||
placeholder = { Text("Цвет") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White)
|
||||
)
|
||||
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(9.dp),
|
||||
onClick = {
|
||||
val newBicycle = Bicycle(item.id, brand, model, color, null)
|
||||
bicycleViewModel.updateBicycle(newBicycle)
|
||||
isFormVisible.value = false
|
||||
navHostController.navigate("ListProduct")
|
||||
},
|
||||
shape = RoundedCornerShape(15.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Принять",
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(9.dp),
|
||||
onClick = {
|
||||
isFormVisible.value = false
|
||||
navHostController.navigate("ListProduct")
|
||||
},
|
||||
shape = RoundedCornerShape(15.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Отменить",
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.example.labwork.pages
|
||||
package com.example.labwork.pages.product
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
@ -35,12 +35,15 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.labwork.models.ItemProduct
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.labwork.R
|
||||
import com.example.labwork.models.Bicycle
|
||||
import com.example.labwork.ui.theme.LightBluePolitech
|
||||
import com.example.labwork.viewmodel.BicycleViewModel
|
||||
|
||||
|
||||
@Composable
|
||||
fun ListProduct(item: ItemProduct) {
|
||||
fun ListProduct(item: Bicycle, bicycleViewModel : BicycleViewModel, navHostController: NavHostController) {
|
||||
var isFullAbout by remember { mutableStateOf(false) }
|
||||
val scale by animateFloatAsState(if (isFullAbout) 1f else 0f)
|
||||
val textSize by animateDpAsState(if (isFullAbout) 18.dp else 24.dp)
|
||||
@ -56,7 +59,7 @@ fun ListProduct(item: ItemProduct) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Column {
|
||||
Image(
|
||||
painter = painterResource(id = item.imageId),
|
||||
painter = painterResource(id = R.drawable.baseline_directions_bike_24),
|
||||
contentDescription = "book",
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
@ -81,43 +84,21 @@ fun ListProduct(item: ItemProduct) {
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
Row {
|
||||
Column {
|
||||
FormUpdateProduct(item, bicycleViewModel, navHostController)
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.padding(start = 9.dp, bottom = 9.dp)
|
||||
.size(height = 32.dp, width = 40.dp),
|
||||
.size(height = 32.dp, width = 128.dp),
|
||||
onClick = {
|
||||
/*TODO*/
|
||||
bicycleViewModel.deleteBicycle(item)
|
||||
navHostController.navigate("ListProduct")
|
||||
},
|
||||
shape = RoundedCornerShape(15.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "+",
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "1000",
|
||||
color = Color.Black,
|
||||
fontSize = 14.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(start = 8.dp, top = 4.dp)
|
||||
)
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.padding(start = 9.dp, bottom = 9.dp)
|
||||
.size(height = 32.dp, width = 40.dp),
|
||||
onClick = {
|
||||
/*TODO*/
|
||||
},
|
||||
shape = RoundedCornerShape(15.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "-",
|
||||
text = "Удалить",
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
@ -127,7 +108,7 @@ fun ListProduct(item: ItemProduct) {
|
||||
}
|
||||
Column {
|
||||
Text(
|
||||
text = item.name,
|
||||
text = item.model,
|
||||
color = Color.Black,
|
||||
fontSize = textSize.value.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
@ -136,22 +117,51 @@ fun ListProduct(item: ItemProduct) {
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp)
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = isFullAbout,
|
||||
enter = fadeIn() + expandIn(),
|
||||
exit = fadeOut() + shrinkOut(),
|
||||
modifier = Modifier.scale(scale)
|
||||
) {
|
||||
Text(
|
||||
color = Color.Black,
|
||||
text = item.about,
|
||||
maxLines = 10,
|
||||
fontSize = 14.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 8.dp)
|
||||
)
|
||||
Column {
|
||||
Text(
|
||||
color = Color.Black,
|
||||
text = item.brand,
|
||||
maxLines = 10,
|
||||
fontSize = 14.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
Text(
|
||||
color = Color.Black,
|
||||
text = item.color,
|
||||
maxLines = 10,
|
||||
fontSize = 14.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
Text(
|
||||
color = Color.Black,
|
||||
text = item.brand,
|
||||
maxLines = 10,
|
||||
fontSize = 14.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
Text(
|
||||
color = Color.Black,
|
||||
text = if (item.userId != null) "Занято" else "Свободно",
|
||||
maxLines = 10,
|
||||
fontSize = 14.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
167
app/src/main/java/com/example/labwork/pages/user/LoginPage.kt
Normal file
167
app/src/main/java/com/example/labwork/pages/user/LoginPage.kt
Normal file
@ -0,0 +1,167 @@
|
||||
package com.example.labwork.pages.user
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.Image
|
||||
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.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.material.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
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.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.labwork.R
|
||||
import com.example.labwork.models.User
|
||||
import com.example.labwork.ui.theme.LightBluePolitech
|
||||
import com.example.labwork.viewmodel.BicycleViewModel
|
||||
import com.example.labwork.viewmodel.UserViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun LoginPage(
|
||||
navController: NavController,
|
||||
navHostController: NavHostController,
|
||||
userViewModel: UserViewModel,
|
||||
bicycleViewModel: BicycleViewModel
|
||||
) {
|
||||
var email by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
var showPassword by remember { mutableStateOf(false) }
|
||||
var user by remember { mutableStateOf<User?>(null) }
|
||||
var acceptLogin by remember { mutableStateOf(false) }
|
||||
|
||||
if (acceptLogin == true) {
|
||||
user?.let { userProfile ->
|
||||
ProfileForm(item = userProfile, userViewModel = userViewModel, navHostController = navHostController, bicycleViewModel = bicycleViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.logo_ulstu),
|
||||
contentDescription = "Logo",
|
||||
modifier = Modifier.size(200.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
TextField(
|
||||
value = email,
|
||||
onValueChange = { email = it },
|
||||
label = { Text("Почта") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
textStyle = TextStyle(fontSize = 16.sp),
|
||||
colors = TextFieldDefaults.textFieldColors(
|
||||
cursorColor = LightBluePolitech,
|
||||
backgroundColor = Color.White,
|
||||
textColor = LightBluePolitech,
|
||||
unfocusedLabelColor = LightBluePolitech,
|
||||
focusedIndicatorColor = LightBluePolitech,
|
||||
unfocusedIndicatorColor = LightBluePolitech,
|
||||
focusedLabelColor = LightBluePolitech
|
||||
),
|
||||
singleLine = true
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
TextField(
|
||||
value = password,
|
||||
onValueChange = { password = it },
|
||||
label = { Text("Пароль") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
textStyle = TextStyle(fontSize = 16.sp),
|
||||
colors = TextFieldDefaults.textFieldColors(
|
||||
cursorColor = LightBluePolitech,
|
||||
backgroundColor = Color.White,
|
||||
textColor = LightBluePolitech,
|
||||
unfocusedLabelColor = LightBluePolitech,
|
||||
focusedIndicatorColor = LightBluePolitech,
|
||||
unfocusedIndicatorColor = LightBluePolitech,
|
||||
focusedLabelColor = LightBluePolitech
|
||||
),
|
||||
singleLine = true,
|
||||
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
trailingIcon = {
|
||||
IconButton(
|
||||
onClick = { showPassword = !showPassword }
|
||||
) {
|
||||
Image(
|
||||
painter = if (showPassword) painterResource(R.drawable.baseline_visibility) else painterResource(
|
||||
R.drawable.baseline_visibility_off
|
||||
),
|
||||
contentDescription = "LogoVissable",
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
GlobalScope.launch {
|
||||
val result = userViewModel.login(email, password)
|
||||
user = userViewModel.getUserByEmail(email)
|
||||
if (result) {
|
||||
acceptLogin = true
|
||||
}
|
||||
}
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech,),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(text = "Авторизоваться", color = Color.White)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Button(
|
||||
onClick = { navController.navigate("register") },
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(text = "Регистрация", color = Color.White)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
156
app/src/main/java/com/example/labwork/pages/user/ProfileForm.kt
Normal file
156
app/src/main/java/com/example/labwork/pages/user/ProfileForm.kt
Normal file
@ -0,0 +1,156 @@
|
||||
package com.example.labwork.pages.user
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.foundation.text.ClickableText
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.material.TextFieldDefaults
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
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.graphics.Color
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.labwork.database.DAO.BicycleDao
|
||||
import com.example.labwork.database.DAO.UserDao
|
||||
import com.example.labwork.models.Bicycle
|
||||
import com.example.labwork.models.User
|
||||
import com.example.labwork.ui.theme.LightBluePolitech
|
||||
import com.example.labwork.viewmodel.BicycleViewModel
|
||||
import com.example.labwork.viewmodel.UserViewModel
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun ProfileForm(item: User, userViewModel: UserViewModel, navHostController: NavHostController, bicycleViewModel: BicycleViewModel) {
|
||||
|
||||
val bicycles by bicycleViewModel.bicycles.collectAsState(emptyList())
|
||||
|
||||
var selectedBicycleId by remember { mutableStateOf<Int?>(null) }
|
||||
val selectedBicycle = bicycles.find { it.id == selectedBicycleId }
|
||||
val expandedDropdown = remember { mutableStateOf(false) }
|
||||
|
||||
var email by remember { mutableStateOf(item.email) }
|
||||
var name by remember { mutableStateOf(item.name) }
|
||||
var password by remember { mutableStateOf(item.password) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
TextField(
|
||||
value = email,
|
||||
onValueChange = { email = it },
|
||||
placeholder = { Text("Почта") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White)
|
||||
)
|
||||
|
||||
TextField(
|
||||
value = name,
|
||||
onValueChange = { name = it },
|
||||
placeholder = { Text("Имя") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White)
|
||||
)
|
||||
|
||||
TextField(
|
||||
value = password,
|
||||
onValueChange = { password = it },
|
||||
placeholder = { Text("Пароль") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White)
|
||||
)
|
||||
|
||||
Button(
|
||||
onClick = { expandedDropdown.value = true },
|
||||
modifier = Modifier.padding(9.dp),
|
||||
shape = RoundedCornerShape(15.dp),
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
) {
|
||||
Text(
|
||||
text = AnnotatedString(selectedBicycle?.brand ?: "Выберите велосипед"),
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = expandedDropdown.value,
|
||||
onDismissRequest = { expandedDropdown.value = false }
|
||||
) {
|
||||
bicycles.forEach { bicycle ->
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
selectedBicycleId = bicycle.id
|
||||
expandedDropdown.value = false
|
||||
println(item.id)
|
||||
println(bicycle.id)
|
||||
}
|
||||
) {
|
||||
Text(text = "${bicycle.brand} ${bicycle.model}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(9.dp),
|
||||
onClick = {
|
||||
userViewModel.updateUser(User(item.id!!, email, name, password))
|
||||
//userViewModel.updateBicycleUserId(selectedBicycleId!!, item.id) // Обновление userId для Bicycle
|
||||
navHostController.navigate("ListProduct")
|
||||
},
|
||||
shape = RoundedCornerShape(15.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Принять",
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(9.dp),
|
||||
onClick = {
|
||||
navHostController.navigate("ListProduct")
|
||||
},
|
||||
shape = RoundedCornerShape(15.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Отменить",
|
||||
color = Color.White,
|
||||
fontSize = 10.sp,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
57
app/src/main/java/com/example/labwork/pages/user/RegOrLog.kt
Normal file
57
app/src/main/java/com/example/labwork/pages/user/RegOrLog.kt
Normal file
@ -0,0 +1,57 @@
|
||||
package com.example.labwork.pages.user
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
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.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.material.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
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.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.example.labwork.R
|
||||
import com.example.labwork.database.DAO.BicycleDao
|
||||
import com.example.labwork.database.DAO.UserDao
|
||||
import com.example.labwork.ui.theme.LightBluePolitech
|
||||
import com.example.labwork.viewmodel.BicycleViewModel
|
||||
import com.example.labwork.viewmodel.UserViewModel
|
||||
|
||||
@Composable
|
||||
fun RegisteryOrLogin(userViewModel: UserViewModel, navHostController: NavHostController, bicycleViewModel: BicycleViewModel) {
|
||||
val navController = rememberNavController()
|
||||
|
||||
NavHost(navController, startDestination = "login") {
|
||||
composable("login") {
|
||||
LoginPage(navController = navController, userViewModel = userViewModel, navHostController = navHostController, bicycleViewModel = bicycleViewModel)
|
||||
}
|
||||
composable("register") {
|
||||
RegisteryPage(navController = navController, userViewModel = userViewModel, navHostController = navHostController)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.example.labwork.pages
|
||||
package com.example.labwork.pages.user
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.material.TextFieldDefaults
|
||||
@ -26,34 +25,26 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.labwork.R
|
||||
import com.example.labwork.database.DAO.BicycleDao
|
||||
import com.example.labwork.database.DAO.UserDao
|
||||
import com.example.labwork.models.Bicycle
|
||||
import com.example.labwork.models.User
|
||||
import com.example.labwork.ui.theme.LightBluePolitech
|
||||
import com.example.labwork.viewmodel.UserViewModel
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun RegisteryOrLogin() {
|
||||
val navController = rememberNavController()
|
||||
|
||||
NavHost(navController, startDestination = "login") {
|
||||
composable("login") {
|
||||
LoginPage(navController)
|
||||
}
|
||||
composable("register") {
|
||||
RegisteryPage(navController)
|
||||
}
|
||||
}
|
||||
}
|
||||
@Composable
|
||||
fun LoginPage(navController: NavController) {
|
||||
fun RegisteryPage(navController: NavController, userViewModel: UserViewModel, navHostController: NavHostController) {
|
||||
var username by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
var showPassword by remember { mutableStateOf(false) }
|
||||
var confirmPassword by remember { mutableStateOf("") }
|
||||
var email by remember { mutableStateOf("") }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@ -91,85 +82,9 @@ fun LoginPage(navController: NavController) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
TextField(
|
||||
value = password,
|
||||
onValueChange = { password = it },
|
||||
label = { Text("Пароль") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
textStyle = TextStyle(fontSize = 16.sp),
|
||||
colors = TextFieldDefaults.textFieldColors(
|
||||
cursorColor = LightBluePolitech,
|
||||
backgroundColor = Color.White,
|
||||
textColor = LightBluePolitech,
|
||||
unfocusedLabelColor = LightBluePolitech,
|
||||
focusedIndicatorColor = LightBluePolitech,
|
||||
unfocusedIndicatorColor = LightBluePolitech,
|
||||
focusedLabelColor = LightBluePolitech
|
||||
),
|
||||
singleLine = true,
|
||||
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
trailingIcon = {
|
||||
IconButton(
|
||||
onClick = { showPassword = !showPassword }
|
||||
) {
|
||||
Image(
|
||||
painter = if(showPassword) painterResource(R.drawable.baseline_visibility) else painterResource(R.drawable.baseline_visibility_off),
|
||||
contentDescription = "LogoVissable",
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Button(
|
||||
onClick = { /* Login logic */ },
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech, ),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(text = "Авторизоваться", color = Color.White)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Button(
|
||||
onClick = { navController.navigate("register") },
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(text = "Регистрация", color = Color.White)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RegisteryPage(navController: NavController) {
|
||||
var username by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
var confirmPassword by remember { mutableStateOf("") }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.logo_ulstu),
|
||||
contentDescription = "Logo",
|
||||
modifier = Modifier.size(200.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
TextField(
|
||||
value = username,
|
||||
onValueChange = { username = it },
|
||||
label = { Text("Логин") },
|
||||
value = email,
|
||||
onValueChange = { email = it },
|
||||
label = { Text("Почта") },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
@ -230,7 +145,13 @@ fun RegisteryPage(navController: NavController) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Button(
|
||||
onClick = { /* Register logic */ },
|
||||
onClick = {
|
||||
if (password == confirmPassword) {
|
||||
val newUser = User(null, name = username, email = email, password = password)
|
||||
userViewModel.insertUser(newUser)
|
||||
navController.navigate("login")
|
||||
}
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(backgroundColor = LightBluePolitech),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
@ -0,0 +1,15 @@
|
||||
package com.example.labwork.repository
|
||||
|
||||
import androidx.paging.PagingData
|
||||
import com.example.labwork.models.Bicycle
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface BicycleRepository {
|
||||
suspend fun insertBicycle(bicycle: Bicycle)
|
||||
suspend fun updateBicycle(bicycle: Bicycle)
|
||||
suspend fun deleteBicycle(bicycle: Bicycle)
|
||||
suspend fun getAllBicycles(): List<Bicycle>
|
||||
fun getBicycles(): Flow<PagingData<Bicycle>>
|
||||
suspend fun getBicyclesByUserId(userId: Int): List<Bicycle>
|
||||
suspend fun getBicycleById(bicycleId: Int?): Bicycle
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.example.labwork.repository
|
||||
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import com.example.labwork.database.DAO.BicycleDao
|
||||
import com.example.labwork.database.Paging.BicyclePagingSource
|
||||
import com.example.labwork.models.Bicycle
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class OfflineBicycleRepository(private val bicycleDao: BicycleDao) : BicycleRepository {
|
||||
override suspend fun insertBicycle(bicycle: Bicycle) {
|
||||
bicycleDao.insertBicycle(bicycle)
|
||||
}
|
||||
|
||||
override suspend fun updateBicycle(bicycle: Bicycle) {
|
||||
bicycleDao.updateBicycle(bicycle)
|
||||
}
|
||||
|
||||
override suspend fun deleteBicycle(bicycle: Bicycle) {
|
||||
bicycleDao.deleteBicycle(bicycle)
|
||||
}
|
||||
|
||||
override suspend fun getAllBicycles(): List<Bicycle> {
|
||||
return bicycleDao.getAllBicycles()
|
||||
}
|
||||
|
||||
override suspend fun getBicyclesByUserId(userId: Int): List<Bicycle> {
|
||||
return bicycleDao.getBicyclesByUserId(userId)
|
||||
}
|
||||
|
||||
override suspend fun getBicycleById(bicycleId: Int?): Bicycle {
|
||||
return bicycleDao.getBicycleById(bicycleId)
|
||||
}
|
||||
|
||||
override fun getBicycles(): Flow<PagingData<Bicycle>> = Pager(config = PagingConfig(pageSize = 3, jumpThreshold = 3, initialLoadSize = 3) )
|
||||
{
|
||||
BicyclePagingSource(bicycleDao)
|
||||
}.flow
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,38 @@
|
||||
package com.example.labwork.repository
|
||||
|
||||
import com.example.labwork.database.DAO.BicycleDao
|
||||
import com.example.labwork.database.DAO.UserDao
|
||||
import com.example.labwork.models.Bicycle
|
||||
import com.example.labwork.models.User
|
||||
|
||||
class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
|
||||
override suspend fun getAllUsers(): List<User> {
|
||||
return userDao.getAllUsers()
|
||||
}
|
||||
|
||||
override suspend fun insertUser(user: User) {
|
||||
userDao.insertUser(user)
|
||||
}
|
||||
|
||||
override suspend fun updateUser(user: User) {
|
||||
userDao.updateUser(user)
|
||||
}
|
||||
|
||||
override suspend fun deleteUser(user: User) {
|
||||
userDao.deleteUser(user)
|
||||
}
|
||||
|
||||
override suspend fun getUserById(userId: Int): User {
|
||||
return userDao.getUserById(userId)
|
||||
}
|
||||
|
||||
override suspend fun getUserByEmail(email: String): User {
|
||||
return userDao.getUserByEmail(email)
|
||||
}
|
||||
|
||||
override suspend fun getUserByEmailAndPassword(email: String, password: String): User? {
|
||||
return userDao.getUserByEmailAndPassword(email, password)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.example.labwork.repository
|
||||
|
||||
import com.example.labwork.models.User
|
||||
|
||||
interface UserRepository {
|
||||
suspend fun getAllUsers(): List<User>
|
||||
suspend fun insertUser(user: User)
|
||||
suspend fun updateUser(user: User)
|
||||
suspend fun deleteUser(user: User)
|
||||
suspend fun getUserById(userId: Int): User
|
||||
suspend fun getUserByEmail(email: String): User
|
||||
suspend fun getUserByEmailAndPassword(email: String, password: String): User?
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.example.labwork.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewmodel.CreationExtras
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.example.labwork.BicycleRentApplication
|
||||
|
||||
object AppViewModelProvider {
|
||||
val Factory = viewModelFactory {
|
||||
initializer {
|
||||
BicycleScreenViewModel(BicycleRentApplication().container.bicycleRepository)
|
||||
}
|
||||
initializer {
|
||||
BicycleViewModel(BicycleRentApplication().container.bicycleRepository)
|
||||
}
|
||||
initializer {
|
||||
UserViewModel(BicycleRentApplication().container.userRepository)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun CreationExtras.BicycleRentApplication(): BicycleRentApplication =
|
||||
(this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as BicycleRentApplication)
|
@ -0,0 +1,11 @@
|
||||
package com.example.labwork.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.paging.PagingData
|
||||
import com.example.labwork.models.Bicycle
|
||||
import com.example.labwork.repository.BicycleRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class BicycleScreenViewModel(private val bicycleRepository: BicycleRepository) : ViewModel() {
|
||||
val bicycles: Flow<PagingData<Bicycle>> = bicycleRepository.getBicycles()
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.example.labwork.viewmodel
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.labwork.models.Bicycle
|
||||
import com.example.labwork.repository.BicycleRepository
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class BicycleViewModel(private val bicycleRepository: BicycleRepository) : ViewModel() {
|
||||
private val _bicycles = MutableLiveData<List<Bicycle>>()
|
||||
val bicycles: StateFlow<List<Bicycle>> = MutableStateFlow(emptyList())
|
||||
|
||||
private val _currentPage = MutableStateFlow(1)
|
||||
val currentPage: StateFlow<Int> = _currentPage
|
||||
|
||||
fun setCurrentPage(page: Int) {
|
||||
_currentPage.value = page
|
||||
}
|
||||
|
||||
fun getCurrentPage(): Int {
|
||||
return _currentPage.value
|
||||
}
|
||||
|
||||
fun fetchBicycles() {
|
||||
viewModelScope.launch {
|
||||
val fetchedBicycles = bicycleRepository.getAllBicycles()
|
||||
(bicycles as MutableStateFlow).value = fetchedBicycles
|
||||
}
|
||||
}
|
||||
fun fetchAllBicycles() {
|
||||
viewModelScope.launch {
|
||||
_bicycles.value = bicycleRepository.getAllBicycles()
|
||||
}
|
||||
}
|
||||
fun getAllBicycles() {
|
||||
viewModelScope.launch {
|
||||
_bicycles.value = bicycleRepository.getAllBicycles()
|
||||
}
|
||||
}
|
||||
|
||||
fun getBicycleById(bicycleId: Int) {
|
||||
viewModelScope.launch {
|
||||
val bicycle = bicycleRepository.getBicycleById(bicycleId)
|
||||
}
|
||||
}
|
||||
|
||||
fun insertBicycle(bicycle: Bicycle) {
|
||||
viewModelScope.launch {
|
||||
bicycleRepository.insertBicycle(bicycle)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateBicycle(bicycle: Bicycle) {
|
||||
viewModelScope.launch {
|
||||
bicycleRepository.updateBicycle(bicycle)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteBicycle(bicycle: Bicycle) {
|
||||
viewModelScope.launch {
|
||||
bicycleRepository.deleteBicycle(bicycle)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.example.labwork.viewmodel
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.labwork.models.User
|
||||
import com.example.labwork.repository.UserRepository
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class UserViewModel(private val userRepository: UserRepository) : ViewModel() {
|
||||
private val _users = MutableLiveData<List<User>>()
|
||||
val users: LiveData<List<User>> get() = _users
|
||||
|
||||
fun getAllUsers() {
|
||||
viewModelScope.launch {
|
||||
_users.value = userRepository.getAllUsers()
|
||||
}
|
||||
}
|
||||
|
||||
fun getUserById(userId: Int) {
|
||||
viewModelScope.launch {
|
||||
val user = userRepository.getUserById(userId)
|
||||
}
|
||||
}
|
||||
|
||||
fun insertUser(user: User) {
|
||||
viewModelScope.launch {
|
||||
userRepository.insertUser(user)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateUser(user: User) {
|
||||
viewModelScope.launch {
|
||||
userRepository.updateUser(user)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteUser(user: User) {
|
||||
viewModelScope.launch {
|
||||
userRepository.deleteUser(user)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun login(email: String, password: String): Boolean {
|
||||
var isSuccess = false
|
||||
val user = userRepository.getUserByEmail(email)
|
||||
isSuccess = user != null && user.password == password
|
||||
return isSuccess
|
||||
}
|
||||
|
||||
suspend fun getUserByEmail(email: String): User? {
|
||||
return userRepository.getUserByEmail(email)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:tint="#004890" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M15.5,5.5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM5,12c-2.8,0 -5,2.2 -5,5s2.2,5 5,5 5,-2.2 5,-5 -2.2,-5 -5,-5zM5,20.5c-1.9,0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5 3.5,1.6 3.5,3.5 -1.6,3.5 -3.5,3.5zM10.8,10.5l2.4,-2.4 0.8,0.8c1.3,1.3 3,2.1 5.1,2.1L19.1,9c-1.5,0 -2.7,-0.6 -3.6,-1.5l-1.9,-1.9c-0.5,-0.4 -1,-0.6 -1.6,-0.6s-1.1,0.2 -1.4,0.6L7.8,8.4c-0.4,0.4 -0.6,0.9 -0.6,1.4 0,0.6 0.2,1.1 0.6,1.4L11,14v5h2v-6.2l-2.2,-2.3zM19,12c-2.8,0 -5,2.2 -5,5s2.2,5 5,5 5,-2.2 5,-5 -2.2,-5 -5,-5zM19,20.5c-1.9,0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5 3.5,1.6 3.5,3.5 -1.6,3.5 -3.5,3.5z"/>
|
||||
</vector>
|
@ -4,5 +4,5 @@
|
||||
# Location of the SDK. This is only used by Gradle.
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
#Fri Oct 27 18:44:58 GMT+04:00 2023
|
||||
sdk.dir=C\:\\Users\\kashi\\AppData\\Local\\Android\\Sdk
|
||||
#Sun Nov 19 17:10:30 GMT+04:00 2023
|
||||
sdk.dir=C\:\\android-sdk
|
||||
|
BIN
отчеты/1 - Кашин Максим Игоревич.docx
Normal file
BIN
отчеты/1 - Кашин Максим Игоревич.docx
Normal file
Binary file not shown.
BIN
отчеты/2 - Кашин Маким Игоревич.docx
Normal file
BIN
отчеты/2 - Кашин Маким Игоревич.docx
Normal file
Binary file not shown.
BIN
отчеты/3 - Кашин Максим Игоревич.docx
Normal file
BIN
отчеты/3 - Кашин Максим Игоревич.docx
Normal file
Binary file not shown.
BIN
отчеты/4 - Кашин Максим Игоревич.docx
Normal file
BIN
отчеты/4 - Кашин Максим Игоревич.docx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user