Compare commits

...

33 Commits
main ... lab4

Author SHA1 Message Date
c9c689dbbc Отчеты 2023-12-20 12:32:37 +03:00
2fa37312d6 Отчеты 2023-12-20 12:32:09 +03:00
c358c953ba Так и живем 2023-11-29 22:50:13 +04:00
2884f2b4eb 1 2023-11-29 22:33:49 +04:00
4226f90712 Откатил к старой версий, без пагинаций 2023-11-25 10:42:53 +04:00
ee980fe775 Вроде сделал что то типо шуточной привязки 2023-11-24 19:51:29 +04:00
e63c1c1df0 Создал interface. Все перекинул 2023-11-24 18:05:02 +04:00
e96160ad7d Вынес factory 2023-11-24 17:38:41 +04:00
b46391b649 Хотел сделать норм пагинацию, не получилось, но файлы сохраню на всякимй 2023-11-24 02:11:44 +04:00
e903f1729c Сделал кринж года, есть пагинация, но мне вообще не нравится не проект, не реализация, не мои программистические способности :( 2023-11-23 22:45:17 +04:00
dc5cc2e862 Абалдеть, я не знаю, что сделал, на атворизация заработала 2023-11-23 22:02:38 +04:00
0cc1d56a3a Пытаюсь сделать авторизацию, пока что не робит :( 2023-11-23 16:52:30 +03:00
96d09edf51 Работает добавление 2023-11-23 15:31:34 +03:00
36c001ca2e Работает обновление 2023-11-23 15:25:37 +03:00
25cdd9b083 Вроде робит, хз насколько правильно только я это сделал 2023-11-23 15:18:36 +03:00
a11e81ab27 Делаем репозиторрий, виюмодели и прочее, сейлюсь перед тем, как их внедрять 2023-11-23 14:34:37 +03:00
e3bc68c14c Так, проверяем, норм ли создать 4 ветка и коммит в нее (+ репозиторий) 2023-11-23 13:26:26 +03:00
eb79619b6c Чуть чуть декораций 2023-11-22 23:53:54 +04:00
9565e46d37 Отображает занято или нет 2023-11-22 22:59:19 +04:00
bce45a28f0 Немного лишнее убрал 2023-11-22 22:54:06 +04:00
eb3bc2ea3d Сделал супер шутку "личного кабинета" 2023-11-22 22:49:55 +04:00
3e68677d23 Вроде бы сделал связь, ура победа 2023-11-22 22:00:09 +04:00
d9cb297f65 Абалдеть, я сделал редактирование.... 2023-11-21 01:04:47 +04:00
0b8c882823 Сделал шуточную авторизацию 2023-11-21 00:24:18 +04:00
4b3c61ca06 Вроде бы сделал регистрацию, но я не знаю, как ее проверить то... 2023-11-20 23:55:47 +04:00
1984f32b8a Крутим вертим, кнопку добавить починили 2023-11-20 23:34:26 +04:00
b622cb235b Чуть чуть сделал красивее, расскидал по папочкам :3 2023-11-20 22:30:30 +04:00
9c8d38f9f4 я не знаю каким чудом, но я сделал добавление 2023-11-20 20:41:00 +04:00
4df3eff3b1 ПВАЗХЩПХЗВАЩЗПХВАХЗПЩВ, ЭТО САМЫЙ ЖОСКИЙ КОСТЫЛЬ, НО ОНО РАБОТАЕТ 2023-11-19 23:09:23 +04:00
61b1507973 Абалдеть, я сделал удаление велосипеда, абалдеть.... 2023-11-19 22:46:47 +04:00
cf8aefb83d Я НЕ ЗНАЮ КАКАОЕ ЧУДО ПРОИЗОШЛО, НО ОНО РАБОТАЕТ!!! 2023-11-19 20:04:27 +04:00
62854ccff8 Меняю версию джавы, добавляю библиотеки, надеюсь, ничего не взорвется 2023-11-16 23:38:33 +04:00
a9f21b28d2 Новая ветка, сейчас буду пытаться что нить с бд, мб поменяю с "библиотеки", на "велосипеды" 2023-11-16 22:31:01 +04:00
36 changed files with 1419 additions and 225 deletions

View File

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

View File

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

View File

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

View File

@ -3,19 +3,29 @@ 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))
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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?
)

View File

@ -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,"Маленький принц","«Маленький принц» — аллегорическая повесть, наиболее известное произведение Антуана де Сент-Экзюпери. ")
)
}

View 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,
)

View File

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

View File

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

View File

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

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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