Compare commits

...

17 Commits
master ... Lab5

Author SHA1 Message Date
bdebaee485 вся лаб 5 2023-12-19 21:52:09 +04:00
7af968a96a лаб 5 2023-12-17 21:47:25 +04:00
2aa2e5bc60 di and pagination 2023-11-12 18:50:40 +04:00
4b7e5338ef вроде все 2023-11-01 22:08:07 +04:00
edeae3587f need to do ChangeHotel 2023-11-01 19:13:12 +04:00
6a8a539858 время сохраняется 2023-11-01 18:36:34 +04:00
71743e9166 заказы показываются 2023-11-01 13:58:14 +04:00
4c013ac345 осталось список заказов и панельку админа 2023-10-31 17:32:36 +04:00
25e1d97db5 работает все 2023-10-29 23:32:58 +04:00
2b9cd69ccb не работает ничего 2023-10-29 21:53:33 +04:00
d73bb9f1aa сдана 2023-10-29 14:23:22 +04:00
83d91169cc дезигн поправлен
потом можно исправить админ панель
2023-10-17 21:59:23 +04:00
35d89b440e впринципе все скрины есть
поправить дезигн нужно
2023-10-16 17:09:41 +04:00
9b61677603 добавила букинг
по хорошему нужно доделать дезигн всего
2023-10-05 00:29:25 +04:00
3b192d27cb first steps for hotel info 2023-10-04 16:12:27 +04:00
72c903a0b3 нужно исправить верстку входа 2023-10-03 14:45:00 +04:00
11bc140481 это только начало 2023-10-01 21:55:07 +04:00
81 changed files with 3932 additions and 53 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" /> <bytecodeTargetLevel target="19" />
</component> </component>
</project> </project>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="C:\Users\60652\.android\avd\Pixel_2_API_30.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-10-29T18:27:39.718325100Z" />
</component>
</project>

View File

@ -7,7 +7,7 @@
<option name="testRunner" value="GRADLE" /> <option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" /> <option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" /> <option name="gradleJvm" value="19" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />

View File

@ -1,6 +1,6 @@
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_19" default="true" project-jdk-name="19" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

6
.idea/vcs.xml Normal file
View File

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

View File

@ -1,16 +1,18 @@
plugins { plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id ("kotlin-kapt")
kotlin("plugin.serialization") version "1.4.21"
} }
android { android {
namespace = "com.example.androidlabs" namespace = "com.example.androidlabs"
compileSdk = 33 compileSdk = 34
defaultConfig { defaultConfig {
applicationId = "com.example.androidlabs" applicationId = "com.example.androidlabs"
minSdk = 24 minSdk = 24
targetSdk = 33 targetSdk = 34
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0"
@ -23,15 +25,18 @@ android {
buildTypes { buildTypes {
release { release {
isMinifyEnabled = false isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
} }
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_19
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_19
} }
kotlinOptions { kotlinOptions {
jvmTarget = "1.8" jvmTarget = "19"
} }
buildFeatures { buildFeatures {
compose = true compose = true
@ -45,17 +50,18 @@ android {
} }
} }
} }
apply(plugin = "kotlin-kapt")
dependencies { dependencies {
implementation("androidx.core:core-ktx:1.9.0") implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
implementation("androidx.activity:activity-compose:1.7.0") implementation("androidx.activity:activity-compose:1.8.0")
implementation(platform("androidx.compose:compose-bom:2023.03.00")) implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3") implementation("androidx.compose.material:material")
implementation("androidx.navigation:navigation-runtime-ktx:2.7.4")
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
@ -63,4 +69,31 @@ dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4") androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest") debugImplementation("androidx.compose.ui:ui-test-manifest")
implementation ("androidx.activity:activity-ktx:1.8.0")
implementation ("androidx.fragment:fragment-ktx:1.6.1")
implementation ("io.coil-kt:coil-compose:1.4.0")
implementation ("com.google.code.gson:gson:2.8.8")
implementation("androidx.navigation:navigation-compose:2.7.4")
implementation ("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0-alpha02")
//ROOM
val room_version = "2.5.2"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
kapt("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.room:room-paging:$room_version")
//Paging
implementation ("androidx.paging:paging-compose:3.2.1")
implementation ("androidx.paging:paging-runtime:3.2.1")
// retrofit
val retrofitVersion = "2.9.0"
implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
implementation("androidx.paging:paging-compose:3.2.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
} }

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application <application
android:name=".App"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"

View File

@ -0,0 +1,19 @@
package com.example.androidlabs
import android.app.Application
import com.example.androidlabs.DB.AppDatabase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class App : Application() {
lateinit var container: AppContainer
override fun onCreate() {
super.onCreate()
//this.deleteDatabase("my-db")
//CoroutineScope(Dispatchers.IO).launch {
// AppDatabase.populateDatabase()
//}
container = AppDataContainer(this)
}
}

View File

@ -0,0 +1,15 @@
package com.example.androidlabs
import com.example.androidlabs.DB.repository.HotelRepository
import com.example.androidlabs.DB.repository.OrderRepository
import com.example.androidlabs.DB.repository.UserRepository
interface AppContainer {
val hotelRepo: HotelRepository
val userRepo: UserRepository
val orderRepo: OrderRepository
companion object {
const val TIMEOUT = 5000L
const val LIMIT = 10
}
}

View File

@ -0,0 +1,38 @@
package com.example.androidlabs
import RestUserRepository
import android.content.Context
import com.example.androidlabs.DB.AppDatabase
import com.example.androidlabs.DB.repository.HotelRepImpl
import com.example.androidlabs.DB.repository.HotelRepository
import com.example.androidlabs.DB.repository.OrderRepository
import com.example.androidlabs.DB.repository.RemoteKeysRepositoryImpl
import com.example.androidlabs.DB.repository.UserRepository
import com.example.androidlabs.api.BackendService
import com.example.androidlabs.api.repository.RestHotelRepository
import com.example.androidlabs.api.repository.RestOrderRepository
class AppDataContainer(private val context: Context) : AppContainer {
override val hotelRepo: HotelRepository by lazy {
RestHotelRepository(
BackendService.getInstance(),
hotelRepository,
AppDatabase.getInstance(context),
remoteKeyRepository
)
}
override val userRepo: UserRepository by lazy {
RestUserRepository(BackendService.getInstance())
}
override val orderRepo: OrderRepository by lazy {
RestOrderRepository(BackendService.getInstance())
}
private val hotelRepository: HotelRepImpl by lazy {
HotelRepImpl(AppDatabase.getInstance(context).hotelDao())
}
private val remoteKeyRepository: RemoteKeysRepositoryImpl by lazy {
RemoteKeysRepositoryImpl(AppDatabase.getInstance(context).remoteKeysDao())
}
}

View File

@ -0,0 +1,79 @@
package com.example.androidlabs.Calendar
import android.app.DatePickerDialog
import android.os.Bundle
import android.widget.DatePicker
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import java.util.*
@Composable
fun MyDp(){
// Fetching the Local Context
val mContext = LocalContext.current
// Declaring integer values
// for year, month and day
val mYear: Int
val mMonth: Int
val mDay: Int
// Initializing a Calendar
val mCalendar = Calendar.getInstance()
// Fetching current year, month and day
mYear = mCalendar.get(Calendar.YEAR)
mMonth = mCalendar.get(Calendar.MONTH)
mDay = mCalendar.get(Calendar.DAY_OF_MONTH)
mCalendar.time = Date()
// Declaring a string value to
// store date in string format
val mDate = remember { mutableStateOf("") }
// Declaring DatePickerDialog and setting
// initial values as current values (present year, month and day)
val mDatePickerDialog = DatePickerDialog(
mContext,
{ _: DatePicker, mYear: Int, mMonth: Int, mDayOfMonth: Int ->
mDate.value = "$mDayOfMonth/${mMonth+1}/$mYear"
}, mYear, mMonth, mDay
)
Column(modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally) {
// Creating a button that on
// click displays/shows the DatePickerDialog
Button(onClick = {
mDatePickerDialog.show()
}, colors = ButtonDefaults.buttonColors(backgroundColor = Color(0XFF0F9D58)) ) {
Text(text = "Open Date Picker", color = Color.White)
}
// Displaying the mDate value in the Text
Text(text = "Selected Date: ${mDate.value}", fontSize = 30.sp, textAlign = TextAlign.Center)
}
}
// For displaying preview in
// the Android Studio IDE emulator
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
MyDp()
}

View File

@ -0,0 +1,81 @@
package com.example.androidlabs.DB
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.androidlabs.DB.dao.HotelDao
import com.example.androidlabs.DB.dao.OrderDao
import com.example.androidlabs.DB.dao.RemoteKeysDao
import com.example.androidlabs.DB.dao.UserDao
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.models.Order
import com.example.androidlabs.DB.models.RemoteKeys
import com.example.androidlabs.DB.models.RoleEnum
import com.example.androidlabs.DB.models.User
import com.example.androidlabs.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
// TODO
@Database(entities = [Hotel::class, User::class, Order::class, RemoteKeys::class], version = 6)
abstract class AppDatabase : RoomDatabase() {
abstract fun hotelDao(): HotelDao
abstract fun userDao(): UserDao
abstract fun orderDao(): OrderDao
abstract fun remoteKeysDao(): RemoteKeysDao
companion object {
private const val DB_NAME: String = "my-db"
@Volatile
private var INSTANCE: AppDatabase? = null
suspend fun populateDatabase() {
INSTANCE?.let { database ->
// User
val userDao = database.userDao()
val user1 = User(null, "Artem", "Emelyanov", "artem@mail.ru", "123", "USER")
val user2 = User(null, "Danil", "Markov", "danil@mail.ru", "123", "ADMIN")
val user3 = User(null, "Viktoria", "Presnyakova", "vika@mail.ru", "123", "USER")
userDao.createUser(user1)
userDao.createUser(user2)
userDao.createUser(user3)
// Hotel
val hotelDao = database.hotelDao()
val hotel1 = Hotel(null, "Hotel1", 1000.0, R.drawable.img, 1, "location1", "info1")
val hotel2 = Hotel(null, "Hotel2", 2000.0, R.drawable.img_2, 2, "location2", "info2")
val hotel3 = Hotel(null, "Hotel3", 3000.0, R.drawable.img_3, 3, "location3", "info3")
val hotel4 = Hotel(null, "Hotel4", 4000.0, R.drawable.img_4, 4, "location4", "info4")
hotelDao.insert(hotel1)
hotelDao.insert(hotel2)
hotelDao.insert(hotel3)
hotelDao.insert(hotel4)
// Order
}
}
fun getInstance(appContext: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
Room.databaseBuilder(
appContext,
AppDatabase::class.java,
DB_NAME
)
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch {
populateDatabase()
}
}
})
.fallbackToDestructiveMigration()
.build()
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,33 @@
package com.example.androidlabs.DB.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.example.androidlabs.DB.models.Hotel
import kotlinx.coroutines.flow.Flow
@Dao
interface HotelDao {
@Insert
suspend fun insert(vararg hotel: Hotel)
@Update
suspend fun update(hotel: Hotel)
@Delete
suspend fun delete(hotel: Hotel)
@Query("SELECT*FROM Hotel")
fun getAllHotelsPaged(): PagingSource<Int, Hotel>
@Query("SELECT * FROM Hotel WHERE hotelId = :id")
suspend fun getHotelById(id: Int): Hotel
@Query("select * from Hotel")
fun getAll(): PagingSource<Int, Hotel>
@Query("DELETE FROM Hotel")
suspend fun deleteAll()
}

View File

@ -0,0 +1,28 @@
package com.example.androidlabs.DB.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import com.example.androidlabs.DB.models.Order
import com.example.androidlabs.DB.models.UserWithOrder
import kotlinx.coroutines.flow.Flow
@Dao
interface OrderDao {
@Insert
suspend fun createOrder(order: Order): Long
@Query("SELECT * FROM 'Order' WHERE orderId = :id")
fun getOrder(id: Int): Order
@Query("SELECT * FROM `Order`")
fun getAllOrder(): Flow<List<Order>>
@Delete
suspend fun delete(order: Order)
@Query("SELECT * FROM users WHERE userId =:id")
fun getUserOrders(id: Int) : Flow<UserWithOrder>
}

View File

@ -0,0 +1,19 @@
package com.example.androidlabs.DB.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.example.androidlabs.DB.models.RemoteKeyType
import com.example.androidlabs.DB.models.RemoteKeys
@Dao
interface RemoteKeysDao {
@Query("SELECT * FROM remote_keys WHERE entityId = :entityId AND type = :type")
suspend fun getRemoteKeys(entityId: Int, type: RemoteKeyType): RemoteKeys?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(remoteKey: List<RemoteKeys>)
@Query("DELETE FROM remote_keys WHERE type = :type")
suspend fun clearRemoteKeys(type: RemoteKeyType)
}

View File

@ -0,0 +1,29 @@
package com.example.androidlabs.DB.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.example.androidlabs.DB.models.User
import com.example.androidlabs.DB.models.UserWithOrder
import kotlinx.coroutines.flow.Flow
@Dao
interface UserDao {
@Insert
suspend fun createUser(user: User)
@Update
suspend fun updateUser(user: User)
@Delete
suspend fun deleteUser(user: User)
@Query("SELECT * FROM users WHERE userId = :id")
suspend fun getUserById(id: Int): User
@Query("SELECT * FROM users WHERE email = :email")
suspend fun getUserByEmail(email: String): User
}

View File

@ -0,0 +1,29 @@
package com.example.androidlabs.DB.models
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class Hotel (
@PrimaryKey(autoGenerate = true)
val hotelId: Int? = null,
@ColumnInfo(name = "Name")
val name: String,
@ColumnInfo(name = "Price")//
val price: Double,
@ColumnInfo(name = "Img")//
val img: Int,
@ColumnInfo(name = "Stars")//
val stars: Int,
@ColumnInfo(name = "Location")//
val location: String,
@ColumnInfo(name = "Info")//
val info: String,
)

View File

@ -0,0 +1,26 @@
package com.example.androidlabs.DB.models
import androidx.room.ColumnInfo
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class Order(
@PrimaryKey(autoGenerate = true)
val orderId: Int? = null,
@ColumnInfo(name = "DateFrom")
val dateFrom: String,
@ColumnInfo(name = "DateTo")
val dateTo: String,
@ColumnInfo(name = "Rooms")
val rooms: Int,
@ColumnInfo(name = "Total")
val total: Double,
@ColumnInfo(name = "CreatorUserId")
val creatorUserId: Int,
@ColumnInfo(name = "BookedHotelId")
val bookedHotelId: Int,
// @Embedded
// val hotel: Hotel
)

View File

@ -0,0 +1,29 @@
package com.example.androidlabs.DB.models
import com.example.androidlabs.R
class PhotoManager {
private val photos = listOf(
R.drawable.img,
R.drawable.img_1,
R.drawable.img_2,
R.drawable.img_3,
R.drawable.img_4,
)
private var currentIndex = 0
fun changePhoto(int: Int): Int {
currentIndex = photos.indexOf(int)
if (photos.isNotEmpty()) {
if(currentIndex + 1 >= photos.size){
currentIndex = 0
}else{
currentIndex += 1
}
return photos[currentIndex]
} else {
return -1
}
}
}

View File

@ -0,0 +1,22 @@
package com.example.androidlabs.DB.models
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
enum class RemoteKeyType(private val type: String) {
SNEAKER(Hotel::class.simpleName ?: "Hotel");
@TypeConverter
fun toRemoteKeyType(value: String) = RemoteKeyType.values().first { it.type == value }
@TypeConverter
fun fromRemoteKeyType(value: RemoteKeyType) = value.type
}
@Entity(tableName = "remote_keys")
data class RemoteKeys(
@PrimaryKey val entityId: Int,
@TypeConverters(RemoteKeyType::class)
val type: RemoteKeyType,
val prevKey: Int?,
val nextKey: Int?
)

View File

@ -0,0 +1,6 @@
package com.example.androidlabs.DB.models
enum class RoleEnum {
Admin,
User
}

View File

@ -0,0 +1,23 @@
package com.example.androidlabs.DB.models
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true)
val userId: Int? = null,
@ColumnInfo(name = "Name")
val name: String,
@ColumnInfo(name = "Surname")
val surname: String,
@ColumnInfo(name = "Email")
val email: String,
@ColumnInfo(name = "Password")
val password: String,
@ColumnInfo(name = "Role")
val role: String,
@ColumnInfo(name = "Photo")
val photo: Int? = null,
)

View File

@ -0,0 +1,13 @@
package com.example.androidlabs.DB.models
import androidx.room.Embedded
import androidx.room.Relation
data class UserWithOrder(
@Embedded val user: User,
@Relation(
parentColumn = "userId",
entityColumn = "CreatorUserId"
)
val orders: List<Order>
)

View File

@ -0,0 +1,35 @@
package com.example.androidlabs.DB.repository
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.androidlabs.DB.dao.HotelDao
import com.example.androidlabs.DB.models.Hotel
import androidx.paging.PagingSource
import com.example.androidlabs.AppContainer
import kotlinx.coroutines.flow.Flow
class HotelRepImpl (private val hotelDao: HotelDao) : HotelRepository {
override suspend fun insertHotel(hotel: Hotel) = hotelDao.insert(hotel)
override suspend fun updateHotel(hotel: Hotel) = hotelDao.update(hotel)
override suspend fun deleteHotel(hotel: Hotel) = hotelDao.delete(hotel)
override suspend fun getHotelById(id: Int): Hotel = hotelDao.getHotelById(id)
override fun getAllHotels(): Flow<PagingData<Hotel>> = Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
pagingSourceFactory = hotelDao::getAll
).flow
suspend fun clearHotels() = hotelDao.deleteAll()
suspend fun insertHotels(hotels: List<Hotel>) =
hotelDao.insert(*hotels.toTypedArray())
fun getAllHotelsPagingSource(): PagingSource<Int, Hotel> = hotelDao.getAll()
}

View File

@ -0,0 +1,14 @@
package com.example.androidlabs.DB.repository
import androidx.paging.PagingSource
import com.example.androidlabs.DB.models.Hotel
import kotlinx.coroutines.flow.Flow
import androidx.paging.PagingData
interface HotelRepository {
suspend fun insertHotel(hotel: Hotel)
suspend fun updateHotel(hotel: Hotel)
suspend fun deleteHotel(hotel: Hotel)
suspend fun getHotelById(id: Int): Hotel
fun getAllHotels(): Flow<PagingData<Hotel>>
}

View File

@ -0,0 +1,17 @@
//package com.example.androidlabs.DB.repository
//
//import com.example.androidlabs.DB.dao.OrderDao
//import com.example.androidlabs.DB.models.Order
//import com.example.androidlabs.DB.models.UserWithOrder
//import kotlinx.coroutines.flow.Flow
//
//class OrderRepImpl (private val orderDao: OrderDao) : OrderRepository {
//
// override suspend fun createOrder(order: Order): Long = orderDao.createOrder(order)
//
// override suspend fun delete(order: Order) = orderDao.delete(order)
//
// override fun getAllOrder(): Flow<List<Order>> = orderDao.getAllOrder()
//
// override fun getUserOrders(id: Int): Flow<UserWithOrder> = orderDao.getUserOrders(id)
//}

View File

@ -0,0 +1,15 @@
package com.example.androidlabs.DB.repository
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.models.Order
import com.example.androidlabs.DB.models.UserWithOrder
import kotlinx.coroutines.flow.Flow
interface OrderRepository {
suspend fun createOrder(order: Order): Long
suspend fun delete(orderId: Int)
//fun getAllOrder(): Flow<List<Order>>
suspend fun getHotelFromOrder(id: Int): Hotel
suspend fun getUserOrders(id: Int) : Flow<List<Order>>
}

View File

@ -0,0 +1,10 @@
package com.example.androidlabs.DB.repository
import com.example.androidlabs.DB.models.RemoteKeyType
import com.example.androidlabs.DB.models.RemoteKeys
interface RemoteKeyRepository {
suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType): RemoteKeys?
suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>)
suspend fun deleteRemoteKey(type: RemoteKeyType)
}

View File

@ -0,0 +1,16 @@
package com.example.androidlabs.DB.repository
import com.example.androidlabs.DB.dao.RemoteKeysDao
import com.example.androidlabs.DB.models.RemoteKeyType
import com.example.androidlabs.DB.models.RemoteKeys
class RemoteKeysRepositoryImpl(private val remoteKeysDao: RemoteKeysDao) : RemoteKeyRepository {
override suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType) =
remoteKeysDao.getRemoteKeys(id, type)
override suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>) =
remoteKeysDao.insertAll(remoteKeys)
override suspend fun deleteRemoteKey(type: RemoteKeyType) =
remoteKeysDao.clearRemoteKeys(type)
}

View File

@ -0,0 +1,17 @@
package com.example.androidlabs.DB.repository
import com.example.androidlabs.DB.dao.UserDao
import com.example.androidlabs.DB.models.User
//class UserRepImpl(private val userDao: UserDao) : UserRepository {
//
// override suspend fun createUser(user: User) = userDao.createUser(user)
//
// override suspend fun updateUser(user: User) = userDao.updateUser(user)
//
// override suspend fun deleteUser(user: User) = userDao.deleteUser(user)
//
// override suspend fun getUserById(id: Int): User = userDao.getUserById(id)
//
// override suspend fun getUserByEmail(email: String): User = userDao.getUserByEmail(email)
//}

View File

@ -0,0 +1,11 @@
package com.example.androidlabs.DB.repository
import com.example.androidlabs.DB.models.User
import com.example.androidlabs.api.model.UserRemoteSignIn
interface UserRepository {
suspend fun createUser(user: User)
suspend fun updateUser(user: User)
suspend fun deleteUser(user: User)
suspend fun authUser(user: UserRemoteSignIn): User
}

View File

@ -0,0 +1,24 @@
package com.example.androidlabs.DB.viewModels
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.example.androidlabs.App
object AppViewModelProvider {
val Factory = viewModelFactory {
initializer {
HotelViewModel(app().container.hotelRepo)
}
initializer {
UserViewModel(app().container.userRepo)
}
initializer {
OrderViewModel(app().container.orderRepo)
}
}
}
fun CreationExtras.app(): App =
(this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as App)

View File

@ -0,0 +1,51 @@
package com.example.androidlabs.DB.viewModels
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.paging.cachedIn
import com.example.androidlabs.App
import com.example.androidlabs.DB.AppDatabase
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.repository.HotelRepository
import com.example.androidlabs.R
import kotlinx.coroutines.launch
class HotelViewModel(private val hotelRepository: HotelRepository): ViewModel() {
var name = mutableStateOf("")
val price = mutableStateOf("")
val location = mutableStateOf("")
val stars = mutableStateOf("")
val info = mutableStateOf("")
val img = mutableStateOf(R.drawable.img)
val HotelList = hotelRepository.getAllHotels()
var hotel: Hotel? = null
fun insertHotel() = viewModelScope.launch {
val hotel = Hotel(
name = name.value,
location = location.value,
price = price.value.toDouble(),
img = img.value,
stars = stars.value.toInt(),
info = info.value
)
hotelRepository.insertHotel(hotel)
}
fun deleteHotel(hotel : Hotel) = viewModelScope.launch {
hotelRepository.deleteHotel(hotel)
}
fun getHotelById(id: Int) = viewModelScope.launch {
hotelRepository.getHotelById(id)
}
fun UpdateHotel(hotel: Hotel) = viewModelScope.launch {
hotelRepository.updateHotel(hotel)
}
}

View File

@ -0,0 +1,61 @@
package com.example.androidlabs.DB.viewModels
import android.util.Log
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import com.example.androidlabs.App
import com.example.androidlabs.DB.AppDatabase
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.models.Order
import com.example.androidlabs.DB.models.UserWithOrder
import com.example.androidlabs.DB.repository.OrderRepository
import com.example.androidlabs.GlobalUser
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import java.util.Date
class OrderViewModel(private val orderRepository: OrderRepository) : ViewModel() {
var selectedItem: Hotel? = null
val rooms = mutableStateOf("")
var dateFrom = mutableStateOf("")
var dateTo = mutableStateOf("")
fun deleteOrder(orderId: Int) = viewModelScope.launch {
orderRepository.delete(orderId)
}
suspend fun getOrderList(id: Int) : Flow<List<Order>> {
return orderRepository.getUserOrders(id)
}
suspend fun getHotelFromOrder(id: Int) : Hotel {
return orderRepository.getHotelFromOrder(id)
}
fun createOrder() = viewModelScope.launch {
Log.d("MyLog", GlobalUser.getInstance().getUser()?.userId.toString())
val order = Order(
dateFrom = dateFrom.value,
dateTo = dateTo.value,
rooms = rooms.value.toInt(),
total = getSubTotal(),
bookedHotelId = selectedItem?.hotelId!!,
creatorUserId = GlobalUser.getInstance().getUser()?.userId!!,
//hotel = selectedItem!!
)
val orderId = orderRepository.createOrder(order)
rooms.value = ""
selectedItem = null
}
fun getSubTotal(): Double {
return selectedItem!!.price * rooms.value.toInt()
}
}

View File

@ -0,0 +1,44 @@
package com.example.androidlabs.DB.viewModels
import android.util.Log
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import com.example.androidlabs.App
import com.example.androidlabs.DB.AppDatabase
import com.example.androidlabs.DB.models.RoleEnum
import com.example.androidlabs.DB.models.User
import com.example.androidlabs.DB.repository.UserRepository
import com.example.androidlabs.GlobalUser
import com.example.androidlabs.R
import com.example.androidlabs.api.model.UserRemoteSignIn
import kotlinx.coroutines.launch
class UserViewModel(private val userRepository: UserRepository): ViewModel() {
var name = mutableStateOf("")
val surname = mutableStateOf("")
val email = mutableStateOf("")
val password = mutableStateOf("")
fun createUser() = viewModelScope.launch {
val user = User(
name = name.value,
surname = surname.value,
email = email.value,
password = password.value,
role = "USER",
photo = R.drawable.img_2
)
userRepository.createUser(user)
}
fun authUser() = viewModelScope.launch {
val user = userRepository.authUser(UserRemoteSignIn(email.value, password.value))
GlobalUser.getInstance().setUser(user)
}
fun isValidEmail(email: String): Boolean {
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()
}
}

View File

@ -3,41 +3,40 @@ package com.example.androidlabs
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize import com.example.androidlabs.DB.models.User
import androidx.compose.material3.MaterialTheme import com.example.androidlabs.Navigation.Navigate
import androidx.compose.material3.Surface import com.example.androidlabs.hotelScreen.HotelInfo
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.androidlabs.ui.theme.AndroidLabsTheme
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
AndroidLabsTheme { Navigate()
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
Greeting("Android")
} }
} }
} }
class GlobalUser private constructor() {
private var user: User? = null
fun setUser(user: User?) {
this.user = user
}
fun getUser(): User? {
return user
}
companion object {
private var instance: GlobalUser? = null
fun getInstance(): GlobalUser {
return instance ?: synchronized(this) {
instance ?: GlobalUser().also { instance = it }
}
}
} }
} }
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
AndroidLabsTheme {
Greeting("Android")
}
}

View File

@ -0,0 +1,69 @@
package com.example.androidlabs.MyOrderScreen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.example.androidlabs.DB.models.Order
import com.example.androidlabs.DB.viewModels.OrderViewModel
import com.example.androidlabs.GlobalUser
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.lifecycle.viewmodel.compose.viewModel
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import kotlinx.coroutines.flow.first
@Composable
fun MyOrderScreen(orderViewModel: OrderViewModel= viewModel(factory = AppViewModelProvider.Factory)) {
// val userWithOrder by orderViewModel.database.userDao().getUserOrders(GlobalUser.getInstance().getUser()?.userId!!).collectAsState(null)
val userId = GlobalUser.getInstance().getUser()?.userId
var usersOrder by remember { mutableStateOf<List<Order>>(emptyList()) }
LaunchedEffect(userId) {
usersOrder = orderViewModel.getOrderList(userId!!).first()
}
Column(
modifier = Modifier
.padding(bottom = 50.dp)
.fillMaxSize()
.background(Color.White)
.verticalScroll(rememberScrollState())
){
Text(
text = "My order",
style = MaterialTheme.typography.h5,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(10.dp, 10.dp)
)
Row {
Column(
modifier = Modifier
.fillMaxSize()
) {
if (usersOrder != null) {
for (item in usersOrder) {
OrderCard(item)
}
}
}
}
}
}

View File

@ -0,0 +1,95 @@
package com.example.androidlabs.MyOrderScreen
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.androidlabs.DB.AppDatabase
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.models.Order
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import com.example.androidlabs.DB.viewModels.OrderViewModel
import com.example.androidlabs.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.Date
@Composable
fun OrderCard(order: Order, orderViewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)){
var hotels by remember { mutableStateOf<List<Hotel>>(emptyList()) }
LaunchedEffect(order.orderId) {
hotels = listOf(orderViewModel.getHotelFromOrder(order.orderId!!))
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
){
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalArrangement = Arrangement.Center
){
Text("${order.orderId}")
Text("From " + order.dateFrom)
Text("To " + order.dateTo)
Text("Sum ${order.total}")
Row(){
if (hotels != null) {
for(hotel in hotels) {
Image(
contentScale = ContentScale.FillBounds,
painter = painterResource(id = hotel.img), // TODO
contentDescription = null,
modifier = Modifier
.size(70.dp)
.padding(0.dp, 10.dp, 10.dp, 10.dp)
)
}
}
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
orderViewModel.deleteOrder(order.orderId!!)
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
) {
Text("Cancel")
}
}
}
}

View File

@ -0,0 +1,82 @@
package com.example.androidlabs.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.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import com.example.androidlabs.DB.viewModels.OrderViewModel
import com.example.androidlabs.MyOrderScreen.MyOrderScreen
import com.example.androidlabs.booking.BookingScreen
import com.example.androidlabs.homeScreen.HomeScreen
import com.example.androidlabs.hotelScreen.HotelInfo
import com.example.androidlabs.profileScreen.profile.Person
import com.example.androidlabs.profileScreen.profile.ProfileScreen
import com.example.androidlabs.profileScreen.signIn.LoginScreen
import com.example.androidlabs.profileScreen.signUp.SignUpScreen
import com.example.androidlabs.adminPanel.AddPanel
import com.example.androidlabs.adminPanel.AdminPanel
import com.example.androidlabs.adminPanel.ChangeHotel
import com.example.androidlabs.adminPanel.ChangePanel
import com.google.gson.Gson
@Composable
fun NavController(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = NavItem.Home.route
) {
composable(NavItem.HotelInfo.route) {
//
backStackEntry ->
val hotelItemString = backStackEntry.arguments?.getString("hotelItem")
val hotelItem = Gson().fromJson(hotelItemString, Hotel::class.java)
hotelItem?.let { HotelInfo(it, navController)
}
}
composable(NavItem.Home.route) {
HomeScreen(navController)
}
composable(NavItem.MyOrder.route){
MyOrderScreen()
}
composable(NavItem.Profile.route) {
ProfileScreen(navController)
}
composable(NavItem.SignIn.route){
LoginScreen(navController)
}
composable(NavItem.SignUp.route){
SignUpScreen(navController)
}
composable(NavItem.Booking.route) {
backStackEntry ->
val hotelItemString = backStackEntry.arguments?.getString("hotelItem")
val hotelItem = Gson().fromJson(hotelItemString, Hotel::class.java)
hotelItem?.let { BookingScreen(it, navController)
}
}
composable(NavItem.ChangeHotel.route) { backStackEntry ->
val hotelItemString = backStackEntry.arguments?.getString("hotelItem")
val hotelItem = Gson().fromJson(hotelItemString, Hotel::class.java)
hotelItem?.let { ChangeHotel(it, onBackClick = {
navController.navigateUp() })
}
}
composable(NavItem.Person.route) {
Person(navController)
}
composable(NavItem.AdminPanel.route){
AdminPanel(navController)
}
composable(NavItem.AddPanel.route){
AddPanel(navController)
}
composable(NavItem.ChangePanel.route){
ChangePanel(navController)
}
}
}

View File

@ -0,0 +1,24 @@
package com.example.androidlabs.Navigation
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Build
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Person
import androidx.compose.ui.graphics.vector.ImageVector
sealed class NavItem(val route: String, val icon: ImageVector?){
object Home : NavItem("home", Icons.Default.Home)
object MyOrder : NavItem("myorder", null)
object Profile : NavItem("profile", Icons.Default.Person)
object SignIn : NavItem("login", null)
object SignUp : NavItem("signup", null)
object HotelInfo : NavItem("HotelInfo/{hotelItem}", null)
object Booking : NavItem("booking/{hotelItem}", null)
object Person : NavItem("person", null)
object AdminPanel : NavItem("admin", Icons.Default.Build)
object AddPanel : NavItem("add", null)
object ChangePanel : NavItem("change", null)
object ChangeHotel : NavItem("changeHotel/{hotelItem}", null)
}

View File

@ -0,0 +1,83 @@
package com.example.androidlabs.Navigation
import android.annotation.SuppressLint
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem
import androidx.compose.material.Icon
import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun Navigate(){
val navController = rememberNavController()
val listItem = listOf(
NavItem.Home,
NavItem.Profile,
NavItem.AdminPanel
)
Scaffold(bottomBar = {
BottomNavigation(
backgroundColor = Color.White
) {
val navBackStackEntry = navController.currentBackStackEntryAsState()
val currentState = navBackStackEntry.value
listItem.forEach { it ->
val isSelected = currentState?.destination?.route == it.route
BottomNavigationItem(
selected = isSelected,
onClick = {
if(!isSelected){
navController.graph.startDestinationRoute?.let {
navController.popBackStack(it, inclusive = true)
}
navController.navigate(it.route){
launchSingleTop
}
}
navController.navigate(it.route)
},
icon = {
val iconModifier = if (isSelected) {
Modifier
.background(color = Color.LightGray, shape = CircleShape)
.padding(8.dp)
} else {
Modifier
}
it.icon?.let { it1 ->
Icon(
imageVector = it1,
contentDescription = null,
modifier = iconModifier.then(Modifier.size(24.dp))
)
}
}
)
}
}
}) {
NavController(navController = navController)
}
}
@Composable
@Preview
fun NavigatePreview(){
Navigate()
}

View File

@ -0,0 +1,253 @@
package com.example.androidlabs.adminPanel
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.androidlabs.DB.models.PhotoManager
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import com.example.androidlabs.DB.viewModels.HotelViewModel
import com.example.androidlabs.R
@Composable
fun AddPanel(navHostController: NavHostController, hotelViewModel: HotelViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val photoManager = PhotoManager()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
.verticalScroll(rememberScrollState())
) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Image(
painter = painterResource(id = hotelViewModel.img.value),
contentDescription = "image",
contentScale = ContentScale.FillHeight,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.height(200.dp)
)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
hotelViewModel.img.value = photoManager.changePhoto(hotelViewModel.img.value)
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 0.dp, 16.dp, 16.dp)
.height(50.dp)
) {
Text("Add image")
}
TextField(
value = hotelViewModel.name.value,
onValueChange = { hotelViewModel.name.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Name",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = hotelViewModel.stars.value,
onValueChange = { hotelViewModel.stars.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Stars",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = hotelViewModel.location.value,
onValueChange = { hotelViewModel.location.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Location",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = hotelViewModel.price.value,
onValueChange = { hotelViewModel.price.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Price",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = hotelViewModel.info.value,
onValueChange = { hotelViewModel.info.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Info",
style = TextStyle(fontSize = 12.sp)
)
}
)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor =colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
hotelViewModel.insertHotel()
navHostController.navigate("home")
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.height(50.dp)
) {
Text("Add hotel")
}
}
}
}
@Preview(showBackground = true)
@Composable
fun AddPreview() {
//AddPanel()
}

View File

@ -0,0 +1,82 @@
package com.example.androidlabs.adminPanel
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.AlertDialog
import androidx.compose.material.Button
import androidx.compose.material.Text
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.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.androidlabs.DB.models.RoleEnum
import com.example.androidlabs.GlobalUser
import com.example.androidlabs.profileScreen.signIn.LoginScreen
@Composable
fun AdminPanel(navHostController: NavHostController) {
var isAddPanelVisible by remember { mutableStateOf(false) }
var isChangePanelVisible by remember { mutableStateOf(true) }
var showDialog by remember { mutableStateOf(GlobalUser.getInstance().getUser()?.role == "USER" || GlobalUser.getInstance().getUser()?.role == null) }
if (showDialog) {
AlertDialog(
onDismissRequest = { showDialog = false },
title = {
Text("Access denied")
},
text = {
Text("You are not admin")
},
confirmButton = {
Button(
onClick = { navHostController.navigate("home") }
) {
Text("OK")
}
}
)
}
else{
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.padding(bottom = 50.dp)
) {
ButtonAdmin(
onAddClick = {
isAddPanelVisible = true
isChangePanelVisible = false
},
onChangeClick = {
isChangePanelVisible = true
isAddPanelVisible = false
}
)
if (isAddPanelVisible) {
AddPanel(navHostController)
}
if (isChangePanelVisible) {
ChangePanel(navHostController)
}
}
}
}
@Composable
@Preview(showBackground = true)
fun SignInScreenPreview(){
val navController = rememberNavController()
AdminPanel(navController)
}

View File

@ -0,0 +1,70 @@
package com.example.androidlabs.adminPanel
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
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.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import com.example.androidlabs.R
@Composable
fun ButtonAdmin(onAddClick: () -> Unit, onChangeClick: () -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
){
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
onAddClick()
},
modifier = Modifier
.clip(RoundedCornerShape(20.dp))
.fillMaxWidth(0.5f)
.padding(16.dp)
) {
Text("Add")
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
onChangeClick()
},
modifier = Modifier
.clip(RoundedCornerShape(20.dp))
.fillMaxWidth()
.padding(16.dp)
) {
Text("Change/Del")
}
}
}

View File

@ -0,0 +1,114 @@
package com.example.androidlabs.adminPanel
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Create
import androidx.compose.material.icons.filled.Delete
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import com.example.androidlabs.DB.viewModels.HotelViewModel
import com.example.androidlabs.R
import com.google.gson.Gson
@Composable
fun CardHotelForChange(item: Hotel, navController: NavHostController, hotelViewModel: HotelViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
.clip(RoundedCornerShape(10.dp))
.background(colorResource(id = R.color.figma)),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Image(
painter = painterResource(id = item.img),
contentDescription = "image",
contentScale = ContentScale.FillWidth,
modifier = Modifier
.size(70.dp)
.padding(10.dp)
.clip(RoundedCornerShape(10.dp))
)
Column(
modifier = Modifier
.weight(1f)
.padding(start = 16.dp)
) {
item.name?.let { Text(text = it, fontSize = 20.sp) }
Text(text = "${item.location}", color = Color.Red, fontSize = 16.sp)
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
hotelViewModel.name.value = item.name ?: ""
hotelViewModel.price.value = item.price.toString()
hotelViewModel.stars.value = item.stars.toString()
hotelViewModel.location.value = item.location ?: ""
hotelViewModel.info.value = item.info ?: ""
val hotelItemString = Gson().toJson(item)
navController.navigate("changeHotel/${hotelItemString}") },
modifier = Modifier
.padding(end = 16.dp)
) {
Icon(imageVector = Icons.Default.Create, contentDescription = "change")
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
hotelViewModel.deleteHotel(item)
},
modifier = Modifier
.padding(end = 16.dp)
) {
Icon(imageVector = Icons.Default.Delete, contentDescription = "delete")
}
}
}
@Composable
@Preview
fun CardHotelLikePreview(){
val navController = rememberNavController()
//CardHotelForChange(Hotel("Hotel", R.drawable.img, 5, "location", "info", 4000), navController)
}

View File

@ -0,0 +1,255 @@
package com.example.androidlabs.adminPanel
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.material.TextField
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.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.viewModels.HotelViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.androidlabs.DB.models.PhotoManager
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import com.example.androidlabs.R
@Composable
fun ChangeHotel(hotel: Hotel, onBackClick: () -> Unit, hotelViewModel: HotelViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val name = remember { mutableStateOf(hotel.name) }
val price = remember{ mutableStateOf(hotel.price.toString()) }
val stars = remember{ mutableStateOf(hotel.stars.toString()) }
val location = remember{ mutableStateOf(hotel.location) }
val info = remember{ mutableStateOf(hotel.info) }
var img by remember { mutableStateOf(hotel.img) }
val photoManager = PhotoManager()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
.verticalScroll(rememberScrollState())
) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Image(
painter = painterResource(id = img),
contentDescription = "image",
contentScale = ContentScale.FillHeight,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.height(200.dp)
)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
img = photoManager.changePhoto(img)
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 0.dp, 16.dp, 16.dp)
.height(50.dp)
) {
Text("Change image")
}
TextField(
value = name.value,
onValueChange = { newValue -> name.value = newValue },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Name",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = stars.value,
onValueChange = { stars.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Stars",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = location.value,
onValueChange = { location.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Location",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = price.value,
onValueChange = { price.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Price",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = info.value,
onValueChange = { info.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Info",
style = TextStyle(fontSize = 12.sp)
)
}
)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
hotelViewModel.UpdateHotel(
Hotel(
hotelId = hotel.hotelId,
name = name.value,
price = price.value.toDouble(),
img = img,
stars = stars.value.toInt(),
location = location.value,
info = info.value
)
)
onBackClick()
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.height(50.dp)
) {
Text("Change hotel")
}
}
}
}

View File

@ -0,0 +1,44 @@
package com.example.androidlabs.adminPanel
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import com.example.androidlabs.DB.viewModels.HotelViewModel
@Composable
fun ChangePanel(navHostController: NavHostController, hotelViewModel: HotelViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val list = hotelViewModel.HotelList.collectAsLazyPagingItems()
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.padding(16.dp)
){
Row {
LazyColumn(
modifier = Modifier
.fillMaxSize()
) {
items(list.itemCount) { index ->
list[index]?.let { hotel ->
CardHotelForChange(item = hotel, navHostController)
}
}
}
}
}
}

View File

@ -0,0 +1,105 @@
package com.example.androidlabs.api
import com.example.androidlabs.api.model.HotelRemote
import com.example.androidlabs.api.model.OrderRemote
import com.example.androidlabs.api.model.UserRemote
import com.example.androidlabs.api.model.UserRemoteSignIn
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query
interface BackendService {
//SNEAKER
@GET("hotel/get/{id}")
suspend fun getHotel(
@Path("id") id: Int,
): HotelRemote
@GET("hotel/getAll")
suspend fun getHotels(
@Query("page") page: Int,
@Query("size") size: Int,
): List<HotelRemote>
@POST("hotel/create")
suspend fun createHotel(
@Body hotel: HotelRemote,
): HotelRemote
@PUT("hotel/update/{id}")
suspend fun updateHotel(
@Path("id") id: Int,
@Body hotel: HotelRemote
): HotelRemote
@DELETE("hotel/delete/{id}")
suspend fun deleteHotel(
@Path("id") id: Int
)
//USER
@POST("user/signup")
suspend fun SignUp(
@Body user: UserRemote,
): UserRemote
@POST("user/signin")
suspend fun SignIn(
@Body user: UserRemoteSignIn
): UserRemote
@POST("order/create")
suspend fun createOrder(
@Body order: OrderRemote
): Long
@GET("order/getUserOrders/{userId}")
suspend fun getUserOrders(
@Path("userId") userId: Int
) : List<OrderRemote>
@GET("order/getHotelFromOrder/{orderId}")
suspend fun getHotelFromOrder(
@Path("orderId") orderId: Int
) : HotelRemote
@GET("order/deleteOrder/{orderId}")
suspend fun deleteOrder(
@Path("orderId") orderId: Int
)
companion object {
private const val BASE_URL = "https://7w06qshk-8080.euw.devtunnels.ms/api/"
@Volatile
private var INSTANCE: BackendService? = null
fun getInstance(): BackendService {
return INSTANCE ?: synchronized(this) {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BASIC
val client = OkHttpClient.Builder()
.addInterceptor(logger)
.build()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
.create(BackendService::class.java)
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,104 @@
package com.example.androidlabs.api
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.example.androidlabs.DB.AppDatabase
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.models.RemoteKeyType
import com.example.androidlabs.DB.models.RemoteKeys
import com.example.androidlabs.DB.repository.HotelRepImpl
import com.example.androidlabs.DB.repository.RemoteKeysRepositoryImpl
import com.example.androidlabs.api.model.toHotel
import retrofit2.HttpException
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class HotelRemoteMediator(
private val service: BackendService,
private val hotelRepository: HotelRepImpl,
private val database: AppDatabase,
private val dbRemoteKeyRepository: RemoteKeysRepositoryImpl
) : RemoteMediator<Int, Hotel>() {
override suspend fun initialize(): InitializeAction {
return InitializeAction.LAUNCH_INITIAL_REFRESH
}
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, Hotel>
): MediatorResult {
val page = when (loadType) {
LoadType.REFRESH -> {
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
remoteKeys?.nextKey?.minus(1) ?: 1
}
LoadType.PREPEND -> {
val remoteKeys = getRemoteKeyForFirstItem(state)
remoteKeys?.prevKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
}
LoadType.APPEND -> {
val remoteKeys = getRemoteKeyForLastItem(state)
remoteKeys?.nextKey
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
}
}
try {
val sneakers = service.getHotels(page, state.config.pageSize).map { it.toHotel() }
val endOfPaginationReached = sneakers.isEmpty()
database.withTransaction {
if (loadType == LoadType.REFRESH) {
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.SNEAKER)
hotelRepository.clearHotels()
}
val prevKey = if (page == 1) null else page - 1
val nextKey = if (endOfPaginationReached) null else page + 1
val keys = sneakers.map {
RemoteKeys(
entityId = it.hotelId!!,
type = RemoteKeyType.SNEAKER,
prevKey = prevKey,
nextKey = nextKey
)
}
dbRemoteKeyRepository.createRemoteKeys(keys)
hotelRepository.insertHotels(sneakers)
}
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
} catch (exception: IOException) {
return MediatorResult.Error(exception)
} catch (exception: HttpException) {
return MediatorResult.Error(exception)
}
}
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, Hotel>): RemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { hotel ->
hotel.hotelId?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.SNEAKER) }
}
}
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Hotel>): RemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { hotel ->
hotel.hotelId?.let { dbRemoteKeyRepository.getAllRemoteKeys(it, RemoteKeyType.SNEAKER) }
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, Hotel>
): RemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.hotelId?.let { hotelUid ->
dbRemoteKeyRepository.getAllRemoteKeys(hotelUid, RemoteKeyType.SNEAKER)
}
}
}
}

View File

@ -0,0 +1,36 @@
package com.example.androidlabs.api.model
import com.example.androidlabs.DB.models.Hotel
import kotlinx.serialization.Serializable
@Serializable
data class HotelRemote (
val id: Int? = 0,
val name: String = "",
val price: Double = 0.0,
val img: Int = 0,
val stars: Int = 0,
val location: String = "",
val info: String = "",
)
fun HotelRemote.toHotel(): Hotel = Hotel(
id,
name,
price,
img,
stars,
location,
info
)
fun Hotel.toHotelRemote():HotelRemote = HotelRemote(
hotelId,
name,
price,
img,
stars,
location,
info
)

View File

@ -0,0 +1,36 @@
package com.example.androidlabs.api.model
import com.example.androidlabs.DB.models.Order
import kotlinx.serialization.Serializable
@Serializable
data class OrderRemote(
val id: Int? = 0,
val dateFrom: String = "",
val dateTo: String = "",
val rooms: Int = 0,
val total: Double = 0.0,
val userId: Int = 0,
val hotelId: Int = 0
)
fun OrderRemote.toOrder(): Order = Order(
id,
dateFrom,
dateTo,
rooms,
total,
userId,
hotelId,
)
fun Order.toOrderRemote():OrderRemote = OrderRemote(
orderId,
dateFrom,
dateTo,
rooms,
total,
creatorUserId,
bookedHotelId,
)

View File

@ -0,0 +1,41 @@
package com.example.androidlabs.api.model
import androidx.room.ColumnInfo
import androidx.room.PrimaryKey
import com.example.androidlabs.DB.models.User
import com.example.androidlabs.DB.models.RoleEnum
import kotlinx.serialization.Serializable
@Serializable
data class UserRemote (
val id: Int? = 0,
val name: String = "",
val surname: String = "",
val email: String = "",
val password: String = "",
val role: String = "",
val photo: Int? = 0,
)
fun UserRemote.toUser(): User = User(
id,
name,
surname,
email,
password,
role,
photo
)
fun User.toUserRemote():UserRemote = UserRemote(
userId,
name,
surname,
email,
password,
role,
photo
)

View File

@ -0,0 +1,9 @@
package com.example.androidlabs.api.model
import kotlinx.serialization.Serializable
@Serializable
data class UserRemoteSignIn(
val email: String = "",
val password: String = "",
)

View File

@ -0,0 +1,60 @@
package com.example.androidlabs.api.repository
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.androidlabs.AppContainer
import com.example.androidlabs.DB.AppDatabase
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.repository.HotelRepImpl
import com.example.androidlabs.DB.repository.HotelRepository
import com.example.androidlabs.DB.repository.RemoteKeysRepositoryImpl
import com.example.androidlabs.api.BackendService
import com.example.androidlabs.api.HotelRemoteMediator
import com.example.androidlabs.api.model.toHotel
import com.example.androidlabs.api.model.toHotelRemote
import kotlinx.coroutines.flow.Flow
class RestHotelRepository(
private val service: BackendService,
private val dbHotelRepository: HotelRepImpl,
private val database: AppDatabase,
private val dbRemoteKeyRepository: RemoteKeysRepositoryImpl
) : HotelRepository {
override fun getAllHotels(): Flow<PagingData<Hotel>> {
val pagingSourceFactory = { dbHotelRepository.getAllHotelsPagingSource() }
@OptIn(ExperimentalPagingApi::class)
return Pager(
config = PagingConfig(
pageSize = AppContainer.LIMIT,
enablePlaceholders = false
),
remoteMediator = HotelRemoteMediator(
service,
dbHotelRepository,
database,
dbRemoteKeyRepository,
),
pagingSourceFactory = pagingSourceFactory
).flow
}
override suspend fun getHotelById(id: Int): Hotel = service.getHotel(id).toHotel()
override suspend fun insertHotel(hotel: Hotel) {
service.createHotel(hotel.toHotelRemote())
}
override suspend fun updateHotel(hotel: Hotel) {
hotel.hotelId?.let { service.updateHotel(it, hotel.toHotelRemote()) }
}
override suspend fun deleteHotel(hotel: Hotel) {
hotel.hotelId?.let { service.deleteHotel(it) }
}
}

View File

@ -0,0 +1,32 @@
package com.example.androidlabs.api.repository
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.models.Order
import com.example.androidlabs.DB.repository.OrderRepository
import com.example.androidlabs.api.BackendService
import com.example.androidlabs.api.model.toHotel
import com.example.androidlabs.api.model.toOrder
import com.example.androidlabs.api.model.toOrderRemote
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
class RestOrderRepository(private val service: BackendService): OrderRepository {
override suspend fun createOrder(order: Order): Long {
return service.createOrder(order.toOrderRemote())
}
override suspend fun delete(orderId: Int) {
service.deleteOrder(orderId)
}
override suspend fun getHotelFromOrder(id: Int): Hotel {
return service.getHotelFromOrder(id).toHotel()
}
override suspend fun getUserOrders(id: Int): Flow<List<Order>> {
val ordersRemoteList = service.getUserOrders(id)
val ordersList = ordersRemoteList.map { it.toOrder() }
return flowOf(ordersList.toList())
}
}

View File

@ -0,0 +1,25 @@
import com.example.androidlabs.DB.models.User
import com.example.androidlabs.DB.repository.UserRepository
import com.example.androidlabs.api.BackendService
import com.example.androidlabs.api.model.UserRemoteSignIn
import com.example.androidlabs.api.model.toUser
import com.example.androidlabs.api.model.toUserRemote
class RestUserRepository(
private var service: BackendService
): UserRepository {
override suspend fun createUser(user: User) {
service.SignUp(user.toUserRemote())
}
override suspend fun updateUser(user: User) {
println()
}
override suspend fun deleteUser(user: User) {
println()
}
override suspend fun authUser(user: UserRemoteSignIn): User {
return service.SignIn(user).toUser()
}
}

View File

@ -0,0 +1,244 @@
package com.example.androidlabs.booking
import android.widget.DatePicker
import androidx.compose.foundation.background
import androidx.compose.foundation.border
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.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.material.TextField
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.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.viewModels.OrderViewModel
import com.example.androidlabs.GlobalUser
import com.example.androidlabs.R
import android.app.DatePickerDialog
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import java.util.Calendar
import java.util.Date
@Composable
fun BookingScreen(hotel: Hotel, navHostController: NavHostController, orderViewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.padding(16.dp)
,
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Booking",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(16.dp)
)
TextField(
value = orderViewModel.rooms.value,
onValueChange = { orderViewModel.rooms.value = it},
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Rooms",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
// Fetching the Local Context
val mContext = LocalContext.current
// Declaring integer values
// for year, month and day
val mYearFrom: Int
val mMonthFrom: Int
val mDayFrom: Int
// Initializing a Calendar
val mCalendarFrom = Calendar.getInstance()
// Fetching current year, month and day
mYearFrom = mCalendarFrom.get(Calendar.YEAR)
mMonthFrom = mCalendarFrom.get(Calendar.MONTH)
mDayFrom = mCalendarFrom.get(Calendar.DAY_OF_MONTH)
mCalendarFrom.time = Date()
// Declaring a string value to
// store date in string format
val mDateFrom = remember { mutableStateOf("") }
// Declaring DatePickerDialog and setting
// initial values as current values (present year, month and day)
val mDatePickerDialogFrom = DatePickerDialog(
mContext,
{ _: DatePicker, mYear: Int, mMonth: Int, mDayOfMonth: Int ->
mDateFrom.value = "$mDayOfMonth/${mMonth+1}/$mYear"
}, mYearFrom, mMonthFrom, mDayFrom
)
// Creating a button that on
// click displays/shows the DatePickerDialog
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = (colorResource(id = R.color.figma_blue)),
contentColor = Color.White
),
onClick = {
mDatePickerDialogFrom.show()
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
.height(50.dp)
) {
Text("Open Date Picker")
}
// Displaying the mDate value in the Text
Text(text = "Selected Date From: ${mDateFrom.value}", fontSize = 15.sp)
Spacer(modifier = Modifier.height(16.dp))
// Fetching the Local Context
// Declaring integer values
// for year, month and day
val mYear: Int
val mMonth: Int
val mDay: Int
// Initializing a Calendar
val mCalendar = Calendar.getInstance()
// Fetching current year, month and day
mYear = mCalendar.get(Calendar.YEAR)
mMonth = mCalendar.get(Calendar.MONTH)
mDay = mCalendar.get(Calendar.DAY_OF_MONTH)
mCalendar.time = Date()
// Declaring a string value to
// store date in string format
val mDate = remember { mutableStateOf("") }
// Declaring DatePickerDialog and setting
// initial values as current values (present year, month and day)
val mDatePickerDialog = DatePickerDialog(
mContext,
{ _: DatePicker, mYear: Int, mMonth: Int, mDayOfMonth: Int ->
mDate.value = "$mDayOfMonth/${mMonth+1}/$mYear"
}, mYear, mMonth, mDay
)
// Creating a button that on
// click displays/shows the DatePickerDialog
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = (colorResource(id = R.color.figma_blue)),
contentColor = Color.White
),
onClick = {
mDatePickerDialog.show()
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
.height(50.dp)
) {
Text("Open Date Picker")
}
// Displaying the mDate value in the Text
Text(text = "Selected Date To: ${mDate.value}", fontSize = 15.sp,)
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = (colorResource(id = R.color.figma_blue)),
contentColor = Color.White
),
onClick = {
if(GlobalUser.getInstance().getUser() != null){
orderViewModel.selectedItem = hotel
orderViewModel.dateFrom = mDateFrom
orderViewModel.dateTo = mDate
orderViewModel.createOrder()
navHostController.navigate("home")
}else{
navHostController.navigate("login")
}
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
.height(50.dp)
) {
Text("Book")
}
}
}
//@Composable
//@Preview(showBackground = true)
//fun BookingScreenPreview(){
// val navController = rememberNavController()
// BookingScreen()
//}

View File

@ -0,0 +1,109 @@
package com.example.androidlabs.homeScreen.CardItem
import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.icons.Icons
import androidx.compose.material.icons.filled.LocationOn
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.R
import com.google.gson.Gson
@Composable
fun HotelCard (hotel: Hotel, navController: NavHostController){
androidx.compose.material.Card(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
.clickable {
val hotelItemString = Gson().toJson(hotel)
navController.navigate("HotelInfo/${hotelItemString}")
},
shape = RoundedCornerShape(15.dp),
elevation = 5.dp
) {
Box(
modifier = Modifier.background(Color.White)
) {
Row(
modifier = Modifier
//.background(Color.Yellow)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = hotel.img),
contentDescription = "hotel",
contentScale = ContentScale.Fit,
modifier = Modifier
.padding(4.dp)
.size(150.dp)
)
Column(
modifier = Modifier
//.background(Color.Red)
.padding(start = 20.dp),
//horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
Text(text = hotel.name, fontSize = 40.sp, fontWeight = FontWeight.Bold)
Row() {
for (i in 1..hotel.stars){
Image(
painter = painterResource(id = R.drawable.star_rate),
contentDescription = "star",
modifier = Modifier
.size(20.dp)
)
}
for (i in 1.. 5 - hotel.stars){
Image(
painter = painterResource(id = R.drawable.star_outline),
contentDescription = "star",
modifier = Modifier.size(20.dp)
)
}
}
Text(text = hotel.location)
}
Image(
imageVector = Icons.Filled.LocationOn,
contentDescription = "location",
modifier = Modifier.size(40.dp)
)
}
}
}
}
@Preview(showBackground = true)
@Composable
fun CardPreview() {
//HotelCard(Hotel("hotel", R.drawable.img, 4, "location"))
}

View File

@ -0,0 +1,96 @@
package com.example.androidlabs.homeScreen
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import com.example.androidlabs.DB.viewModels.HotelViewModel
import com.example.androidlabs.R
import com.example.androidlabs.homeScreen.CardItem.HotelCard
import com.example.androidlabs.homeScreen.SearchField.SearchField
@Composable
fun HomeScreen(navController: NavHostController, hotelViewModel: HotelViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val list = hotelViewModel.HotelList.collectAsLazyPagingItems()
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
//.padding(bottom = 60.dp)
) {
Box(modifier = Modifier
.background(colorResource(id = R.color.figma_blue))
.fillMaxHeight(0.18f)
){
Column(
modifier = Modifier
.fillMaxHeight(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
){
Text(text= "Beautiful Place to Live", fontSize = 20.sp, fontWeight = FontWeight.Bold,
color = Color.White)
Text(text="Find a Source you want to spent times", color = Color.White)
SearchField(
modifier = Modifier
.padding(horizontal = 10.dp, vertical = 20.dp),
) { searchText ->
// Обработка введенного текста поиска
}
}
}
Column (
modifier = Modifier
//.verticalScroll(rememberScrollState())
.padding(bottom = 60.dp)
){
LazyVerticalGrid(
columns = GridCells.Fixed(1)
) {
items(
count = list.itemCount,
key = list.itemKey { hotel -> hotel.hotelId!! }
) { index: Int ->
val hotel: Hotel? = list[index]
if (hotel != null) {
HotelCard(hotel, navController)
}
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun HotelPreview() {
var nc = rememberNavController()
HomeScreen(nc)
}

View File

@ -0,0 +1,76 @@
package com.example.androidlabs.homeScreen.SearchField
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
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.BasicTextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
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.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@Composable
fun SearchField(
modifier: Modifier = Modifier,
onSearch: (String) -> Unit
) {
var searchText by remember { mutableStateOf("") }
Box(
modifier = modifier
.clip(RoundedCornerShape(30.dp))
.fillMaxWidth()
.background(Color.White)
,
) {
Row(
modifier = Modifier
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
content = {
BasicTextField(
value = searchText,
singleLine = true,
onValueChange = {
searchText = it
onSearch(it)
},
textStyle = TextStyle(color = Color.Black),
modifier = Modifier
.weight(1f)
)
Image(
imageVector = Icons.Filled.Search,
contentDescription = "search",
modifier = Modifier.size(50.dp)
.padding(3.dp)
)
}
)
}
}
@Preview(showBackground = true)
@Composable
fun FieldPreview() {
SearchField(
) { searchText ->
// Обработка введенного текста поиска
}
}

View File

@ -0,0 +1,171 @@
package com.example.androidlabs.hotelScreen
import android.util.Log
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.Image
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
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.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonColors
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Divider
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.androidlabs.DB.models.Hotel
import com.example.androidlabs.R
import com.example.androidlabs.homeScreen.CardItem.HotelCard
import com.google.gson.Gson
@Composable
fun HotelInfo(hotel: Hotel, navController: NavHostController) {
Log.d("MyLog", hotel.toString())
Column (
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.background(Color.White)
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.SpaceBetween,
){
Image(
painter = painterResource(id = hotel.img),
contentDescription = "hotel",
contentScale = ContentScale.FillWidth,
modifier = Modifier
.fillMaxWidth()
)
Box(
modifier = Modifier.background(Color.White)
){
Row (
modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
){
Text(text = hotel.name)
// stars
}
}
Divider(color = Color.Black, thickness = 1.dp)
Box(
modifier = Modifier.background(Color.White)
){
Row (
modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
){
Text(text = "1 room | 1 Night")
Text(text = "Rs. " + hotel.price)
}
}
Divider(color = Color.Black, thickness = 1.dp)
Box(
modifier = Modifier
.background(Color.White)
){
Column (
modifier = Modifier
.fillMaxWidth()
,
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
){
Text(text = "Location")
Text(text = hotel.location)
}
}
Divider(color = Color.Black, thickness = 1.dp)
Box(
modifier = Modifier
.background(Color.White)
){
Column (
modifier = Modifier
.fillMaxWidth()
,
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
){
Text(text = "Amenties")
Text(text = "wifi")
}
}
Divider(color = Color.Black, thickness = 1.dp)
Box(
modifier = Modifier
.background(Color.White)
){
Column (
modifier = Modifier
.fillMaxWidth()
,
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
){
Text(text = "Info")
Text(text = hotel.info)
}
}
Row(
modifier = Modifier
.padding(bottom = 60.dp),
verticalAlignment = Alignment.Bottom
){
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = (colorResource(id = R.color.figma_blue)),
contentColor = Color.White
),
onClick = {
val hotelItemString = Gson().toJson(hotel)
navController.navigate("booking/${hotelItemString}")
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 5.dp)
.height(50.dp)
) {
Text("Select Room")
}
}
}
}
@Preview(showBackground = true)
@Composable
fun HotelInfoPreview() {
val navController = rememberNavController()
// HotelInfo(Hotel("hotel", R.drawable.img_1, 4, "location", "info", 4000), navController)
}

View File

@ -0,0 +1,65 @@
package com.example.androidlabs.profileScreen.profile
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
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.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.androidlabs.GlobalUser
import com.example.androidlabs.R
@Composable
fun Person(navHostController: NavHostController) {
Column(
modifier = Modifier
.background(Color.White)
.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
Button(
onClick = {
GlobalUser.getInstance().setUser(null)
navHostController.navigate("profile")
},
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.white),
contentColor = Color.Black
),
modifier = Modifier
.padding(16.dp, 0.dp)
) {
Text("Exit")
}
ProfileCard(navHostController)
}
}
@Preview
@Composable
fun PersonPreview(){
val navController = rememberNavController()
Person(navController)
}

View File

@ -0,0 +1,90 @@
package com.example.androidlabs.profileScreen.profile
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import com.example.androidlabs.GlobalUser
import com.example.androidlabs.R
@Composable
fun ProfileCard(navHostController: NavHostController) {
val globalUser = GlobalUser.getInstance().getUser()
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
.background(colorResource(id = R.color.figma))
){
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
){
Image(
contentScale = ContentScale.Crop,
painter = painterResource(id = R.drawable.img_1),
contentDescription = null,
modifier = Modifier
.size(150.dp)
.border(2.dp, Color.White, CircleShape)
.padding(16.dp)
.clip(CircleShape)
)
if (globalUser != null) {
Text(
text = "${globalUser.name} ${globalUser.surname}",
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
Text(
text = globalUser.email,
fontSize = 16.sp,
color = Color.Gray
)
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.figma_blue),
contentColor = Color.White
),
onClick = {
navHostController.navigate("myorder")
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
) {
Text("My order")
}
}
}
}

View File

@ -0,0 +1,47 @@
package com.example.androidlabs.profileScreen.profile
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable;
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.colorResource
import com.example.androidlabs.GlobalUser
import com.example.androidlabs.R
import com.example.androidlabs.profileScreen.signIn.LoginScreen
@Composable
fun ProfileScreen(navController: NavHostController) {
val globalUser: GlobalUser = GlobalUser.getInstance()
if(globalUser.getUser() != null){
Person(navController)
}else{
LoginScreen(navController = navController)
}
}
@Composable
@Preview
fun ProfileScreenPreview(){
val navController = rememberNavController()
ProfileScreen(navController = navController)
}

View File

@ -0,0 +1,178 @@
package com.example.androidlabs.profileScreen.signIn
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.material.TextField
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.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import com.example.androidlabs.DB.viewModels.UserViewModel
import com.example.androidlabs.R
@Composable
fun SignInCard(navController: NavHostController, userViewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
){
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
){
var isEmailValid by remember { mutableStateOf(true) }
var isPasswordValid by remember { mutableStateOf(true) }
Text(
text = "Sign In",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(16.dp)
)
TextField(
value = userViewModel.email.value,
onValueChange = {
userViewModel.email.value = it
isEmailValid = userViewModel.isValidEmail(it)},
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Username",
style = TextStyle(fontSize = 12.sp)
)
}
)
if (!isEmailValid) {
Text(
text = "Invalid email format",
color = Color.Red,
style = TextStyle(fontSize = 12.sp)
)
}
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = userViewModel.password.value,
onValueChange = {
userViewModel.password.value = it
isPasswordValid = it.isNotEmpty()
},
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Password",
style = TextStyle(fontSize = 12.sp)
)
}
)
if (!isPasswordValid) {
Text(
text = "Password is required",
color = Color.Red,
style = TextStyle(fontSize = 12.sp)
)
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = (colorResource(id = R.color.figma_blue)),
contentColor = Color.White
),
onClick = {
userViewModel.authUser()
navController.navigate("person")
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
.height(50.dp)
) {
Text("Sign In")
}
ClickableText(
text = AnnotatedString("You do not have an account? Register!"),
modifier = Modifier
.padding(0.dp, 0.dp, 0.dp, 16.dp),
onClick = {
navController.navigate("signup")
}
)
}
}
}
@Composable
@Preview(showBackground = true)
fun SignInScreenPreview(){
val navController = rememberNavController()
LoginScreen(navController = navController)
}

View File

@ -0,0 +1,45 @@
package com.example.androidlabs.profileScreen.signIn
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.androidlabs.profileScreen.profile.ProfileScreen
import androidx.compose.material.Text as Text1
@Composable
fun LoginScreen(navController: NavHostController) {
Column(modifier = Modifier
.fillMaxSize()
.background(Color.White),
verticalArrangement = Arrangement.Center
) {
SignInCard(navController)
}
}
@Composable
@Preview
fun LoginScreenPreview(){
val navController = rememberNavController()
LoginScreen(navController = navController)
}

View File

@ -0,0 +1,199 @@
package com.example.androidlabs.profileScreen.signUp
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.material.TextField
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.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.androidlabs.DB.viewModels.AppViewModelProvider
import com.example.androidlabs.DB.viewModels.UserViewModel
import com.example.androidlabs.R
import com.example.androidlabs.profileScreen.signIn.LoginScreen
@Composable
fun SignUpCard(navHostController: NavHostController, userViewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(16.dp))
){
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
){
Text(
text = "Sign Up",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(16.dp)
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = userViewModel.name.value,
onValueChange = { userViewModel.name.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Name",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = userViewModel.surname.value,
onValueChange = { userViewModel.surname.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Surname",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = userViewModel.email.value,
onValueChange = { userViewModel.email.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Email",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = userViewModel.password.value,
onValueChange = { userViewModel.password.value = it },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(16.dp, 0.dp)
.border(1.dp, Color.Gray, RoundedCornerShape(4.dp)),
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
),
placeholder = {
Text(
text = "Password",
style = TextStyle(fontSize = 12.sp)
)
}
)
Spacer(modifier = Modifier.height(16.dp))
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = (colorResource(id = R.color.figma_blue)),
contentColor = Color.White
),
onClick = {
userViewModel.createUser()
navHostController.navigate("login")
},
modifier = Modifier
.fillMaxWidth()
.padding(16.dp, 16.dp, 16.dp, 0.dp)
.height(50.dp)
) {
Text("Sign Up")
}
}
}
}

View File

@ -0,0 +1,48 @@
package com.example.androidlabs.profileScreen.signUp
import androidx.compose.foundation.background
import androidx.compose.foundation.border
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.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.DropdownMenu
import androidx.compose.material.Text
import androidx.compose.material.TextField
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.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
@Composable
fun SignUpScreen(navHostController: NavHostController) {
Column(modifier = Modifier
.fillMaxSize()
.background(Color.White),
verticalArrangement = Arrangement.Center
) {
SignUpCard(navHostController)
}
}

View File

@ -1,13 +1,14 @@
package com.example.androidlabs.ui.theme
package com.example.androidlabs.ui.theme
/*
import android.app.Activity import android.app.Activity
import android.os.Build import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material3.darkColorScheme import androidx.compose.material.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
@ -68,3 +69,5 @@ fun AndroidLabsTheme(
content = content content = content
) )
} }
*/

View File

@ -1,5 +1,5 @@
package com.example.androidlabs.ui.theme package com.example.androidlabs.ui.theme
/*
import androidx.compose.material3.Typography import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
@ -15,7 +15,7 @@ val Typography = Typography(
lineHeight = 24.sp, lineHeight = 24.sp,
letterSpacing = 0.5.sp letterSpacing = 0.5.sp
) )
/* Other default text styles to override Other default text styles to override
titleLarge = TextStyle( titleLarge = TextStyle(
fontFamily = FontFamily.Default, fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
@ -30,5 +30,6 @@ val Typography = Typography(
lineHeight = 16.sp, lineHeight = 16.sp,
letterSpacing = 0.5.sp letterSpacing = 0.5.sp
) )
*/
) )
*/

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
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="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
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="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
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="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
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="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
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="M14.43,10l-2.43,-8l-2.43,8l-7.57,0l6.18,4.41l-2.35,7.59l6.17,-4.69l6.18,4.69l-2.35,-7.59l6.17,-4.41z"/>
</vector>

View File

@ -7,4 +7,7 @@
<color name="teal_700">#FF018786</color> <color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color> <color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFFFF</color>
<color name="figma">#F4F4F4</color>
<color name="figma_blue">#802A7DB9</color>
</resources> </resources>