Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
eb23e9c671 | |||
edb8f8b6b6 | |||
5a18ee67fc | |||
f879990c39 |
@ -1,123 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<JetCodeStyleSettings>
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
|
||||||
</JetCodeStyleSettings>
|
|
||||||
<codeStyleSettings language="XML">
|
|
||||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
||||||
</indentOptions>
|
|
||||||
<arrangement>
|
|
||||||
<rules>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:android</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:id</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:name</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>name</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>style</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
</rules>
|
|
||||||
</arrangement>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="kotlin">
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
41
.idea/inspectionProfiles/Project_Default.xml
Normal file
41
.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
<option name="previewFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
@ -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="KotlinJpsPluginSettings">
|
<component name="KotlinJpsPluginSettings">
|
||||||
<option name="version" value="1.8.10" />
|
<option name="version" value="1.8.20" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal 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>
|
@ -1,6 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
id("org.jetbrains.kotlin.android")
|
id("org.jetbrains.kotlin.android")
|
||||||
|
id("com.google.devtools.ksp")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -23,21 +24,24 @@ 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_17
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "17"
|
||||||
}
|
}
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
compose = true
|
compose = true
|
||||||
}
|
}
|
||||||
composeOptions {
|
composeOptions {
|
||||||
kotlinCompilerExtensionVersion = "1.4.3"
|
kotlinCompilerExtensionVersion = "1.4.5"
|
||||||
}
|
}
|
||||||
packaging {
|
packaging {
|
||||||
resources {
|
resources {
|
||||||
@ -47,15 +51,30 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation("com.jakewharton.threetenabp:threetenabp:1.2.1")
|
||||||
|
implementation("androidx.datastore:datastore-preferences:1.0.0")
|
||||||
|
// Core
|
||||||
implementation("androidx.core:core-ktx:1.9.0")
|
implementation("androidx.core:core-ktx:1.9.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")
|
|
||||||
|
// UI
|
||||||
|
implementation("androidx.activity:activity-compose:1.7.2")
|
||||||
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||||
|
implementation("androidx.navigation:navigation-compose:2.6.0")
|
||||||
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.material3:material3")
|
||||||
|
|
||||||
|
// Room
|
||||||
|
val room_version = "2.5.2"
|
||||||
|
implementation("androidx.room:room-runtime:$room_version")
|
||||||
|
annotationProcessor("androidx.room:room-compiler:$room_version")
|
||||||
|
ksp("androidx.room:room-compiler:$room_version")
|
||||||
|
implementation("androidx.room:room-ktx:$room_version")
|
||||||
|
implementation("androidx.room:room-paging:$room_version")
|
||||||
|
|
||||||
|
// Tests
|
||||||
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")
|
||||||
|
BIN
app/src/images/photo.jpg
Normal file
BIN
app/src/images/photo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
@ -10,13 +10,13 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.MyApplication"
|
android:theme="@style/Theme.Pmudemo"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainComposeActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.MyApplication">
|
android:theme="@style/Theme.Pmudemo">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
package com.example.myapplication
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.compose.setContent
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
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.myapplication.ui.theme.MyApplicationTheme
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setContent {
|
|
||||||
MyApplicationTheme {
|
|
||||||
// A surface container using the 'background' color from the theme
|
|
||||||
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
|
|
||||||
Greeting("Android")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun Greeting(name: String, modifier: Modifier = Modifier) {
|
|
||||||
Text(
|
|
||||||
text = "Hello $name!",
|
|
||||||
modifier = modifier
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
|
||||||
@Composable
|
|
||||||
fun GreetingPreview() {
|
|
||||||
MyApplicationTheme {
|
|
||||||
Greeting("Android")
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,43 @@
|
|||||||
|
package com.example.myapplication
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import com.example.myapplication.composeui.navigation.MainNavbar
|
||||||
|
import com.example.myapplication.datastore.DataStoreManager
|
||||||
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
|
import com.jakewharton.threetenabp.AndroidThreeTen
|
||||||
|
|
||||||
|
class MainComposeActivity : ComponentActivity() {
|
||||||
|
private val dataStoreManager = DataStoreManager(this)
|
||||||
|
private val isDarkTheme = mutableStateOf(true)
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
application.deleteDatabase("pmy-db")
|
||||||
|
AndroidThreeTen.init(this)
|
||||||
|
setContent {
|
||||||
|
PmudemoTheme(darkTheme = isDarkTheme.value) {
|
||||||
|
LaunchedEffect(key1 = true) {
|
||||||
|
dataStoreManager.getSettings().collect { setting ->
|
||||||
|
isDarkTheme.value = setting.isDarkTheme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
MainNavbar(
|
||||||
|
isDarkTheme = isDarkTheme,
|
||||||
|
dataStoreManager = dataStoreManager
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
190
app/src/main/java/com/example/myapplication/composeui/Cart.kt
Normal file
190
app/src/main/java/com/example/myapplication/composeui/Cart.kt
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
package com.example.myapplication.composeui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
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
|
||||||
|
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.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
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.asImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.myapplication.R
|
||||||
|
import com.example.myapplication.database.AppDatabase
|
||||||
|
import com.example.myapplication.entities.model.SessionFromCart
|
||||||
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Cart(id: Int) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val sessions = remember { mutableStateListOf<SessionFromCart>() }
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
AppDatabase.getInstance(context).userDao().getCartByUid(id).collect { data ->
|
||||||
|
sessions.clear()
|
||||||
|
sessions.addAll(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(all = 10.dp)
|
||||||
|
) {
|
||||||
|
items(sessions) { session ->
|
||||||
|
var currentCount by remember { mutableStateOf(session.count) }
|
||||||
|
|
||||||
|
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
||||||
|
val formattedDate = dateFormatter.format(session.dateTime)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = formattedDate,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp)
|
||||||
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
.background(MaterialTheme.colorScheme.secondary)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
if (session.cinema.image != null)
|
||||||
|
Image(
|
||||||
|
bitmap = BitmapFactory.decodeByteArray(
|
||||||
|
session.cinema.image,
|
||||||
|
0,
|
||||||
|
session.cinema.image.size
|
||||||
|
).asImageBitmap(),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(90.dp)
|
||||||
|
.padding(4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${session.cinema.name}, ${session.cinema.year}\n" +
|
||||||
|
"Цена: ${session.price}\n" +
|
||||||
|
"${currentCount}/${session.availableCount}",
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.background,
|
||||||
|
shape = RoundedCornerShape(10.dp)
|
||||||
|
) // Задаем фон для кнопок
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
if (currentCount > 0) {
|
||||||
|
currentCount--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = ImageVector.vectorResource(id = R.drawable.minus),
|
||||||
|
contentDescription = "Уменьшить",
|
||||||
|
tint = MaterialTheme.colorScheme.onBackground,
|
||||||
|
modifier = Modifier.size(10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "$currentCount",
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
)
|
||||||
|
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
if (currentCount < session.availableCount) {
|
||||||
|
currentCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Add,
|
||||||
|
contentDescription = "Увеличить",
|
||||||
|
tint = MaterialTheme.colorScheme.onBackground,
|
||||||
|
modifier = Modifier.size(10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = { },
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) { Text("Купить") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||||
|
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
fun CartPreview() {
|
||||||
|
PmudemoTheme {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
Cart(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,218 @@
|
|||||||
|
package com.example.myapplication.composeui.navigation
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
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.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
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.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.Person
|
||||||
|
import androidx.compose.material.icons.filled.Search
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.NavigationBar
|
||||||
|
import androidx.compose.material3.NavigationBarItem
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
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.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavDestination
|
||||||
|
import androidx.navigation.NavDestination.Companion.hierarchy
|
||||||
|
import androidx.navigation.NavGraph.Companion.findStartDestination
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
|
import androidx.navigation.NavType
|
||||||
|
import androidx.navigation.compose.NavHost
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import androidx.navigation.navArgument
|
||||||
|
import com.example.myapplication.composeui.Cart
|
||||||
|
import com.example.myapplication.datastore.DataStoreManager
|
||||||
|
import com.example.myapplication.entities.composeui.CinemaList
|
||||||
|
import com.example.myapplication.entities.composeui.CinemaView
|
||||||
|
import com.example.myapplication.entities.composeui.OrderList
|
||||||
|
import com.example.myapplication.entities.composeui.OrderView
|
||||||
|
import com.example.myapplication.user.composeui.UserProfile
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Topbar(
|
||||||
|
navController: NavHostController,
|
||||||
|
currentScreen: Screen?
|
||||||
|
) {
|
||||||
|
var searchQuery by remember { mutableStateOf("") }
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(color = MaterialTheme.colorScheme.primary)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
navController.previousBackStackEntry != null
|
||||||
|
&& (currentScreen == null || !currentScreen.showInBottomBar)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.ArrowBack,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(30.dp)
|
||||||
|
.clickable { navController.navigateUp() },
|
||||||
|
tint = MaterialTheme.colorScheme.secondary
|
||||||
|
)
|
||||||
|
} else
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Person,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(30.dp)
|
||||||
|
.clickable { navController.navigate(Screen.UserProfile.route) },
|
||||||
|
tint = MaterialTheme.colorScheme.secondary
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
BasicTextField(
|
||||||
|
value = searchQuery,
|
||||||
|
onValueChange = { newValue -> searchQuery = newValue },
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.height(36.dp)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
RoundedCornerShape(18.dp)
|
||||||
|
)
|
||||||
|
.padding(start = 13.dp, top = 8.dp),
|
||||||
|
keyboardOptions = KeyboardOptions.Default.copy(
|
||||||
|
imeAction = androidx.compose.ui.text.input.ImeAction.Search
|
||||||
|
),
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onSearch = { }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Search,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(30.dp)
|
||||||
|
.clickable { },
|
||||||
|
tint = MaterialTheme.colorScheme.secondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Navbar(
|
||||||
|
navController: NavHostController,
|
||||||
|
currentDestination: NavDestination?,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
NavigationBar(modifier = modifier, containerColor = MaterialTheme.colorScheme.primary) {
|
||||||
|
Screen.bottomBarItems.forEach { screen ->
|
||||||
|
NavigationBarItem(
|
||||||
|
icon = {
|
||||||
|
Icon(
|
||||||
|
screen.icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.secondary
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = { Text(stringResource(screen.resourceId)) },
|
||||||
|
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
|
||||||
|
onClick = {
|
||||||
|
navController.navigate(screen.route) {
|
||||||
|
popUpTo(navController.graph.findStartDestination().id) {
|
||||||
|
saveState = true
|
||||||
|
}
|
||||||
|
launchSingleTop = true
|
||||||
|
restoreState = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Navhost(
|
||||||
|
navController: NavHostController,
|
||||||
|
innerPadding: PaddingValues,
|
||||||
|
isDarkTheme: MutableState<Boolean>,
|
||||||
|
dataStore: DataStoreManager,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
NavHost(
|
||||||
|
navController,
|
||||||
|
startDestination = Screen.CinemaList.route,
|
||||||
|
modifier.padding(innerPadding)
|
||||||
|
) {
|
||||||
|
composable(Screen.CinemaList.route) { CinemaList(navController) }
|
||||||
|
composable(Screen.OrderList.route) { OrderList(navController, 1) }
|
||||||
|
composable(Screen.Cart.route) { Cart(1) }
|
||||||
|
composable(Screen.UserProfile.route) { UserProfile(isDarkTheme, dataStore) }
|
||||||
|
composable(
|
||||||
|
Screen.CinemaView.route,
|
||||||
|
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||||
|
) { backStackEntry ->
|
||||||
|
backStackEntry.arguments?.let { CinemaView(it.getInt("id")) }
|
||||||
|
}
|
||||||
|
composable(
|
||||||
|
Screen.OrderView.route,
|
||||||
|
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||||
|
) { backStackEntry ->
|
||||||
|
backStackEntry.arguments?.let { OrderView(it.getInt("id")) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun MainNavbar(
|
||||||
|
isDarkTheme: MutableState<Boolean>,
|
||||||
|
dataStoreManager: DataStoreManager
|
||||||
|
) {
|
||||||
|
val navController = rememberNavController()
|
||||||
|
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||||
|
val currentDestination = navBackStackEntry?.destination
|
||||||
|
val currentScreen = currentDestination?.route?.let { Screen.getItem(it) }
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
Topbar(navController, currentScreen)
|
||||||
|
},
|
||||||
|
bottomBar = {
|
||||||
|
if (currentScreen == null || currentScreen.showInBottomBar) {
|
||||||
|
Navbar(navController, currentDestination)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { innerPadding ->
|
||||||
|
Navhost(navController, innerPadding, isDarkTheme, dataStoreManager)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.example.myapplication.composeui.navigation
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Favorite
|
||||||
|
import androidx.compose.material.icons.filled.Home
|
||||||
|
import androidx.compose.material.icons.filled.List
|
||||||
|
import androidx.compose.material.icons.filled.ShoppingCart
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import com.example.myapplication.R
|
||||||
|
|
||||||
|
enum class Screen(
|
||||||
|
val route: String,
|
||||||
|
@StringRes val resourceId: Int,
|
||||||
|
val icon: ImageVector = Icons.Filled.Favorite,
|
||||||
|
val showInBottomBar: Boolean = true
|
||||||
|
) {
|
||||||
|
CinemaList(
|
||||||
|
"Cinema-list", R.string.Cinema_main_title, Icons.Filled.Home
|
||||||
|
),
|
||||||
|
SessionList(
|
||||||
|
"Session-list", R.string.Sessions_title, showInBottomBar = false
|
||||||
|
),
|
||||||
|
Cart(
|
||||||
|
"cart", R.string.Cart_title, Icons.Filled.ShoppingCart
|
||||||
|
),
|
||||||
|
OrderList(
|
||||||
|
"Order-list", R.string.Order_title, Icons.Filled.List
|
||||||
|
),
|
||||||
|
CinemaView(
|
||||||
|
"Cinema-view/{id}", R.string.Cinema_view_title, showInBottomBar = false
|
||||||
|
),
|
||||||
|
OrderView(
|
||||||
|
"Order-view/{id}", R.string.Order_view_title, showInBottomBar = false
|
||||||
|
),
|
||||||
|
UserProfile(
|
||||||
|
"User-profile", R.string.Profile_title, showInBottomBar = false
|
||||||
|
);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val bottomBarItems = listOf(
|
||||||
|
CinemaList,
|
||||||
|
Cart,
|
||||||
|
OrderList
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getItem(route: String): Screen? {
|
||||||
|
val findRoute = route.split("/").first()
|
||||||
|
return values().find { value -> value.route.startsWith(findRoute) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,147 @@
|
|||||||
|
package com.example.myapplication.database
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Color
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.Room
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import androidx.room.TypeConverters
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
import com.example.myapplication.entities.dao.CinemaDao
|
||||||
|
import com.example.myapplication.entities.dao.OrderDao
|
||||||
|
import com.example.myapplication.entities.dao.OrderSessionCrossRefDao
|
||||||
|
import com.example.myapplication.entities.dao.SessionDao
|
||||||
|
import com.example.myapplication.entities.dao.UserDao
|
||||||
|
import com.example.myapplication.entities.dao.UserSessionCrossRefDao
|
||||||
|
import com.example.myapplication.entities.model.Cinema
|
||||||
|
import com.example.myapplication.entities.model.LocalDateTimeConverter
|
||||||
|
import com.example.myapplication.entities.model.Order
|
||||||
|
import com.example.myapplication.entities.model.OrderSessionCrossRef
|
||||||
|
import com.example.myapplication.entities.model.Session
|
||||||
|
import com.example.myapplication.entities.model.User
|
||||||
|
import com.example.myapplication.entities.model.UserSessionCrossRef
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
|
||||||
|
@Database(
|
||||||
|
entities = [Cinema::class, Session::class, Order::class,
|
||||||
|
OrderSessionCrossRef::class, User::class, UserSessionCrossRef::class],
|
||||||
|
version = 1,
|
||||||
|
exportSchema = false
|
||||||
|
)
|
||||||
|
@TypeConverters(LocalDateTimeConverter::class)
|
||||||
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
abstract fun cinemaDao(): CinemaDao
|
||||||
|
abstract fun sessionDao(): SessionDao
|
||||||
|
abstract fun orderDao(): OrderDao
|
||||||
|
abstract fun orderSessionCrossRefDao(): OrderSessionCrossRefDao
|
||||||
|
abstract fun userDao(): UserDao
|
||||||
|
abstract fun userSessionCrossRefDao(): UserSessionCrossRefDao
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val DB_NAME: String = "pmy-db"
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var INSTANCE: AppDatabase? = null
|
||||||
|
|
||||||
|
private suspend fun populateDatabase() {
|
||||||
|
INSTANCE?.let { database ->
|
||||||
|
// Users
|
||||||
|
val userDao = database.userDao()
|
||||||
|
val user1 = User(1, "Login", "password")
|
||||||
|
val user2 = User(2, "Login123", "password123")
|
||||||
|
userDao.insert(user1)
|
||||||
|
userDao.insert(user2)
|
||||||
|
// Cinemas
|
||||||
|
val cinemaDao = database.cinemaDao()
|
||||||
|
val cinema1 = Cinema(1, "BLUE 1", "Desc1", createColoredImage(Color.BLUE), 2023)
|
||||||
|
val cinema2 = Cinema(2, "GREEN 2", "Desc2", createColoredImage(Color.GREEN), 2023)
|
||||||
|
val cinema3 = Cinema(3, "RED 3", "Desc3", createColoredImage(Color.RED), 2023)
|
||||||
|
cinemaDao.insert(cinema1)
|
||||||
|
cinemaDao.insert(cinema2)
|
||||||
|
cinemaDao.insert(cinema3)
|
||||||
|
// Orders
|
||||||
|
val orderDao = database.orderDao()
|
||||||
|
val order1 = Order(1, 1)
|
||||||
|
val order2 = Order(2, 1)
|
||||||
|
val order3 = Order(3, 1)
|
||||||
|
val order4 = Order(4, 1)
|
||||||
|
orderDao.insert(order1)
|
||||||
|
orderDao.insert(order2)
|
||||||
|
orderDao.insert(order3)
|
||||||
|
orderDao.insert(order4)
|
||||||
|
// Sessions
|
||||||
|
val sessionDao = database.sessionDao()
|
||||||
|
val session1 = Session(1, LocalDateTime.now(), 150.0, 120, cinema1.uid)
|
||||||
|
val session2 = Session(2, LocalDateTime.now(), 200.0, 110, cinema2.uid)
|
||||||
|
val session3 = Session(3, LocalDateTime.now(), 300.0, 100, cinema3.uid)
|
||||||
|
val session4 = Session(4, LocalDateTime.now(), 320.0, 1150, cinema1.uid)
|
||||||
|
sessionDao.insert(session1)
|
||||||
|
sessionDao.insert(session2)
|
||||||
|
sessionDao.insert(session3)
|
||||||
|
sessionDao.insert(session4)
|
||||||
|
// OrderSessionCrossRef для связи заказов с сеансами
|
||||||
|
val orderSessionCrossRefDao = database.orderSessionCrossRefDao()
|
||||||
|
if (session1.uid != null && session2.uid != null && session3.uid != null && session4.uid != null) {
|
||||||
|
val orderSessionCrossRef1 = OrderSessionCrossRef(order1.uid, session3.uid, 150.0, 5)
|
||||||
|
val orderSessionCrossRef2 = OrderSessionCrossRef(order1.uid, session2.uid, 300.0, 10)
|
||||||
|
val orderSessionCrossRef3 = OrderSessionCrossRef(order2.uid, session2.uid, 350.0, 6)
|
||||||
|
val orderSessionCrossRef4 = OrderSessionCrossRef(order3.uid, session1.uid, 250.0, 10)
|
||||||
|
val orderSessionCrossRef5 = OrderSessionCrossRef(order3.uid, session3.uid, 150.0, 16)
|
||||||
|
val orderSessionCrossRef6 = OrderSessionCrossRef(order4.uid, session3.uid, 150.0, 2)
|
||||||
|
//val orderSessionCrossRef7 = OrderSessionCrossRef(order4.uid, session4.uid, 110.0, 1)
|
||||||
|
orderSessionCrossRefDao.insert(orderSessionCrossRef1)
|
||||||
|
orderSessionCrossRefDao.insert(orderSessionCrossRef2)
|
||||||
|
orderSessionCrossRefDao.insert(orderSessionCrossRef3)
|
||||||
|
orderSessionCrossRefDao.insert(orderSessionCrossRef4)
|
||||||
|
orderSessionCrossRefDao.insert(orderSessionCrossRef5)
|
||||||
|
orderSessionCrossRefDao.insert(orderSessionCrossRef6)
|
||||||
|
//orderSessionCrossRefDao.insert(orderSessionCrossRef7)
|
||||||
|
}
|
||||||
|
// UserSessions
|
||||||
|
val userSessionCrossRefDao = database.userSessionCrossRefDao()
|
||||||
|
val userSessionCrossRef1 = UserSessionCrossRef(1, 1, 5)
|
||||||
|
val userSessionCrossRef2 = UserSessionCrossRef(1, 3, 15)
|
||||||
|
userSessionCrossRefDao.insert(userSessionCrossRef1)
|
||||||
|
userSessionCrossRefDao.insert(userSessionCrossRef2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
.also { INSTANCE = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createColoredImage(color: Int): ByteArray {
|
||||||
|
val width = 100
|
||||||
|
val height = 100
|
||||||
|
|
||||||
|
val bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||||
|
bmp.eraseColor(color)
|
||||||
|
|
||||||
|
val stream = ByteArrayOutputStream()
|
||||||
|
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream)
|
||||||
|
|
||||||
|
return stream.toByteArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.example.myapplication.datastore
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.preferences.core.Preferences
|
||||||
|
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||||
|
import androidx.datastore.preferences.core.edit
|
||||||
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("data_store")
|
||||||
|
|
||||||
|
class DataStoreManager(private val context: Context) {
|
||||||
|
suspend fun saveSettings(settingData: SettingData) {
|
||||||
|
context.dataStore.edit { pref ->
|
||||||
|
pref[booleanPreferencesKey("isDarkTheme")] = settingData.isDarkTheme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSettings() = context.dataStore.data.map { pref ->
|
||||||
|
return@map SettingData(
|
||||||
|
pref[booleanPreferencesKey("isDarkTheme")] ?: true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.example.myapplication.datastore
|
||||||
|
|
||||||
|
data class SettingData(
|
||||||
|
val isDarkTheme: Boolean
|
||||||
|
)
|
@ -0,0 +1,109 @@
|
|||||||
|
package com.example.myapplication.entities.composeui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
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.Row
|
||||||
|
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.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.myapplication.composeui.navigation.Screen
|
||||||
|
import com.example.myapplication.database.AppDatabase
|
||||||
|
import com.example.myapplication.entities.model.Cinema
|
||||||
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CinemaList(navController: NavController?) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val cinemas = remember { mutableStateListOf<Cinema>() }
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
AppDatabase.getInstance(context).cinemaDao().getAll().collect { data ->
|
||||||
|
cinemas.clear()
|
||||||
|
cinemas.addAll(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(all = 10.dp)
|
||||||
|
) {
|
||||||
|
items(cinemas) { cinema ->
|
||||||
|
val cinemaId = Screen.CinemaView.route.replace("{id}", cinema.uid.toString())
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(all = 10.dp)
|
||||||
|
.clickable { navController?.navigate(cinemaId) }
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
shape = RoundedCornerShape(16.dp)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
if (cinema.image != null)
|
||||||
|
Image(
|
||||||
|
bitmap = BitmapFactory.decodeByteArray(
|
||||||
|
cinema.image,
|
||||||
|
0,
|
||||||
|
cinema.image.size
|
||||||
|
).asImageBitmap(),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(90.dp)
|
||||||
|
.padding(4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
"${cinema.name}, ${cinema.year}",
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||||
|
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
fun CinemaListPreview() {
|
||||||
|
PmudemoTheme {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
CinemaList(navController = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,209 @@
|
|||||||
|
package com.example.myapplication.entities.composeui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
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.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ShoppingCart
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
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.asImageBitmap
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
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 com.example.myapplication.database.AppDatabase
|
||||||
|
import com.example.myapplication.entities.model.Cinema
|
||||||
|
import com.example.myapplication.entities.model.SessionFromCinema
|
||||||
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CinemaView(id: Int) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val cinemaWithSessions = remember {
|
||||||
|
mutableStateListOf<Pair<Cinema, List<SessionFromCinema>>>()
|
||||||
|
}
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
cinemaWithSessions.clear()
|
||||||
|
cinemaWithSessions
|
||||||
|
.addAll(AppDatabase.getInstance(context).cinemaDao().getByUid(id).map { (cinema, sessionFromCinema) ->
|
||||||
|
Pair(cinema, sessionFromCinema)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val cinema = cinemaWithSessions.firstOrNull()?.first
|
||||||
|
val sessions = cinemaWithSessions.firstOrNull()?.second
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
item {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
shape = RoundedCornerShape(16.dp)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
.background(color = MaterialTheme.colorScheme.secondary),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${cinema?.name ?: ""}, ${cinema?.year ?: 1930}",
|
||||||
|
style = TextStyle(
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 8.dp)
|
||||||
|
)
|
||||||
|
if (cinema?.image != null)
|
||||||
|
Image(
|
||||||
|
bitmap = BitmapFactory.decodeByteArray(
|
||||||
|
cinema.image,
|
||||||
|
0,
|
||||||
|
cinema.image.size
|
||||||
|
).asImageBitmap(),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(200.dp)
|
||||||
|
.padding(4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = cinema?.description ?: "",
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
Text(
|
||||||
|
text = "Сеансы",
|
||||||
|
style = TextStyle(
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 8.dp, bottom = 8.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sessions != null) {
|
||||||
|
items(sessions) { session ->
|
||||||
|
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
||||||
|
val formattedDate = dateFormatter.format(session.dateTime)
|
||||||
|
Text(
|
||||||
|
text = formattedDate,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp)
|
||||||
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
.background(MaterialTheme.colorScheme.secondary)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
if (cinema?.image != null)
|
||||||
|
Image(
|
||||||
|
bitmap = BitmapFactory.decodeByteArray(
|
||||||
|
cinema.image,
|
||||||
|
0,
|
||||||
|
cinema.image.size
|
||||||
|
).asImageBitmap(),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(90.dp)
|
||||||
|
.padding(4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Цена: ${session.price}\n" +
|
||||||
|
"Билетов: ${session.availableCount}",
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.ShoppingCart,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
.size(24.dp)
|
||||||
|
.clickable {}
|
||||||
|
.align(Alignment.CenterEnd),
|
||||||
|
tint = MaterialTheme.colorScheme.onSecondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||||
|
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
fun CinemaViewPreview() {
|
||||||
|
PmudemoTheme {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
CinemaView(id = 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
package com.example.myapplication.entities.composeui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
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.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.myapplication.composeui.navigation.Screen
|
||||||
|
import com.example.myapplication.database.AppDatabase
|
||||||
|
import com.example.myapplication.entities.model.Order
|
||||||
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun OrderList(navController: NavController?, userId: Int?) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val orders = remember { mutableStateListOf<Order>() }
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
AppDatabase.getInstance(context).orderDao().getAll(userId).collect { data ->
|
||||||
|
orders.clear()
|
||||||
|
orders.addAll(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(all = 10.dp)
|
||||||
|
) {
|
||||||
|
items(orders) { order ->
|
||||||
|
val orderId = Screen.OrderView.route.replace("{id}", order.uid.toString())
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(all = 10.dp)
|
||||||
|
.clickable { navController?.navigate(orderId) }
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
shape = RoundedCornerShape(16.dp)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text("Заказ №${order.uid}", color = MaterialTheme.colorScheme.onSecondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||||
|
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
fun OrderListPreview() {
|
||||||
|
PmudemoTheme {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
OrderList(navController = null, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
package com.example.myapplication.entities.composeui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
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
|
||||||
|
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.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
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.asImageBitmap
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.myapplication.database.AppDatabase
|
||||||
|
import com.example.myapplication.entities.model.SessionFromOrder
|
||||||
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun OrderView(id: Int) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val sessions = remember {
|
||||||
|
mutableStateListOf<SessionFromOrder>()
|
||||||
|
}
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
sessions.clear()
|
||||||
|
sessions.addAll(AppDatabase.getInstance(context).orderDao().getByUid(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
) {
|
||||||
|
items(sessions) { session ->
|
||||||
|
val count = remember { mutableStateOf(session.count) }
|
||||||
|
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
||||||
|
val formattedDate = dateFormatter.format(session.dateTime)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = formattedDate,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp)
|
||||||
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
.background(MaterialTheme.colorScheme.secondary)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
if (session.cinema.image != null)
|
||||||
|
Image(
|
||||||
|
bitmap = BitmapFactory.decodeByteArray(
|
||||||
|
session.cinema.image,
|
||||||
|
0,
|
||||||
|
session.cinema.image.size
|
||||||
|
).asImageBitmap(),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(90.dp)
|
||||||
|
.padding(4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(start = 8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${session.cinema.name}, ${session.cinema.year}\n" +
|
||||||
|
"Цена: ${session.frozenPrice}\n" +
|
||||||
|
"Количество: ${count.value}",
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||||
|
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
fun OrderViewPreview() {
|
||||||
|
PmudemoTheme {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
OrderView(id = 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,166 @@
|
|||||||
|
package com.example.myapplication.user.composeui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
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.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
|
import androidx.compose.material3.SwitchDefaults
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.myapplication.datastore.DataStoreManager
|
||||||
|
import com.example.myapplication.datastore.SettingData
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun UserProfile(
|
||||||
|
isDarkTheme: MutableState<Boolean>,
|
||||||
|
dataStoreManager: DataStoreManager
|
||||||
|
) {
|
||||||
|
var username by remember { mutableStateOf("") }
|
||||||
|
var password by remember { mutableStateOf("") }
|
||||||
|
var isRegistration by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
LazyColumn {
|
||||||
|
item {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Логин",
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
|
)
|
||||||
|
BasicTextField(
|
||||||
|
value = username,
|
||||||
|
onValueChange = { newValue -> username = newValue },
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.size(36.dp)
|
||||||
|
.background(MaterialTheme.colorScheme.secondary, RoundedCornerShape(18.dp))
|
||||||
|
.padding(start = 13.dp, top = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Пароль",
|
||||||
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
|
)
|
||||||
|
BasicTextField(
|
||||||
|
value = password,
|
||||||
|
onValueChange = { newValue -> password = newValue },
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.size(36.dp)
|
||||||
|
.background(MaterialTheme.colorScheme.secondary, RoundedCornerShape(18.dp))
|
||||||
|
.padding(start = 13.dp, top = 8.dp),
|
||||||
|
visualTransformation = PasswordVisualTransformation()
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isRegistration) {
|
||||||
|
Button(
|
||||||
|
onClick = { },
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp)
|
||||||
|
) {
|
||||||
|
Text("Регистрация")
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = "Уже есть аккаунт? Войти",
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
isRegistration = false
|
||||||
|
}
|
||||||
|
.align(Alignment.CenterHorizontally),
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Button(
|
||||||
|
onClick = { },
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp)
|
||||||
|
) {
|
||||||
|
Text("Вход")
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = "Нет аккаунта? Зарегистрироваться",
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
isRegistration = true
|
||||||
|
}
|
||||||
|
.align(Alignment.CenterHorizontally),
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val switchColors = SwitchDefaults.colors(
|
||||||
|
checkedThumbColor = MaterialTheme.colorScheme.primary, // Change the color when the switch is checked
|
||||||
|
checkedTrackColor = MaterialTheme.colorScheme.secondary, // Change the color of the track when the switch is checked
|
||||||
|
uncheckedThumbColor = MaterialTheme.colorScheme.primary, // Change the color when the switch is unchecked
|
||||||
|
uncheckedTrackColor = MaterialTheme.colorScheme.onPrimary // Change the color of the track when the switch is unchecked
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp),
|
||||||
|
horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Темная тема", modifier = Modifier
|
||||||
|
.align(Alignment.CenterVertically)
|
||||||
|
.padding(5.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
val coroutine = rememberCoroutineScope()
|
||||||
|
|
||||||
|
Switch(
|
||||||
|
checked = isDarkTheme.value,
|
||||||
|
onCheckedChange = {
|
||||||
|
isDarkTheme.value = !isDarkTheme.value
|
||||||
|
coroutine.launch {
|
||||||
|
dataStoreManager.saveSettings(SettingData(isDarkTheme = isDarkTheme.value))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors = switchColors
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||||
|
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
fun UserProfilePreview() {
|
||||||
|
PmudemoTheme {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
UserProfile(navController = null, isDarkTheme = remember { mutableStateOf(true) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.example.myapplication.entities.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Update
|
||||||
|
import com.example.myapplication.entities.model.Cinema
|
||||||
|
import com.example.myapplication.entities.model.SessionFromCinema
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface CinemaDao {
|
||||||
|
@Query("select * from cinemas order by name")
|
||||||
|
fun getAll(): Flow<List<Cinema>>
|
||||||
|
|
||||||
|
@Query("SELECT c.*, s.date_time, s.price, s.max_count-IFNULL(SUM(os.count), 0) as available_count " +
|
||||||
|
"FROM cinemas AS c " +
|
||||||
|
"JOIN sessions AS s ON s.cinema_id = c.uid " +
|
||||||
|
"LEFT JOIN orders_sessions AS os ON os.session_id = s.uid " +
|
||||||
|
"WHERE c.uid = :cinemaId " +
|
||||||
|
"GROUP BY os.session_id")
|
||||||
|
suspend fun getByUid(cinemaId: Int?): Map<Cinema, List<SessionFromCinema>>
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
suspend fun insert(cinema: Cinema)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
suspend fun update(cinema: Cinema)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun delete(cinema: Cinema)
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.example.myapplication.entities.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Update
|
||||||
|
import com.example.myapplication.entities.model.Order
|
||||||
|
import com.example.myapplication.entities.model.SessionFromOrder
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface OrderDao {
|
||||||
|
@Query("select * from orders where user_id = :userId")
|
||||||
|
fun getAll(userId: Int?): Flow<List<Order>>
|
||||||
|
|
||||||
|
@Query("SELECT o.*, s.*, os.count, os.frozen_price " +
|
||||||
|
"FROM orders AS o " +
|
||||||
|
"JOIN orders_sessions AS os ON os.order_id = o.uid " +
|
||||||
|
"JOIN sessions AS s ON s.uid = os.session_id " +
|
||||||
|
"WHERE o.uid = :orderId")
|
||||||
|
fun getByUid(orderId: Int?): List<SessionFromOrder>
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
suspend fun insert(order: Order)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
suspend fun update(order: Order)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun delete(order: Order)
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.example.myapplication.entities.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Update
|
||||||
|
import com.example.myapplication.entities.model.OrderSessionCrossRef
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface OrderSessionCrossRefDao {
|
||||||
|
@Insert
|
||||||
|
suspend fun insert(orderSessionCrossRef: OrderSessionCrossRef)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
suspend fun update(orderSessionCrossRef: OrderSessionCrossRef)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun delete(orderSessionCrossRef: OrderSessionCrossRef)
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.example.myapplication.entities.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Update
|
||||||
|
import com.example.myapplication.entities.model.Session
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface SessionDao {
|
||||||
|
@Insert
|
||||||
|
suspend fun insert(session: Session)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
suspend fun update(session: Session)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun delete(session: Session)
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.example.myapplication.entities.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Update
|
||||||
|
import com.example.myapplication.entities.model.SessionFromCart
|
||||||
|
import com.example.myapplication.entities.model.User
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface UserDao {
|
||||||
|
@Query("select * from users order by login collate nocase asc")
|
||||||
|
fun getAll(): Flow<List<User>>
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"SELECT sessions.*, sessions.max_count-sum(orders_sessions.count) as available_count, " +
|
||||||
|
"users_sessions.count FROM sessions " +
|
||||||
|
"join users_sessions on sessions.uid = users_sessions.session_id " +
|
||||||
|
"join orders_sessions on sessions.uid = orders_sessions.session_id " +
|
||||||
|
"where users_sessions.user_id = :userId " +
|
||||||
|
"GROUP BY orders_sessions.session_id "
|
||||||
|
)
|
||||||
|
fun getCartByUid(userId: Int): Flow<List<SessionFromCart>>
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
suspend fun insert(user: User)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
suspend fun update(user: User)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun delete(user: User)
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.example.myapplication.entities.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Query
|
||||||
|
import androidx.room.Update
|
||||||
|
import com.example.myapplication.entities.model.SessionFromCart
|
||||||
|
import com.example.myapplication.entities.model.UserSessionCrossRef
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface UserSessionCrossRefDao {
|
||||||
|
@Insert
|
||||||
|
suspend fun insert(userSessionCrossRef: UserSessionCrossRef)
|
||||||
|
|
||||||
|
@Update
|
||||||
|
suspend fun update(userSessionCrossRef: UserSessionCrossRef)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun delete(userSessionCrossRef: UserSessionCrossRef)
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.example.myapplication.entities.model
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.Ignore
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(tableName = "cinemas")
|
||||||
|
data class Cinema(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
val uid: Int?,
|
||||||
|
val name: String,
|
||||||
|
val description: String,
|
||||||
|
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
|
||||||
|
val image: ByteArray?,
|
||||||
|
val year: Long
|
||||||
|
) {
|
||||||
|
@Ignore
|
||||||
|
constructor(
|
||||||
|
name: String,
|
||||||
|
description: String,
|
||||||
|
image: ByteArray?,
|
||||||
|
year: Long
|
||||||
|
) : this(null, name, description, image, year)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as Cinema
|
||||||
|
if (uid != other.uid) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return uid ?: -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.example.myapplication.entities.model
|
||||||
|
|
||||||
|
import androidx.room.TypeConverter
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
|
|
||||||
|
class LocalDateTimeConverter {
|
||||||
|
@TypeConverter
|
||||||
|
fun fromLocalDateTime(value: LocalDateTime?): String? {
|
||||||
|
return value?.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun toLocalDateTime(value: String?): LocalDateTime? {
|
||||||
|
return value?.let { LocalDateTime.parse(it) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.example.myapplication.entities.model
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
tableName = "orders", foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = User::class,
|
||||||
|
parentColumns = ["uid"],
|
||||||
|
childColumns = ["user_id"],
|
||||||
|
onDelete = ForeignKey.RESTRICT,
|
||||||
|
onUpdate = ForeignKey.RESTRICT
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class Order(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
val uid: Int,
|
||||||
|
@ColumnInfo(name = "user_id", index = true)
|
||||||
|
val userId: Int?,
|
||||||
|
) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as Order
|
||||||
|
if (uid != other.uid) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return uid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.example.myapplication.entities.model
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import java.util.Objects
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
tableName = "orders_sessions",
|
||||||
|
primaryKeys = ["order_id", "session_id"]
|
||||||
|
)
|
||||||
|
data class OrderSessionCrossRef(
|
||||||
|
@ColumnInfo(name = "order_id", index = true)
|
||||||
|
val orderId: Int,
|
||||||
|
@ColumnInfo(name = "session_id", index = true)
|
||||||
|
val sessionId: Int,
|
||||||
|
@ColumnInfo(name = "frozen_price")
|
||||||
|
val frozenPrice: Double,
|
||||||
|
val count: Int
|
||||||
|
) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (javaClass != other?.javaClass) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
other as OrderSessionCrossRef
|
||||||
|
if (orderId == other.orderId && sessionId == other.sessionId) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return Objects.hash(orderId, sessionId)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.example.myapplication.entities.model
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
|
import androidx.room.Ignore
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
tableName = "sessions", foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = Cinema::class,
|
||||||
|
parentColumns = ["uid"],
|
||||||
|
childColumns = ["cinema_id"],
|
||||||
|
onDelete = ForeignKey.RESTRICT,
|
||||||
|
onUpdate = ForeignKey.RESTRICT
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
data class Session(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
val uid: Int?,
|
||||||
|
@ColumnInfo(name = "date_time")
|
||||||
|
val dateTime: LocalDateTime,
|
||||||
|
val price: Double,
|
||||||
|
@ColumnInfo(name = "max_count")
|
||||||
|
val maxCount: Int,
|
||||||
|
@ColumnInfo(name = "cinema_id", index = true)
|
||||||
|
val cinemaId: Int?,
|
||||||
|
) {
|
||||||
|
@Ignore
|
||||||
|
constructor(
|
||||||
|
dateTime: LocalDateTime,
|
||||||
|
price: Double,
|
||||||
|
maxCount: Int,
|
||||||
|
cinema: Cinema,
|
||||||
|
) : this(null, dateTime, price, maxCount, cinema.uid)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as Session
|
||||||
|
if (uid != other.uid) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return uid ?: -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.example.myapplication.entities.model
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Relation
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
|
|
||||||
|
data class SessionFromCart(
|
||||||
|
@ColumnInfo(name = "uid")
|
||||||
|
val uid: Int?,
|
||||||
|
@ColumnInfo(name = "date_time")
|
||||||
|
val dateTime: LocalDateTime,
|
||||||
|
val price: Double,
|
||||||
|
@ColumnInfo(name = "available_count")
|
||||||
|
val availableCount: Int,
|
||||||
|
val count: Int,
|
||||||
|
@ColumnInfo(name = "cinema_id")
|
||||||
|
val cinemaId: Int?,
|
||||||
|
@Relation(
|
||||||
|
parentColumn = "cinema_id",
|
||||||
|
entity = Cinema::class,
|
||||||
|
entityColumn = "uid"
|
||||||
|
) val cinema: Cinema
|
||||||
|
)
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.example.myapplication.entities.model
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
|
|
||||||
|
data class SessionFromCinema (
|
||||||
|
@ColumnInfo(name = "uid")
|
||||||
|
val uid: Int?,
|
||||||
|
@ColumnInfo(name = "date_time")
|
||||||
|
val dateTime: LocalDateTime,
|
||||||
|
val price: Double,
|
||||||
|
@ColumnInfo(name = "available_count")
|
||||||
|
val availableCount: Int,
|
||||||
|
)
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.example.myapplication.entities.model
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Relation
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
|
|
||||||
|
data class SessionFromOrder(
|
||||||
|
@ColumnInfo(name = "uid")
|
||||||
|
val uid: Int?,
|
||||||
|
@ColumnInfo(name = "date_time")
|
||||||
|
val dateTime: LocalDateTime,
|
||||||
|
@ColumnInfo(name = "frozen_price")
|
||||||
|
val frozenPrice: Double,
|
||||||
|
val count: Int,
|
||||||
|
@ColumnInfo(name = "cinema_id")
|
||||||
|
val cinemaId: Int?,
|
||||||
|
@Relation(
|
||||||
|
parentColumn = "cinema_id",
|
||||||
|
entity = Cinema::class,
|
||||||
|
entityColumn = "uid"
|
||||||
|
)
|
||||||
|
val cinema: Cinema
|
||||||
|
)
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.example.myapplication.entities.model
|
||||||
|
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(tableName = "users")
|
||||||
|
data class User(
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
val uid: Int?,
|
||||||
|
val login: String,
|
||||||
|
val password: String
|
||||||
|
) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as User
|
||||||
|
if (uid != other.uid) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return uid ?: -1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.example.myapplication.entities.model
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
|
||||||
|
@Entity(
|
||||||
|
tableName = "users_sessions",
|
||||||
|
primaryKeys = ["user_id", "session_id"]
|
||||||
|
)
|
||||||
|
data class UserSessionCrossRef(
|
||||||
|
@ColumnInfo(name = "user_id", index = true)
|
||||||
|
val userId: Int,
|
||||||
|
@ColumnInfo(name = "session_id", index = true)
|
||||||
|
val sessionId: Int,
|
||||||
|
@ColumnInfo(name = "count")
|
||||||
|
val count: Int,
|
||||||
|
)
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.example.myapplication.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
val LightGray = Color(0xFFB2CCD6)
|
||||||
|
val LightBlueGray = Color(0xFF70A3B2)
|
||||||
|
val LightBgGray = Color(0xFFCED6DC)
|
||||||
|
|
||||||
|
val Gray = Color(0xFFD6D6D6)
|
||||||
|
val DarkGray = Color(0xFF191A1F)
|
||||||
|
val BgGray = Color(0xFF2A2D32)
|
@ -10,21 +10,31 @@ import androidx.compose.material3.dynamicLightColorScheme
|
|||||||
import androidx.compose.material3.lightColorScheme
|
import androidx.compose.material3.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.Color
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
|
|
||||||
private val DarkColorScheme = darkColorScheme(
|
private val DarkColorScheme = darkColorScheme(
|
||||||
primary = Purple80,
|
primary = DarkGray,
|
||||||
secondary = PurpleGrey80,
|
onPrimary = Color.White,
|
||||||
tertiary = Pink80
|
|
||||||
|
secondary = Gray,
|
||||||
|
onSecondary = Color.Black,
|
||||||
|
|
||||||
|
background = BgGray,
|
||||||
|
onBackground = Color.White,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val LightColorScheme = lightColorScheme(
|
private val LightColorScheme = lightColorScheme(
|
||||||
primary = Purple40,
|
primary = LightBlueGray,
|
||||||
secondary = PurpleGrey40,
|
onPrimary = Color.White,
|
||||||
tertiary = Pink40
|
|
||||||
|
secondary = LightGray,
|
||||||
|
onSecondary = Color.Black,
|
||||||
|
|
||||||
|
onBackground = Color.Black,
|
||||||
|
|
||||||
/* Other default colors to override
|
/* Other default colors to override
|
||||||
background = Color(0xFFFFFBFE),
|
background = Color(0xFFFFFBFE),
|
||||||
@ -38,10 +48,10 @@ private val LightColorScheme = lightColorScheme(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MyApplicationTheme(
|
fun PmudemoTheme(
|
||||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
// Dynamic color is available on Android 12+
|
// Dynamic color is available on Android 12+
|
||||||
dynamicColor: Boolean = true,
|
dynamicColor: Boolean = false,
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
val colorScheme = when {
|
val colorScheme = when {
|
@ -1,11 +0,0 @@
|
|||||||
package com.example.myapplication.ui.theme
|
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
|
|
||||||
val Purple80 = Color(0xFFD0BCFF)
|
|
||||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
|
||||||
val Pink80 = Color(0xFFEFB8C8)
|
|
||||||
|
|
||||||
val Purple40 = Color(0xFF6650a4)
|
|
||||||
val PurpleGrey40 = Color(0xFF625b71)
|
|
||||||
val Pink40 = Color(0xFF7D5260)
|
|
8
app/src/main/res/drawable/minus.xml
Normal file
8
app/src/main/res/drawable/minus.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path android:fillColor="#000000"
|
||||||
|
android:pathData="M19,13H5v-2h14v2z"/>
|
||||||
|
</vector>
|
BIN
app/src/main/res/drawable/photo.jpg
Normal file
BIN
app/src/main/res/drawable/photo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
25
app/src/main/res/drawable/ticket.xml
Normal file
25
app/src/main/res/drawable/ticket.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="64dp"
|
||||||
|
android:height="64dp"
|
||||||
|
android:viewportWidth="64"
|
||||||
|
android:viewportHeight="64">
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
|
||||||
|
<!-- Зона фона -->
|
||||||
|
<rect width="64" height="64" rx="8" ry="8" fill="#FFC107" />
|
||||||
|
|
||||||
|
<!-- Билет -->
|
||||||
|
<rect x="8" y="12" width="48" height="40" rx="4" ry="4" fill="#FFFFFF" />
|
||||||
|
|
||||||
|
<!-- Линия для разделения -->
|
||||||
|
<line x1="8" y1="32" x2="56" y2="32" stroke="#FFA000" stroke-width="2" />
|
||||||
|
|
||||||
|
<!-- Линия для номера билета -->
|
||||||
|
<line x1="16" y1="48" x2="48" y2="48" stroke="#FFA000" stroke-width="2" />
|
||||||
|
|
||||||
|
<!-- Текст для номера билета -->
|
||||||
|
<text x="32" y="53" fill="#FFA000" font-size="12" text-anchor="middle">
|
||||||
|
</text>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
</vector>
|
@ -1,3 +1,14 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">My Application</string>
|
<string name="app_name">pmu-demo</string>
|
||||||
|
<string name="Cinema_main_title">Фильмы</string>
|
||||||
|
<string name="Cinema_view_title">Фильм</string>
|
||||||
|
<string name="Order_view_title">Заказ</string>
|
||||||
|
<string name="Cinema_name">Название</string>
|
||||||
|
<string name="Cinema_year">Год</string>
|
||||||
|
<string name="Cinema_description">Описание</string>
|
||||||
|
<string name="Cinema_image">Изображение</string>
|
||||||
|
<string name="Cart_title">Корзина</string>
|
||||||
|
<string name="Order_title">Мои заказы</string>
|
||||||
|
<string name="Profile_title">Профиль</string>
|
||||||
|
<string name="Sessions_title">Сеансы</string>
|
||||||
</resources>
|
</resources>
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="Theme.MyApplication" parent="android:Theme.Material.Light.NoActionBar" />
|
<style name="Theme.Pmudemo" parent="android:Theme.Material.Light.NoActionBar" />
|
||||||
</resources>
|
</resources>
|
@ -1,5 +1,6 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application") version "8.1.1" apply false
|
id("com.android.application") version "8.1.2" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
|
id("org.jetbrains.kotlin.android") version "1.8.20" apply false
|
||||||
|
id("com.google.devtools.ksp") version "1.8.20-1.0.11" apply false
|
||||||
}
|
}
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,4 +1,4 @@
|
|||||||
#Mon Sep 18 13:48:19 GMT+04:00 2023
|
#Sun Oct 01 15:07:08 GMT+04:00 2023
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
|
||||||
|
BIN
reports/2 - Балберова Дарья Николаевна.docx
Normal file
BIN
reports/2 - Балберова Дарья Николаевна.docx
Normal file
Binary file not shown.
BIN
reports/3 - Балберова Дарья Николаевна.docx
Normal file
BIN
reports/3 - Балберова Дарья Николаевна.docx
Normal file
Binary file not shown.
@ -15,3 +15,4 @@ dependencyResolutionManagement {
|
|||||||
|
|
||||||
rootProject.name = "My Application"
|
rootProject.name = "My Application"
|
||||||
include(":app")
|
include(":app")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user