feature: lab4 maybe done

This commit is contained in:
Danil Markov 2023-12-09 20:14:52 +04:00
parent f1f3dcf01f
commit 0996e16a84
40 changed files with 862 additions and 555 deletions

View File

@ -9,20 +9,54 @@
<option name="autoReloadType" value="NONE" />
</component>
<component name="ChangeListManager">
<list default="true" id="7c94e195-a540-483e-9a1c-11797aeb1741" name="Changes" comment="feature: lab4 add repos">
<change afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/OrderViewModel.kt" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/ServiceViewModel.kt" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/UserViewModel.kt" afterDir="false" />
<list default="true" id="7c94e195-a540-483e-9a1c-11797aeb1741" name="Changes" comment="feature&amp;fix: lab4 add viewmodel, fix repos">
<change afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/AppContainer.kt" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/AppDataContainer.kt" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/MainActivity.kt" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/AppViewModelProvider.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/build.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/app/build.gradle.kts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/AndroidManifest.xml" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/AndroidManifest.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/App.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/App.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Basket/Basket.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Basket/Basket.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Basket/BasketItemUI.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Basket/BasketItemUI.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/List_of_Services/AddService.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/List_of_Services/AddService.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/List_of_Services/ListOfServices.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/List_of_Services/ListOfServices.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/List_of_Services/Service.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/List_of_Services/Service.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Navbar/NavController.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Navbar/NavController.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Navbar/NavItem.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Navbar/NavItem.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Orders/Orders.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Orders/Orders.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Profile/Login.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Profile/Login.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Profile/Profile.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Profile/Profile.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Profile/ProfileChange.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Profile/ProfileChange.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Profile/ProfileNotAuth.kt" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Profile/Registration.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Profile/Registration.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/UIComponents/MyTextField.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/UIComponents/MyTextField.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/dao/BasketDao.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/dao/BasketDao.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/dao/OrderDao.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/dao/OrderDao.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/dao/ServiceDao.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/dao/ServiceDao.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/dao/UserDao.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/dao/UserDao.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/database/AppDatabase.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/database/AppDatabase.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/Basket.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/Basket.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/BasketItem.kt" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/BasketService.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/BasketService.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/OrderService.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/OrderService.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/Service.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/Service.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/User.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/model/User.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/repository/BasketRepository.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/repository/BasketRepository.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/repository/OrderRepository.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/repository/OrderRepository.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/repository/ServiceRepository.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/repository/ServiceRepository.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/BasketViewModel.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/BasketViewModel.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/OrderViewModel.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/OrderViewModel.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/ServiceViewModel.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/ServiceViewModel.kt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/UserViewModel.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/UserViewModel.kt" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ExecutionTargetManager" SELECTED_TARGET="device_and_snapshot_combo_box_target[6681ed71]" />
<component name="ExecutionTargetManager" SELECTED_TARGET="device_and_snapshot_combo_box_target[adb-6681ed71-4kOMN8._adb-tls-connect._tcp]" />
<component name="ExternalProjectsData">
<projectState path="$PROJECT_DIR$">
<ProjectState />
@ -61,28 +95,34 @@
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;ApkExportedModule&quot;: &quot;My_Application.app&quot;,
&quot;ExportApk.ApkPathForMy_Application.app&quot;: &quot;C:\\Users\\Danil\\Desktop\\MDP\\labs\\app&quot;,
&quot;PROJECT_TRUSTED_KEY&quot;: &quot;true&quot;,
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.cidr.known.project.marker&quot;: &quot;true&quot;,
&quot;cidr.known.project.marker&quot;: &quot;true&quot;,
&quot;com.android.tools.idea.devicemanager.tab&quot;: &quot;Physical&quot;,
&quot;last_opened_file_path&quot;: &quot;C:/Users/Danil/Downloads/test&quot;,
&quot;project.structure.last.edited&quot;: &quot;Modules&quot;,
&quot;project.structure.proportion&quot;: &quot;0.17&quot;,
&quot;project.structure.side.proportion&quot;: &quot;0.2&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;reference.settings.ide.settings.new.ui&quot;
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"ApkExportedModule": "My_Application.app",
"ExportApk.ApkPathForMy_Application.app": "C:\\Users\\Danil\\Desktop\\MDP\\labs\\app",
"PROJECT_TRUSTED_KEY": "true",
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.cidr.known.project.marker": "true",
"cidr.known.project.marker": "true",
"com.android.tools.idea.devicemanager.tab": "Physical",
"last_opened_file_path": "C:/Users/Danil/Downloads/test",
"project.structure.last.edited": "Modules",
"project.structure.proportion": "0.17",
"project.structure.side.proportion": "0.2",
"settings.editor.selected.configurable": "emulator"
},
&quot;keyToStringList&quot;: {
&quot;ExportApk.BuildVariants&quot;: [
&quot;release&quot;
"keyToStringList": {
"ExportApk.BuildVariants": [
"release"
],
"com.android.tools.idea.sqlite.queryhistory": [
"insert into tbl_user values (1, \"Danil\", \"Markov\", \"danil@mail.ru\", \"123\", \"ADMIN\", null)",
"delete from tbl_user where userId = 6",
"delete from tbl_user where userId = 4",
"delete from tbl_user where userId = 2"
]
}
}</component>
}]]></component>
<component name="PsdUISettings">
<option name="MODULE_TAB" value="Signing Configs" />
<option name="LAST_EDITED_SIGNING_CONFIG" value="debug" />
@ -295,7 +335,14 @@
<option name="project" value="LOCAL" />
<updated>1700908930838</updated>
</task>
<option name="localTasksCounter" value="7" />
<task id="LOCAL-00007" summary="feature&amp;fix: lab4 add viewmodel, fix repos">
<created>1700915139985</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1700915139985</updated>
</task>
<option name="localTasksCounter" value="8" />
<servers />
</component>
<component name="Vcs.Log.Tabs.Properties">
@ -314,6 +361,33 @@
<MESSAGE value="feature: UI, lab2 maybe done" />
<MESSAGE value="feature: lab3 is done" />
<MESSAGE value="feature: lab4 add repos" />
<option name="LAST_COMMIT_MESSAGE" value="feature: lab4 add repos" />
<MESSAGE value="feature&amp;fix: lab4 add viewmodel, fix repos" />
<option name="LAST_COMMIT_MESSAGE" value="feature&amp;fix: lab4 add viewmodel, fix repos" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" type="kotlin-line">
<url>file://$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/OrderViewModel.kt</url>
<line>38</line>
<option name="timeStamp" value="18" />
</line-breakpoint>
<line-breakpoint enabled="true" type="kotlin-line">
<url>file://$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/OrderViewModel.kt</url>
<line>36</line>
<option name="timeStamp" value="19" />
</line-breakpoint>
<line-breakpoint enabled="true" type="kotlin-line">
<url>file://$PROJECT_DIR$/app/src/main/java/com/example/myapplication/composeui/Navbar/NavController.kt</url>
<line>63</line>
<option name="timeStamp" value="23" />
</line-breakpoint>
<line-breakpoint enabled="true" type="kotlin-line">
<url>file://$PROJECT_DIR$/app/src/main/java/com/example/myapplication/viewmodel/ServiceViewModel.kt</url>
<line>30</line>
<option name="timeStamp" value="25" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
</project>

View File

@ -80,6 +80,8 @@ dependencies {
implementation("androidx.navigation:navigation-compose:2.7.5")
implementation ("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0-beta01")
implementation ("androidx.paging:paging-compose:3.2.1")
implementation ("androidx.paging:paging-runtime:3.2.1")
//ROOM
val room_version = "2.5.2"

View File

@ -4,6 +4,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name=".App"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
@ -14,7 +15,7 @@
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<activity
android:name=".App"
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyApplication">

View File

@ -1,61 +1,12 @@
package com.example.myapplication
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import com.example.myapplication.composeui.Navbar.NavBar
import com.example.myapplication.database.AppDatabase
import com.example.myapplication.model.User
import com.example.myapplication.ui.theme.AppTheme
import com.example.myapplication.ui.theme.BlueMain
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import android.app.Application
class App : ComponentActivity() {
val database by lazy { AppDatabase.getInstance(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.deleteDatabase("my-db")
CoroutineScope(Dispatchers.IO).launch {
AppDatabase.populateDatabase()
}
setContent {
AppTheme (darkTheme = false){
// A surface container using the 'background' color from the theme
class App : Application() {
lateinit var container: AppContainer
Surface(
modifier = Modifier.fillMaxSize()
.background(BlueMain),
) {
NavBar();
}
}
}
}
}
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 }
}
}
override fun onCreate() {
super.onCreate()
container = AppDataContainer(this)
}
}

View File

@ -0,0 +1,13 @@
package com.example.myapplication
import com.example.myapplication.repository.BasketRepository
import com.example.myapplication.repository.OrderRepository
import com.example.myapplication.repository.ServiceRepository
import com.example.myapplication.repository.UserRepository
interface AppContainer {
val serviceRepo: ServiceRepository
val userRepo: UserRepository
val orderRepo: OrderRepository
val basketRepo: BasketRepository
}

View File

@ -0,0 +1,15 @@
package com.example.myapplication
import android.content.Context
import com.example.myapplication.database.AppDatabase
import com.example.myapplication.repository.BasketRepository
import com.example.myapplication.repository.OrderRepository
import com.example.myapplication.repository.ServiceRepository
import com.example.myapplication.repository.UserRepository
class AppDataContainer(context: Context) : AppContainer {
override val serviceRepo = ServiceRepository(AppDatabase.getInstance(context).serviceDao())
override val userRepo = UserRepository(AppDatabase.getInstance(context).userDao())
override val orderRepo = OrderRepository(AppDatabase.getInstance(context).orderDao())
override val basketRepo = BasketRepository(AppDatabase.getInstance(context).basketDao())
}

View File

@ -0,0 +1,53 @@
package com.example.myapplication
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import com.example.myapplication.composeui.Navbar.NavBar
import com.example.myapplication.model.User
import com.example.myapplication.ui.theme.AppTheme
import com.example.myapplication.ui.theme.BlueMain
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppTheme (darkTheme = false){
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier
.fillMaxSize()
.background(BlueMain),
) {
NavBar();
}
}
}
}
}
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 }
}
}
}
}

View File

@ -1,6 +1,5 @@
package com.example.myapplication.composeui.Basket
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@ -11,8 +10,6 @@ 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.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
@ -20,42 +17,34 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
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.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.myapplication.R
import com.example.myapplication.database.AppDatabase
import com.example.myapplication.GlobalUser
import com.example.myapplication.composeui.Profile.Login
import com.example.myapplication.model.Service
import com.example.myapplication.ui.theme.BlueMain
import com.example.myapplication.ui.theme.GreenBtn
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlin.math.roundToInt
import com.example.myapplication.viewmodel.AppViewModelProvider
import com.example.myapplication.viewmodel.BasketViewModel
import com.example.myapplication.viewmodel.OrderViewModel
@Composable
fun Basket(navController : NavHostController){
val basketList = remember { mutableStateMapOf<Service, Int>() }
val context = LocalContext.current
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
AppDatabase.getInstance(context).basketDao().getBasketWithServices(1).collect { data ->
basketList.clear()
for (item in data.services){
basketList[item] = (basketList[item] ?: 0) + 1
}
}
}
}
fun Basket(navController : NavHostController, basketViewModel: BasketViewModel = viewModel(factory = AppViewModelProvider.Factory), orderViewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val user = GlobalUser.getInstance().getUser()
if (user == null){
Login(navController = navController)
}else{
basketViewModel.updateSubTotal(user.userId!!)
val total = basketViewModel.total.value
val basketList by basketViewModel.getBasketServices(user.userId).collectAsState(initial = null)
Column(
modifier = Modifier
.fillMaxSize()
@ -64,19 +53,11 @@ fun Basket(navController : NavHostController){
.padding(bottom = 60.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = R.drawable.icon_calendar),
contentDescription = null,
modifier = Modifier
.padding(5.dp)
)
LazyColumn {
items(basketList.toList()) { (service, count) ->
key(service.serviceId) {
BasketItemUI(service, count){ newCount ->
basketList[service] = newCount
}
}
val serviceList: List<Service>? = basketList?.services
if (serviceList != null){
orderViewModel.updateSelectedItems(serviceList)
for (item in serviceList){
BasketItemUI(item = item)
}
}
Box(modifier = Modifier
@ -99,26 +80,15 @@ fun Basket(navController : NavHostController){
modifier = Modifier.weight(1f)
)
Text(
text = (getTotalPrice(basketList)).toString(),
style = MaterialTheme.typography.bodyMedium
)
}
Row (
horizontalArrangement = Arrangement.SpaceBetween,
){
Text(
text = "Date:",
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(1f)
)
Text(
text = "11.11.2023:",
text = "$$total",
style = MaterialTheme.typography.bodyMedium
)
}
}
Button(
onClick = { /*TODO*/ },
onClick = {
orderViewModel.createOrder()
},
modifier = Modifier
.height(60.dp)
.fillMaxWidth()
@ -135,11 +105,4 @@ fun Basket(navController : NavHostController){
}
}
}
fun getTotalPrice(basketList: SnapshotStateMap<Service, Int>): Double {
var price = 0.00
for (item in basketList){
price += item.key.price * item.value
}
return (price*100).roundToInt() / 100.0
}

View File

@ -21,10 +21,11 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
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
@ -34,14 +35,28 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.myapplication.GlobalUser
import com.example.myapplication.model.Service
import com.example.myapplication.ui.theme.GreenBtn
import com.example.myapplication.ui.theme.TextPrimary
import com.example.myapplication.viewmodel.AppViewModelProvider
import com.example.myapplication.viewmodel.BasketViewModel
import com.example.myapplication.viewmodel.OrderViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun BasketItemUI(item: Service, count: Int, onCountChanged: (newCount: Int) -> Unit
) {
fun BasketItemUI(item: Service, basketViewModel: BasketViewModel = viewModel(factory = AppViewModelProvider.Factory), orderViewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
val userId = GlobalUser.getInstance().getUser()?.userId!!
val basketStateId = remember { mutableIntStateOf(0) }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
basketStateId.value = basketViewModel.getUsersBasket(userId).basketId!!
}
}
val quantityState by basketViewModel.getQuantityState(basketStateId.value, item.serviceId!!).collectAsState()
Box(
modifier = Modifier
.padding(0.dp, 0.dp, 0.dp, 10.dp)
@ -99,16 +114,14 @@ fun BasketItemUI(item: Service, count: Int, onCountChanged: (newCount: Int) -> U
style = MaterialTheme.typography.bodyMedium
)
Row(verticalAlignment = Alignment.CenterVertically) {
var num by remember { mutableIntStateOf(count) }
Text(
text = num.toString(),
text = "$quantityState",
color = TextPrimary
)
Column(verticalArrangement = Arrangement.SpaceAround) {
Button(
onClick = {
num += 1
onCountChanged(num)
basketViewModel.incrementQuantity(basketStateId.intValue, item.serviceId!!)
},
modifier = Modifier
.size(42.dp)
@ -124,8 +137,10 @@ fun BasketItemUI(item: Service, count: Int, onCountChanged: (newCount: Int) -> U
}
Button(
onClick = {
num -= 1
onCountChanged(num)
if (quantityState == 1) basketViewModel.deleteServiceFromBasket(basketStateId.intValue,
item.serviceId!!
)
basketViewModel.decrementQuantity(basketStateId.intValue, item.serviceId!!)
},
modifier = Modifier
.size(42.dp)

View File

@ -1,7 +1,6 @@
package com.example.myapplication.composeui.List_of_Services
import android.content.ContentResolver
import android.graphics.BitmapFactory
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@ -12,44 +11,47 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.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.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.myapplication.composeui.Navbar.NavItem
import com.example.myapplication.composeui.UIComponents.MyTextField
import com.example.myapplication.model.Service
import com.example.myapplication.ui.theme.BlueMain
import com.example.myapplication.ui.theme.GreenBtn
import com.example.myapplication.ui.theme.TextPrimary
import com.example.myapplication.viewmodel.AppViewModelProvider
import com.example.myapplication.viewmodel.ServiceViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
@Composable
fun AddService (navController: NavController){
var serviceName = ""
var price = ""
var expanded by remember { mutableStateOf(false) }
fun AddService (navController: NavController, service: Service, serviceViewModel: ServiceViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val create = service.serviceId == null
LaunchedEffect(Dispatchers.Default){
if(!create){
serviceViewModel.service.value.serviceId = service.serviceId
serviceViewModel.service.value.photo = service.photo
}
}
Column (
modifier = Modifier
.fillMaxSize()
@ -77,15 +79,29 @@ fun AddService (navController: NavController){
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
){
/* Image(
bitmap = selectedImage!!,
contentDescription = null,
modifier = Modifier
.fillMaxHeight()
.heightIn(min = 100.dp)
.widthIn(max = (LocalConfiguration.current.screenWidthDp / 3).dp),
contentScale = ContentScale.FillHeight,
)*/
if(create){
Image(
painter = painterResource(id = serviceViewModel.photo.intValue),
contentDescription = null,
modifier = Modifier
.fillMaxHeight()
.heightIn(min = 100.dp)
.widthIn(max = (LocalConfiguration.current.screenWidthDp / 3).dp),
contentScale = ContentScale.FillHeight,
)
}else{
service.photo?.let { painterResource(id = it) }?.let {
Image(
painter = it,
contentDescription = null,
modifier = Modifier
.fillMaxHeight()
.heightIn(min = 100.dp)
.widthIn(max = (LocalConfiguration.current.screenWidthDp / 3).dp),
contentScale = ContentScale.FillHeight,
)
}
}
Column(
modifier = Modifier
@ -93,9 +109,14 @@ fun AddService (navController: NavController){
.widthIn(max = (LocalConfiguration.current.screenWidthDp / 3).dp),
verticalArrangement = Arrangement.Top,
){
serviceName?.let {
if(create){
Text(
text = it,
text = serviceViewModel.name.value,
color = TextPrimary,
style = MaterialTheme.typography.bodyMedium)
}else{
Text(
text = service.name,
color = TextPrimary,
style = MaterialTheme.typography.bodyMedium)
}
@ -107,25 +128,42 @@ fun AddService (navController: NavController){
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.CenterHorizontally,
){
Text(
text = "${price}$",
style = MaterialTheme.typography.bodyMedium,
)
if(create){
Text(
text = serviceViewModel.price.doubleValue.toString(),
style = MaterialTheme.typography.bodyMedium,
)
}else{
Text(
text = service.price.toString(),
style = MaterialTheme.typography.bodyMedium,
)
}
}
}
}
Column (
){
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "Service name"){
newValue ->
serviceName = newValue
if(create){
MyTextField(label = "Service name"){
serviceViewModel.name.value = it
}
}else{
MyTextField(label = service.name){
serviceViewModel.service.value.name = it
}
}
}
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "Price"){
newValue ->
price = newValue
if(create){
MyTextField(label = "Price"){
serviceViewModel.price.doubleValue = it.toDouble()
}
}else{
MyTextField(label = service.price.toString()){
serviceViewModel.service.value.price = it.toDouble()
}
}
}
}
@ -149,7 +187,11 @@ fun AddService (navController: NavController){
}
Button(
onClick = {
if (create)
serviceViewModel.createService()
else
serviceViewModel.service.let { serviceViewModel.updateService() }
navController.navigate(NavItem.ListOfServices.route)
},
modifier = Modifier
.height(60.dp)
@ -162,15 +204,11 @@ fun AddService (navController: NavController){
),
contentPadding = PaddingValues(0.dp),
) {
Text(text = "Add service", style = MaterialTheme.typography.bodyMedium.copy(Color.White))
if(create) {
Text(text = "Add service", style = MaterialTheme.typography.bodyMedium.copy(Color.White))
}else{
Text(text = "Update service", style = MaterialTheme.typography.bodyMedium.copy(Color.White))
}
}
}
}
private suspend fun loadSelectedImage(uri: android.net.Uri, contentResolver: ContentResolver): ImageBitmap {
return withContext(Dispatchers.IO) {
val inputStream = contentResolver.openInputStream(uri)
val bitmap = BitmapFactory.decodeStream(inputStream)
bitmap.asImageBitmap()
}
}

View File

@ -6,33 +6,20 @@ import androidx.compose.foundation.layout.Column
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.LaunchedEffect
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.myapplication.database.AppDatabase
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.myapplication.model.Service
import com.example.myapplication.ui.theme.BlueMain
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import com.example.myapplication.viewmodel.AppViewModelProvider
import com.example.myapplication.viewmodel.ServiceViewModel
@Composable
fun ListOfServices(navController: NavHostController){
val serviceList = remember { mutableStateListOf<Service>() }
val context = LocalContext.current
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
AppDatabase.getInstance(context).serviceDao().getAllServices().collect { data ->
serviceList.clear()
serviceList.addAll(data)
}
}
}
fun ListOfServices(navController: NavHostController, serviceViewModel: ServiceViewModel = viewModel(factory = AppViewModelProvider.Factory)){
Column(
modifier = Modifier
.fillMaxSize()
@ -45,9 +32,17 @@ fun ListOfServices(navController: NavHostController){
searchText ->
//TODO search logic
}
val services = serviceViewModel.serviceList.collectAsLazyPagingItems()
LazyColumn(modifier = Modifier.padding(15.dp, 0.dp)){
itemsIndexed(serviceList){_, item ->
Service(item)
items(
count = services.itemCount,
key = services.itemKey { service -> service.serviceId!! }
){
index: Int ->
val service: Service? = services[index]
if (service != null){
Service(navController, item = service)
}
}
}
}

View File

@ -16,8 +16,12 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Create
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -30,12 +34,25 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.myapplication.GlobalUser
import com.example.myapplication.model.BasketService
import com.example.myapplication.model.RoleEnum
import com.example.myapplication.model.Service
import com.example.myapplication.ui.theme.GreenBtn
import com.example.myapplication.ui.theme.TextPrimary
import com.example.myapplication.viewmodel.AppViewModelProvider
import com.example.myapplication.viewmodel.BasketViewModel
import com.example.myapplication.viewmodel.ServiceViewModel
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@Composable
fun Service(item: Service){
fun Service(navController: NavHostController, item: Service, basketViewModel: BasketViewModel = viewModel(factory = AppViewModelProvider.Factory), serviceViewModel: ServiceViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val user = GlobalUser.getInstance().getUser()
Box(
modifier = Modifier
.padding(0.dp, 0.dp, 0.dp, 10.dp)
@ -73,11 +90,30 @@ fun Service(item: Service){
.widthIn(max = (LocalConfiguration.current.screenWidthDp / 3).dp),
verticalArrangement = Arrangement.Top,
){
item.name?.let {
Text(
text = it,
color = TextPrimary,
style = MaterialTheme.typography.bodyMedium)
Text(
text = item.name,
color = TextPrimary,
style = MaterialTheme.typography.bodyMedium)
if(user?.role == RoleEnum.Admin){
Button(
onClick = {
runBlocking {
launch(Dispatchers.Default){
serviceViewModel.deleteService(item)
}
}
},
modifier = Modifier
.size(42.dp)
.clip(CircleShape),
colors = ButtonDefaults.buttonColors(
containerColor = GreenBtn,
contentColor = Color.White
),
contentPadding = PaddingValues(0.dp),
){
Icon(imageVector = Icons.Default.Delete, contentDescription = null)
}
}
}
Column(
@ -93,7 +129,13 @@ fun Service(item: Service){
style = MaterialTheme.typography.bodyMedium,
)
Button(
onClick = { /*TODO*/ },
onClick = {
runBlocking{
launch(Dispatchers.Default){
basketViewModel.addToBasket(BasketService(basketViewModel.getUsersBasket(user?.userId!!).basketId!!, item.serviceId!!, 1))
}
}
},
modifier = Modifier
.size(42.dp)
.clip(CircleShape),
@ -105,6 +147,24 @@ fun Service(item: Service){
){
Text(text = "+")
}
if(user?.role == RoleEnum.Admin){
Button(
onClick = {
serviceViewModel.service.value = item
navController.navigate("add_service/${Gson().toJson(item)}")
},
modifier = Modifier
.size(42.dp)
.clip(CircleShape),
colors = ButtonDefaults.buttonColors(
containerColor = GreenBtn,
contentColor = Color.White
),
contentPadding = PaddingValues(0.dp),
){
Icon(imageVector = Icons.Default.Create, contentDescription = null)
}
}
}
}
}

View File

@ -12,15 +12,15 @@ import com.example.myapplication.composeui.Orders.Orders
import com.example.myapplication.composeui.Profile.Login
import com.example.myapplication.composeui.Profile.Profile
import com.example.myapplication.composeui.Profile.ProfileChange
import com.example.myapplication.composeui.Profile.ProfileNotAuth
import com.example.myapplication.composeui.Profile.Registration
import com.example.myapplication.model.Service
import com.google.gson.Gson
@Composable
fun NavController(navController : NavHostController){
NavHost(
navController = navController,
startDestination = NavItem.ListOfServices.route,
){
composable(
NavItem.ListOfServices.route
@ -28,60 +28,43 @@ fun NavController(navController : NavHostController){
ListOfServices(navController)
}
composable(
// "${NavItem.Basket.route}/{userId}"
"${NavItem.Basket.route}"
NavItem.Basket.route
){
Basket(navController)
// backStackEntry ->
// backStackEntry.arguments?.getString("userId")?.let {
// Basket(
// navController,
// it.toLong()
// )
// }
}
composable(
// "${NavItem.Profile.route}/{userId}"
"${NavItem.Profile.route}"
NavItem.Profile.route
){
Profile(navController)
// backStackEntry ->
// backStackEntry.arguments?.getString("userId")?.let {
// Profile(
// navController,
// it.toLong()
// )
// }
}
composable(
"${NavItem.ProfileChange.route}"
NavItem.ProfileChange.route
){
ProfileChange(navController)
}
composable(
"${NavItem.Orders.route}"
NavItem.Orders.route
){
Orders(navController)
}
composable(
"${NavItem.ProfileNotAuth.route}"
){
ProfileNotAuth(navController)
}
composable(
"${NavItem.Login.route}"
NavItem.Login.route
){
Login(navController)
}
composable(
"${NavItem.Registration.route}"
NavItem.Registration.route
){
Registration(navController)
}
composable(
"${NavItem.AddService.route}"
NavItem.AddService.route
){
AddService(navController)
backStackEntry ->
val serviceItemString = backStackEntry.arguments?.getString("serviceItem")
val serviceItem = Gson().fromJson(serviceItemString, Service::class.java)
serviceItem?.let { AddService(navController, it)
}
}
}
}

View File

@ -27,10 +27,6 @@ sealed class NavItem(
"orders",
R.drawable.icon_profile
)
object ProfileNotAuth : NavItem(
"profile_not_auth",
R.drawable.icon_profile
)
object Login : NavItem(
"login",
R.drawable.icon_profile
@ -40,7 +36,7 @@ sealed class NavItem(
R.drawable.icon_profile
)
object AddService : NavItem(
"add_service",
"add_service/{serviceItem}",
R.drawable.icon_list_of_services
)
}

View File

@ -11,24 +11,26 @@ import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.myapplication.database.AppDatabase
import com.example.myapplication.GlobalUser
import com.example.myapplication.model.Order
import com.example.myapplication.ui.theme.BlueMain
import com.example.myapplication.viewmodel.AppViewModelProvider
import com.example.myapplication.viewmodel.OrderViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun Orders (navController: NavController){
fun Orders (navController: NavController, orderViewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val ordersList = remember { mutableStateListOf<Order>() }
val context = LocalContext.current
val user = GlobalUser.getInstance().getUser()
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
AppDatabase.getInstance(context).orderDao().getAllOrder().collect { data ->
orderViewModel.getUserOrders(user?.userId!!).collect { data ->
ordersList.clear()
ordersList.addAll(data)
ordersList.addAll(data.orders)
}
}
}

View File

@ -16,6 +16,10 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.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
@ -23,15 +27,18 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.myapplication.composeui.Navbar.NavItem
import com.example.myapplication.composeui.UIComponents.MyTextField
import com.example.myapplication.ui.theme.BlueMain
import com.example.myapplication.ui.theme.GreenBtn
import com.example.myapplication.ui.theme.TextSecondary
import com.example.myapplication.viewmodel.AppViewModelProvider
import com.example.myapplication.viewmodel.UserViewModel
@Composable
fun Login (navController: NavController){
fun Login (navController: NavController, userViewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
Column(
modifier = Modifier
.fillMaxSize()
@ -55,19 +62,45 @@ fun Login (navController: NavController){
}
Column (
){
Row (modifier = Modifier
.padding(vertical = 5.dp)
){
MyTextField(label = "Email", onValueChanged = {})
var isEmailValid by remember { mutableStateOf(true)}
var isPasswordValid by remember { mutableStateOf(true)}
if (!isEmailValid) {
Text(
text = "Invalid email format",
style = MaterialTheme.typography.bodyMedium
.copy(Color.Red, fontSize = TextUnit(4.0f, TextUnitType.Em))
)
}
Row (modifier = Modifier
.padding(vertical = 5.dp)
){
MyTextField(label = "Password", onValueChanged = {})
MyTextField(label = "Email", onValueChanged = {
userViewModel.email.value = it
isEmailValid = userViewModel.isValidEmail()
})
}
if (!isPasswordValid) {
Text(
text = "Password is required",
style = MaterialTheme.typography.bodyMedium
.copy(Color.Red, fontSize = TextUnit(4.0f, TextUnitType.Em))
)
}
Row (modifier = Modifier
.padding(vertical = 5.dp)
){
MyTextField(label = "Password", onValueChanged = {
userViewModel.password.value = it
isPasswordValid = it.isNotEmpty()
})
}
}
Button(
onClick = { navController.navigate(NavItem.ListOfServices.route) },
onClick = {
userViewModel.authUser()
navController.navigate(NavItem.Profile.route)
},
modifier = Modifier
.height(60.dp)
.padding(top = 10.dp)

View File

@ -18,35 +18,26 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
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.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import com.example.myapplication.GlobalUser
import com.example.myapplication.composeui.Navbar.NavItem
import com.example.myapplication.database.AppDatabase
import com.example.myapplication.model.User
import com.example.myapplication.model.RoleEnum
import com.example.myapplication.ui.theme.BlueMain
import com.example.myapplication.ui.theme.GreenBtn
import com.example.myapplication.ui.theme.RedBtn
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
fun Profile(navController: NavHostController){
val context = LocalContext.current
val user = remember { mutableStateOf<User?>(null)}
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
user.value = AppDatabase.getInstance(context).userDao().getUserById(2)
}
}
val user = GlobalUser.getInstance().getUser()
if(user == null){
Login(navController = navController)
}else{
Column (
modifier = Modifier
.fillMaxSize()
@ -62,20 +53,9 @@ fun Profile(navController: NavHostController){
){
// TODO: upload profile image
}
Box(modifier = Modifier.padding(15.dp)){
Text(
text = user.value?.name + " " + user.value?.surname,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.fillMaxWidth()
.align(Alignment.Center),
textAlign = TextAlign.Center,
)
}
Box(modifier = Modifier.padding(15.dp)){
user.value?.email?.let {
Box(modifier = Modifier.padding(15.dp)){
Text(
text = it,
text = user.name + " " + user.surname,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.fillMaxWidth()
@ -83,7 +63,17 @@ fun Profile(navController: NavHostController){
textAlign = TextAlign.Center,
)
}
}
Box(modifier = Modifier.padding(15.dp)){
Text(
text = user.email,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.fillMaxWidth()
.align(Alignment.Center),
textAlign = TextAlign.Center,
)
}
Button(
onClick = { navController.navigate(NavItem.ProfileChange.route) },
modifier = Modifier
@ -122,27 +112,32 @@ fun Profile(navController: NavHostController){
color = Color.White
)
}
Button(
onClick = { navController.navigate(NavItem.AddService.route) },
modifier = Modifier
.height(60.dp)
.fillMaxWidth()
.clip(CircleShape)
.padding(vertical = 5.dp),
colors = ButtonDefaults.buttonColors(
containerColor = GreenBtn,
contentColor = Color.White
),
contentPadding = PaddingValues(0.dp),
) {
Text(
text = "Add service",
style = MaterialTheme.typography.bodyMedium,
color = Color.White
)
if(user.role == RoleEnum.Admin){
Button(
onClick = { navController.navigate("add_service/{}") },
modifier = Modifier
.height(60.dp)
.fillMaxWidth()
.clip(CircleShape)
.padding(vertical = 5.dp),
colors = ButtonDefaults.buttonColors(
containerColor = GreenBtn,
contentColor = Color.White
),
contentPadding = PaddingValues(0.dp),
) {
Text(
text = "Add service",
style = MaterialTheme.typography.bodyMedium,
color = Color.White
)
}
}
Button(
onClick = { navController.navigate(NavItem.ProfileNotAuth.route) },
onClick = {
GlobalUser.getInstance().setUser(null)
navController.navigate(NavItem.Login.route)
},
modifier = Modifier
.height(60.dp)
.fillMaxWidth()
@ -167,3 +162,4 @@ fun Profile(navController: NavHostController){
}
}
}
}

View File

@ -1,8 +1,6 @@
package com.example.myapplication.composeui.Profile
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.PaddingValues
@ -13,11 +11,6 @@ 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.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material3.AlertDialogDefaults.shape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
@ -27,28 +20,30 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
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.graphics.Shape
import androidx.compose.ui.modifier.modifierLocalConsumer
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.example.myapplication.GlobalUser
import com.example.myapplication.R
import com.example.myapplication.composeui.Navbar.NavItem
import com.example.myapplication.composeui.UIComponents.MyTextField
import com.example.myapplication.ui.theme.BlueBorder
import com.example.myapplication.ui.theme.BlueMain
import com.example.myapplication.ui.theme.GreenBtn
import com.example.myapplication.ui.theme.TextSecondary
import com.example.myapplication.viewmodel.AppViewModelProvider
import com.example.myapplication.viewmodel.UserViewModel
@Composable
fun ProfileChange (navController: NavHostController){
fun ProfileChange (navController: NavHostController, userViewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val user = GlobalUser.getInstance().getUser()
Column (
modifier = Modifier
.fillMaxSize()
@ -72,7 +67,7 @@ fun ProfileChange (navController: NavHostController){
}
Box(modifier = Modifier.padding(15.dp)){
Text(
text = "Name Surname",
text = "${user?.name} ${user?.surname}",
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.fillMaxWidth()
@ -82,7 +77,7 @@ fun ProfileChange (navController: NavHostController){
}
Box(modifier = Modifier.padding(15.dp)){
Text(
text = "example@mail.ex",
text = "${user?.email}",
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.fillMaxWidth()
@ -93,23 +88,48 @@ fun ProfileChange (navController: NavHostController){
Column (
){
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "Name", onValueChanged = {})
MyTextField(label = "Name", onValueChanged = {userViewModel.name.value = it})
}
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "Surname", onValueChanged = {})
MyTextField(label = "Surname", onValueChanged = {userViewModel.surname.value = it})
}
var isEmailValid by remember { mutableStateOf(true) }
var isPasswordValid by remember { mutableStateOf(true) }
if (!isEmailValid) {
Text(
text = "Invalid email format",
style = MaterialTheme.typography.bodyMedium
.copy(Color.Red, fontSize = TextUnit(4.0f, TextUnitType.Em))
)
}
Row (modifier = Modifier
.padding(vertical = 5.dp)
){
MyTextField(label = "Email", onValueChanged = {
userViewModel.email.value = it
isEmailValid = userViewModel.isValidEmail()
})
}
if (!isPasswordValid) {
Text(
text = "Password is required",
style = MaterialTheme.typography.bodyMedium
.copy(Color.Red, fontSize = TextUnit(4.0f, TextUnitType.Em))
)
}
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "Email", onValueChanged = {})
}
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "Old password", onValueChanged = {})
}
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "New password", onValueChanged = {})
MyTextField(label = "Password", onValueChanged = {
userViewModel.password.value = it
isPasswordValid = it.isNotEmpty()
})
}
}
Button(
onClick = { /*TODO*/ },
onClick = {
userViewModel.updateUser()
navController.navigate(NavItem.Profile.route)
},
modifier = Modifier
.height(60.dp)
.padding(top = 10.dp)

View File

@ -1,81 +0,0 @@
package com.example.myapplication.composeui.Profile
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
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.CircleShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.example.myapplication.composeui.Navbar.NavItem
import com.example.myapplication.ui.theme.BlueMain
import com.example.myapplication.ui.theme.GreenBtn
@Composable
fun ProfileNotAuth (navController: NavController){
Column(
modifier = Modifier
.fillMaxSize()
.background(BlueMain)
.padding(15.dp)
.padding(bottom = 60.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
){
Row (
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(bottom = 15.dp)
){
Button(
onClick = { navController.navigate(NavItem.Login.route) },
modifier = Modifier
.height(60.dp)
.fillMaxWidth()
.clip(CircleShape),
colors = ButtonDefaults.buttonColors(
containerColor = GreenBtn,
contentColor = Color.White
),
contentPadding = PaddingValues(0.dp),
) {
Text(
text = "Login",
style = MaterialTheme.typography.bodyMedium
.copy(Color.White)
)
}
}
Button(
onClick = { navController.navigate(NavItem.Registration.route) },
modifier = Modifier
.height(60.dp)
.fillMaxWidth()
.clip(CircleShape),
colors = ButtonDefaults.buttonColors(
containerColor = GreenBtn,
contentColor = Color.White
),
contentPadding = PaddingValues(0.dp),
) {
Text(
text = "Registration",
style = MaterialTheme.typography.bodyMedium
.copy(Color.White)
)
}
}
}

View File

@ -16,6 +16,10 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.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
@ -23,15 +27,18 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.myapplication.composeui.Navbar.NavItem
import com.example.myapplication.composeui.UIComponents.MyTextField
import com.example.myapplication.ui.theme.BlueMain
import com.example.myapplication.ui.theme.GreenBtn
import com.example.myapplication.ui.theme.TextSecondary
import com.example.myapplication.viewmodel.AppViewModelProvider
import com.example.myapplication.viewmodel.UserViewModel
@Composable
fun Registration (navController: NavController){
fun Registration (navController: NavController, userViewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
Column(
modifier = Modifier
.fillMaxSize()
@ -56,20 +63,50 @@ fun Registration (navController: NavController){
Column (
){
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "Name", onValueChanged = {})
MyTextField(label = "Name", onValueChanged = { userViewModel.name.value = it })
}
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "Surname", onValueChanged = {})
MyTextField(label = "Surname", onValueChanged = { userViewModel.surname.value = it })
}
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "Email", onValueChanged = {})
var isEmailValid by remember { mutableStateOf(true) }
var isPasswordValid by remember { mutableStateOf(true) }
if (!isEmailValid) {
Text(
text = "Invalid email format",
style = MaterialTheme.typography.bodyMedium
.copy(Color.Red, fontSize = TextUnit(4.0f, TextUnitType.Em))
)
}
Row (modifier = Modifier.padding(vertical = 5.dp)){
MyTextField(label = "Password", onValueChanged = {})
Row (modifier = Modifier
.padding(vertical = 5.dp)
){
MyTextField(label = "Email", onValueChanged = {
userViewModel.email.value = it
isEmailValid = userViewModel.isValidEmail()
})
}
if (!isPasswordValid) {
Text(
text = "Password is required",
style = MaterialTheme.typography.bodyMedium
.copy(Color.Red, fontSize = TextUnit(4.0f, TextUnitType.Em))
)
}
Row (modifier = Modifier
.padding(vertical = 5.dp)
){
MyTextField(label = "Password", onValueChanged = {
userViewModel.password.value = it
isPasswordValid = it.isNotEmpty()
})
}
}
Button(
onClick = { navController.navigate(NavItem.ListOfServices.route)},
onClick = {
userViewModel.createUser()
navController.navigate(NavItem.Login.route)
},
modifier = Modifier
.height(60.dp)
.padding(top = 10.dp)

View File

@ -28,7 +28,7 @@ import com.example.myapplication.ui.theme.TextSecondary
@Composable
fun MyTextField (
label: String,
onValueChanged: (String) -> Unit
onValueChanged: (String) -> Unit,
){
val textState = remember { mutableStateOf(TextFieldValue()) }
val text by rememberUpdatedState(newValue = textState.value)
@ -46,13 +46,16 @@ fun MyTextField (
if(textState.value.text.isEmpty()){
Text(
text = label,
style = MaterialTheme.typography.bodyMedium.copy(color = TextSecondary)
style = MaterialTheme.typography.bodyMedium.copy(color = TextSecondary),
)
}else{
}
BasicTextField(
value = text,
onValueChange = { newValue ->
textState.value = newValue
onValueChange = {
textState.value = it
onValueChanged(it.text)
},
modifier = Modifier.fillMaxWidth(),
textStyle = MaterialTheme.typography.bodyMedium,

View File

@ -16,9 +16,27 @@ interface BasketDao {
@Insert
suspend fun insertBasketService(basketService: BasketService)
@Query("SELECT * FROM tbl_basket WHERE creatorUserId = :id")
suspend fun getBasketWithServices(id: Int): Flow<BasketWithServices>
fun getBasketWithServices(id: Int): Flow<BasketWithServices>
@Query("SELECT * FROM tbl_basket WHERE creatorUserId = :id")
suspend fun getUsersBasket(id: Int): Basket
@Query("SELECT * FROM tbl_basket")
suspend fun getAllBaskets(): Flow<List<Basket>>
fun getAllBaskets(): Flow<List<Basket>>
@Delete
suspend fun delete(basket: Basket)
@Query("DELETE FROM tbl_basket_service WHERE basketId = :basketId AND serviceId = :serviceId")
suspend fun removeServiceFromBasket(basketId: Int, serviceId: Int)
@Query("UPDATE tbl_basket_service SET quantity = :quantity WHERE basketId = :basketId AND serviceId = :serviceId")
suspend fun updateServiceQuantity(basketId: Int, serviceId: Int, quantity: Int)
@Query("UPDATE tbl_basket_service SET quantity = quantity + 1 WHERE basketId = :basketId AND serviceId = :serviceId")
suspend fun incrementServiceQuantity(basketId: Int, serviceId: Int)
@Query("UPDATE tbl_basket_service SET quantity = quantity - 1 WHERE basketId = :basketId AND serviceId = :serviceId")
suspend fun decrementServiceQuantity(basketId: Int, serviceId: Int)
@Query("SELECT quantity FROM tbl_basket_service WHERE basketId = :basketId AND serviceId = :serviceId")
suspend fun getQuantity(basketId: Int, serviceId: Int): Int?
@Query("SELECT * FROM tbl_basket_service WHERE basketId = :basketId AND serviceId = :serviceId")
suspend fun getService(basketId: Int, serviceId: Int): BasketService?
@Query("SELECT SUM(price * quantity) FROM tbl_basket_service bs JOIN tbl_service s ON bs.serviceId = s.serviceId WHERE bs.basketId = :basketId")
suspend fun getTotalPriceForBasket(basketId: Int): Double?
@Query("DELETE FROM tbl_basket_service WHERE basketId = :basketId")
suspend fun clearBasket(basketId: Int)
}

View File

@ -19,9 +19,9 @@ interface OrderDao {
@Insert
suspend fun insertOrderService(orderService: OrderService)
@Query("SELECT * FROM tbl_order WHERE orderId = :id")
suspend fun getOrderWithServices(id: Int): Flow<OrderWithServices>
fun getOrderWithServices(id: Int): Flow<OrderWithServices>
@Query("SELECT * FROM tbl_order")
suspend fun getAllOrders(): Flow<List<Order>>
fun getAllOrders(): Flow<List<Order>>
@Query("SELECT * FROM tbl_user WHERE userId =:id")
suspend fun getUserOrders(id: Int) : Flow<UserWithOrder>
fun getUserOrders(id: Int) : Flow<UserWithOrder>
}

View File

@ -1,5 +1,6 @@
package com.example.myapplication.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
@ -20,8 +21,9 @@ interface ServiceDao {
suspend fun delete(service: Service)
@Query("SELECT*FROM tbl_service")
suspend fun getAllServices(): Flow<List<Service>>
fun getAllServices(): Flow<List<Service>>
@Query("SELECT*FROM tbl_service")
fun getAllServicesPaged(): PagingSource<Int, Service>
@Query("SELECT * FROM tbl_service WHERE serviceId = :id")
suspend fun getServiceById(id: Int): Service
}

View File

@ -27,5 +27,5 @@ interface UserDao {
suspend fun getUserByEmail(email: String): User
@Query("SELECT * FROM tbl_user WHERE userId =:id")
suspend fun getUserOrders(id: Int) : Flow<UserWithOrder>
fun getUserOrders(id: Int) : Flow<UserWithOrder>
}

View File

@ -5,7 +5,6 @@ import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.myapplication.R
import com.example.myapplication.dao.BasketDao
import com.example.myapplication.dao.OrderDao
import com.example.myapplication.dao.ServiceDao
@ -20,9 +19,8 @@ import com.example.myapplication.model.User
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.Date
@Database(entities = [User::class, Service::class, Order::class, OrderService::class, Basket::class, BasketService::class], version = 4)
@Database(entities = [User::class, Service::class, Order::class, OrderService::class, Basket::class, BasketService::class], version = 7)
abstract class AppDatabase : RoomDatabase(){
abstract fun serviceDao(): ServiceDao
abstract fun userDao(): UserDao
@ -39,36 +37,11 @@ abstract class AppDatabase : RoomDatabase(){
INSTANCE?.let { database ->
// User
val userDao = database.userDao()
val user1 = User(null, "Artem", "Emelyanov", "artem@mail.ru", "123", RoleEnum.User)
val user2 = User(null, "Danil", "Markov", "danil@mail.ru", "123", RoleEnum.Admin)
val user3 = User(null, "Viktoria", "Presnyakova", "vika@mail.ru", "123", RoleEnum.User)
userDao.createUser(user1)
userDao.createUser(user2)
userDao.createUser(user3)
// Service
val serviceDao = database.serviceDao()
val service1 = Service(null, "Test", 19.09, R.drawable.image_service)
val service2 = Service(null, "Test", 19.09, R.drawable.image_service)
val service3 = Service(null, "Test", 19.09, R.drawable.image_service)
val service4 = Service(null, "Test", 19.09, R.drawable.image_service)
val serviceId1 = serviceDao.insert(service1).toInt()
val serviceId2 = serviceDao.insert(service2).toInt()
serviceDao.insert(service3)
serviceDao.insert(service4)
// Order
val orderDao = database.orderDao()
val order1 = Order(null, Date().time, 200.00, 1)
val order2 = Order(null, Date().time, 200.00, 1)
val orderId1 = orderDao.createOrder(order1).toInt()
val orderId2 = orderDao.createOrder(order2).toInt()
orderDao.insertOrderService(OrderService(orderId1, serviceId1))
orderDao.insertOrderService(OrderService(orderId2, serviceId2))
// Basket
val user1 = User(null, "Danil", "Markov", "danil@mail.ru", "123", RoleEnum.Admin)
userDao.insert(user1)
val basketDao = database.basketDao()
val basket = Basket(null, Date().time, 200.00, 1)
val basketId = basketDao.createBasket(basket).toInt()
basketDao.insertBasketService(BasketService(null, basketId, serviceId1))
basketDao.insertBasketService(BasketService(null, basketId, serviceId1))
val basket1 = Basket(null, user1.userId!!)
basketDao.insert(basket1)
}
}

View File

@ -5,9 +5,7 @@ import androidx.room.PrimaryKey
@Entity(tableName = "tbl_basket")
data class Basket(
@PrimaryKey(autoGenerate = true)
@PrimaryKey
val basketId: Int? = null,
val date: Long,
val total: Double,
val creatorUserId: Int
)

View File

@ -1,6 +0,0 @@
package com.example.myapplication.model
data class BasketItem (
val service: Service,
val count: Int
)

View File

@ -1,12 +1,11 @@
package com.example.myapplication.model
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "tbl_basket_service")
@Entity(tableName = "tbl_basket_service",
primaryKeys = ["basketId", "serviceId"])
data class BasketService(
@PrimaryKey(autoGenerate = true)
val basketServiceId: Int? = null,
val basketId: Int,
val serviceId: Int,
val quantity: Int
)

View File

@ -5,5 +5,6 @@ import androidx.room.Entity
@Entity(primaryKeys = ["orderId", "serviceId"], tableName = "tbl_order_service")
data class OrderService(
val orderId: Int,
val serviceId: Int
val serviceId: Int,
val quantity: Int
)

View File

@ -6,8 +6,8 @@ import androidx.room.PrimaryKey
@Entity(tableName="tbl_service")
data class Service (
@PrimaryKey(autoGenerate = true)
val serviceId: Int? = null,
val name: String,
val price: Double,
val photo: Int? = null
var serviceId: Int? = null,
var name: String,
var price: Double,
var photo: Int? = null
)

View File

@ -7,10 +7,10 @@ import androidx.room.PrimaryKey
data class User(
@PrimaryKey(autoGenerate = true)
val userId: Int? = null,
val name: String,
val surname: String,
val email: String,
val password: String,
var name: String,
var surname: String,
var email: String,
var password: String,
val role: RoleEnum,
val photo: Int? = null
)

View File

@ -3,11 +3,22 @@ package com.example.myapplication.repository
import com.example.myapplication.dao.BasketDao
import com.example.myapplication.model.Basket
import com.example.myapplication.model.BasketService
import com.example.myapplication.model.BasketWithServices
import kotlinx.coroutines.flow.Flow
class BasketRepository(private val basketDao: BasketDao) {
suspend fun insert(basket: Basket) = basketDao.insert(basket)
suspend fun createBasket(basket: Basket): Long = basketDao.insert(basket)
suspend fun getUsersBasket(userId: Int): Basket = basketDao.getUsersBasket(userId)
suspend fun removeServiceFromBasket(basketId: Int, serviceId: Int) = basketDao.removeServiceFromBasket(basketId, serviceId)
suspend fun updateServiceQuantity(basketId: Int, serviceId: Int, quantity: Int) = basketDao.updateServiceQuantity(basketId, serviceId, quantity)
suspend fun incrementServiceQuantity(basketId: Int, serviceId: Int) = basketDao.incrementServiceQuantity(basketId, serviceId)
suspend fun decrementServiceQuantity(basketId: Int, serviceId: Int) = basketDao.decrementServiceQuantity(basketId, serviceId)
suspend fun insertBasketService(basketService: BasketService) = basketDao.insertBasketService(basketService)
fun getBasketWithServices(id: Int): Flow<BasketWithServices> = basketDao.getBasketWithServices(id)
fun getAllBasket(): Flow<List<Basket>> = basketDao.getAllBaskets()
suspend fun delete(basket: Basket) = basketDao.delete(basket)
suspend fun getBasketWithServices(id: Int) = basketDao.getBasketWithServices(id)
suspend fun getAllBaskets() = basketDao.getAllBaskets()
suspend fun getQuantity(basketId: Int, serviceId: Int): Int? = basketDao.getQuantity(basketId, serviceId)
suspend fun getService(basketId: Int, serviceId: Int): BasketService? = basketDao.getService(basketId, serviceId)
suspend fun getTotalPriceForBasket(basketId: Int): Double? = basketDao.getTotalPriceForBasket(basketId)
suspend fun clearBasket(basketId: Int) = basketDao.clearBasket(basketId)
}

View File

@ -8,7 +8,7 @@ class OrderRepository(private val orderDao: OrderDao) {
suspend fun insert(order: Order) = orderDao.insert(order)
suspend fun insertOrderService(orderService: OrderService) = orderDao.insertOrderService(orderService)
suspend fun delete(order: Order) = orderDao.delete(order)
suspend fun getOrderWithServices(id: Int) = orderDao.getOrderWithServices(id)
suspend fun getAllOrders() = orderDao.getAllOrders()
suspend fun getUserOrders(id: Int) = orderDao.getUserOrders(id)
fun getOrderWithServices(id: Int) = orderDao.getOrderWithServices(id)
fun getAllOrders() = orderDao.getAllOrders()
fun getUserOrders(id: Int) = orderDao.getUserOrders(id)
}

View File

@ -1,12 +1,23 @@
package com.example.myapplication.repository
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.myapplication.dao.ServiceDao
import com.example.myapplication.model.Service
import kotlinx.coroutines.flow.Flow
class ServiceRepository(private val serviceDao: ServiceDao) {
suspend fun insert(service: Service) = serviceDao.insert(service)
suspend fun update(service: Service) = serviceDao.update(service)
suspend fun delete(service: Service) = serviceDao.delete(service)
suspend fun getServiceById(id: Int) = serviceDao.getServiceById(id)
suspend fun getAllServices() = serviceDao.getAllServices()
fun getAllServices() = serviceDao.getAllServices()
fun call(): Flow<PagingData<Service>> {
return Pager(
PagingConfig(pageSize = 5)
){
serviceDao.getAllServicesPaged()
}.flow
}
}

View File

@ -0,0 +1,27 @@
package com.example.myapplication.viewmodel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.example.myapplication.App
object AppViewModelProvider {
val Factory = viewModelFactory {
initializer {
ServiceViewModel(app().container.serviceRepo)
}
initializer {
UserViewModel(app().container.userRepo, app().container.basketRepo)
}
initializer {
OrderViewModel(app().container.orderRepo, app().container.basketRepo)
}
initializer {
BasketViewModel(app().container.basketRepo, app().container.orderRepo,)
}
}
}
fun CreationExtras.app(): App =
(this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as App)

View File

@ -1,43 +1,92 @@
package com.example.myapplication.viewmodel
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableDoubleStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.myapplication.GlobalUser
import com.example.myapplication.model.Basket
import com.example.myapplication.model.BasketService
import com.example.myapplication.model.BasketWithServices
import com.example.myapplication.model.Service
import com.example.myapplication.repository.BasketRepository
import com.example.myapplication.repository.OrderRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
class BasketViewModel(private val basketRepository: BasketRepository) : ViewModel() {
val date = mutableLongStateOf(0L)
private var _selectedItems = mutableStateOf<List<Service>>(emptyList())
val selectedItems get() = _selectedItems.value
class BasketViewModel(private val basketRepository: BasketRepository, private val orderRepository: OrderRepository) : ViewModel() {
private val _quantityStateMap = mutableMapOf<Int, MutableStateFlow<Int>>()
private val _total = mutableDoubleStateOf(0.00)
val total: State<Double> get() = _total
fun getQuantityState(basketId: Int, serviceId: Int): StateFlow<Int> {
val quantityStateFlow = _quantityStateMap.getOrPut(serviceId) {
MutableStateFlow(0)
}
fun createBasket() = viewModelScope.launch {
val basket = Basket(
date = date.value,
total = getTotal(),
creatorUserId = GlobalUser.getInstance().getUser()?.userId!!
)
viewModelScope.launch {
val quantityFromDb = basketRepository.getQuantity(basketId, serviceId)
quantityFromDb?.let { quantityStateFlow.value = it }
}
var basketId = basketRepository.insert(basket)
return quantityStateFlow
}
for(service in selectedItems){
val basketService = BasketService(null, basketId.toInt(), service.serviceId!!)
basketRepository.insertBasketService(basketService)
suspend fun isServiceInBasket(basketId: Int, serviceId: Int): Boolean {
return basketRepository.getService(basketId, serviceId) != null
}
fun addToBasket(basketServices: BasketService) = viewModelScope.launch {
val isServiceInBasket = isServiceInBasket(basketServices.basketId, basketServices.serviceId)
if (isServiceInBasket) {
incrementQuantity(basketServices.basketId, basketServices.serviceId)
} else {
basketRepository.insertBasketService(basketServices)
}
}
suspend fun getBasketWithServices(id: Int) : Flow<BasketWithServices> {
fun getBasketServices(id: Int): Flow<BasketWithServices> {
return basketRepository.getBasketWithServices(id)
}
private fun getTotal(): Double {
return selectedItems.sumOf { it.price }
suspend fun getUsersBasket(id: Int): Basket {
return basketRepository.getUsersBasket(id)
}
fun deleteServiceFromBasket(basketId: Int, serviceId: Int) = viewModelScope.launch {
basketRepository.removeServiceFromBasket(basketId, serviceId)
}
fun incrementQuantity(basketId: Int, serviceId: Int) {
val currentQuantity = _quantityStateMap[serviceId]?.value ?: 1
_quantityStateMap[serviceId]?.value = currentQuantity + 1
viewModelScope.launch {
basketRepository.incrementServiceQuantity(basketId, serviceId)
updateSubTotal(GlobalUser.getInstance().getUser()?.userId!!)
}
}
fun decrementQuantity(basketId: Int, serviceId: Int) {
val currentQuantity = _quantityStateMap[serviceId]?.value ?: 1
if (currentQuantity > 1) {
_quantityStateMap[serviceId]?.value = currentQuantity - 1
viewModelScope.launch {
basketRepository.decrementServiceQuantity(basketId, serviceId)
updateSubTotal(GlobalUser.getInstance().getUser()?.userId!!)
}
}
}
fun updateSubTotal(userId: Int) {
viewModelScope.launch {
_total.value = getTotal(userId)
}
}
suspend fun getTotal(userId: Int): Double {
return basketRepository.getTotalPriceForBasket(basketRepository.getUsersBasket(userId!!).basketId!!) ?: 0.00
}
}

View File

@ -1,6 +1,8 @@
package com.example.myapplication.viewmodel
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableDoubleStateOf
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.myapplication.GlobalUser
@ -9,39 +11,60 @@ import com.example.myapplication.model.OrderService
import com.example.myapplication.model.OrderWithServices
import com.example.myapplication.model.Service
import com.example.myapplication.model.UserWithOrder
import com.example.myapplication.repository.BasketRepository
import com.example.myapplication.repository.OrderRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import java.util.Date
class OrderViewModel(private val orderRepository: OrderRepository) : ViewModel() {
private var _selectedItems = mutableStateOf<List<Service>>(emptyList())
val selectedItems get() = _selectedItems.value
class OrderViewModel(private val orderRepository: OrderRepository, private val basketRepository: BasketRepository) : ViewModel() {
private var _selectedItems = MutableLiveData<List<Service>>()
val selectedItems get() = _selectedItems
private val _total = mutableDoubleStateOf(0.00)
val total: State<Double> get() = _total
fun createOrder() = viewModelScope.launch {
val userId = GlobalUser.getInstance().getUser()?.userId!!
val order = Order(
date = Date().time,
total = getTotal(),
total = getTotal(basketRepository.getUsersBasket(userId).basketId!!),
creatorUserId = GlobalUser.getInstance().getUser()?.userId!!
)
var orderId = orderRepository.insert(order)
for(service in selectedItems){
val orderService = OrderService(orderId.toInt(), service.serviceId!!)
orderRepository.insertOrderService(orderService)
for(service in selectedItems.value!!){
val quantity = basketRepository.getQuantity(basketRepository.getUsersBasket(userId).basketId!!, service.serviceId!!)
val orderService = OrderService( orderId.toInt(), service.serviceId!!, quantity!!)
if (orderService != null) {
orderRepository.insertOrderService(orderService)
}
}
basketRepository.clearBasket(basketRepository.getUsersBasket(userId).basketId!!)
}
suspend fun getOrderWithServices(id: Int) : Flow<OrderWithServices> {
fun getOrderWithServices(id: Int) : Flow<OrderWithServices> {
return orderRepository.getOrderWithServices(id)
}
suspend fun getUserOrders(id: Int): Flow<UserWithOrder> {
fun getUserOrders(id: Int): Flow<UserWithOrder> {
return orderRepository.getUserOrders(id)
}
private fun getTotal(): Double {
return selectedItems.sumOf { it.price }
fun updateSelectedItems(items: List<Service>) {
_selectedItems.value = items
val userId = GlobalUser.getInstance().getUser()?.userId!!
updateSubTotal(userId)
}
fun updateSubTotal(userId: Int) {
viewModelScope.launch {
_total.value = getTotal(userId)
}
}
suspend fun getTotal(basketId: Int): Double {
return basketRepository.getTotalPriceForBasket(basketId) ?: 0.00
}
}

View File

@ -5,6 +5,7 @@ import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.cachedIn
import com.example.myapplication.R
import com.example.myapplication.model.Service
import com.example.myapplication.repository.ServiceRepository
@ -14,7 +15,8 @@ class ServiceViewModel(private val serviceRepository: ServiceRepository): ViewMo
var name = mutableStateOf("")
var price = mutableDoubleStateOf(0.00)
var photo = mutableIntStateOf(R.drawable.image_service)
var service: Service? = null
var service = mutableStateOf<Service>(Service(null,"", 0.0, null))
val serviceList = serviceRepository.call().cachedIn(viewModelScope)
fun createService() = viewModelScope.launch {
val service = Service(
@ -25,8 +27,8 @@ class ServiceViewModel(private val serviceRepository: ServiceRepository): ViewMo
serviceRepository.insert(service)
}
fun updateService(service: Service) = viewModelScope.launch {
serviceRepository.update(service)
fun updateService() = viewModelScope.launch {
serviceRepository.update(service.value)
}
fun deleteService(service: Service) = viewModelScope.launch {

View File

@ -6,12 +6,14 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.myapplication.GlobalUser
import com.example.myapplication.R
import com.example.myapplication.model.Basket
import com.example.myapplication.model.RoleEnum
import com.example.myapplication.model.User
import com.example.myapplication.repository.BasketRepository
import com.example.myapplication.repository.UserRepository
import kotlinx.coroutines.launch
class UserViewModel(private val userRepository: UserRepository): ViewModel() {
class UserViewModel(private val userRepository: UserRepository, private val basketRepository: BasketRepository): ViewModel() {
var name = mutableStateOf("")
var surname = mutableStateOf("")
var email = mutableStateOf("")
@ -19,7 +21,7 @@ class UserViewModel(private val userRepository: UserRepository): ViewModel() {
var photo = mutableIntStateOf(R.drawable.icon_profile)
fun createUser() = viewModelScope.launch {
val user = User(
var user = User(
name = name.value,
surname = surname.value,
email = email.value,
@ -31,13 +33,41 @@ class UserViewModel(private val userRepository: UserRepository): ViewModel() {
fun authUser() = viewModelScope.launch {
val user = userRepository.getUserByEmail(email.value)
if(!password.value.isEmpty() and (user.password == password.value)){
if(password.value.isNotEmpty() && user.password == password.value){
val globalUser = GlobalUser.getInstance()
globalUser.setUser(user)
val basket = basketRepository.getUsersBasket(user.userId!!)
if(basket == null){
basketRepository.createBasket(Basket(null, user.userId))
}
}
}
fun isValidEmail(email: String): Boolean {
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()
fun updateUser() = viewModelScope.launch {
var updateUser = GlobalUser.getInstance().getUser()
if(email.value != "")
updateUser?.email = email.value
else
updateUser?.email = updateUser?.email.toString()
if(name.value != "")
updateUser?.name = name.value
else
updateUser?.name = updateUser?.name.toString()
if(surname.value != "")
updateUser?.surname = surname.value
else
updateUser?.surname = updateUser?.surname.toString()
if(password.value != "")
updateUser?.password = password.value
else
updateUser?.password = updateUser?.password.toString()
//updateUser?.photo =
if (updateUser != null) {
userRepository.update(updateUser)
}
}
fun isValidEmail(): Boolean {
return android.util.Patterns.EMAIL_ADDRESS.matcher(email.value).matches()
}
}