Compare commits

...

No commits in common. "main" and "Lab5" have entirely different histories.
main ... Lab5

123 changed files with 5638 additions and 36 deletions

48
.gitignore vendored
View File

@ -1,35 +1,15 @@
# ---> Android
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Log/OS Files
*.log
# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json
# IntelliJ
*.iml
.idea/
misc.xml
deploymentTargetDropDown.xml
render.experimental.xml
# Keystore files
*.jks
*.keystore
# Google Services (e.g. APIs or Firebase)
google-services.json
# Android Profiling
*.hprof
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

3
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name Normal file
View File

@ -0,0 +1 @@
Shawarma

6
.idea/compiler.xml Normal file
View File

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

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="C:\Users\Danya\.android\avd\Nexus_5X_API_34_3.avd" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-12-25T13:14:56.067510100Z" />
</component>
</project>

20
.idea/gradle.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -0,0 +1,32 @@
<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" />
</inspection_tool>
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
</inspection_tool>
</profile>
</component>

6
.idea/kotlinc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.7.0" />
</component>
</project>

6
.idea/misc.xml Normal file
View File

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

6
.idea/vcs.xml Normal file
View File

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

View File

@ -1,2 +0,0 @@
# PIbd-33_Mochalov_D.V._Mobile

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

102
app/build.gradle Normal file
View File

@ -0,0 +1,102 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
//lab 3
id 'kotlin-kapt'
//lab5
id("org.jetbrains.kotlin.plugin.serialization")
}
apply plugin: 'com.android.application'
apply plugin: 'com.google.dagger.hilt.android'
android {
namespace 'com.example.shawarma'
compileSdk 34
defaultConfig {
applicationId "com.example.shawarma"
minSdk 23
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
kapt {
arguments {arg("room.schemaLocation", "$projectDir/schemas")}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
manifestPlaceholders = [usesCleartextTraffic:"true"]
}
debug {
manifestPlaceholders = [usesCleartextTraffic:"true"]
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.2.0'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20"
def nav_version = "2.7.0"
implementation "androidx.navigation:navigation-compose:$nav_version"
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.activity:activity-compose:1.3.1'
implementation "androidx.compose.ui:ui:$compose_ui_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version"
implementation 'androidx.compose.material:material:1.2.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version"
// lab 3
implementation 'androidx.room:room-runtime:2.5.0' // Библиотека "Room"
kapt "androidx.room:room-compiler:2.5.0" // Кодогенератор
implementation 'androidx.room:room-ktx:2.5.0' // Дополнительно для Kotlin Coroutines, Kotlin Flows
// lab4
implementation "com.google.dagger:hilt-android:2.42"
kapt "com.google.dagger:hilt-android-compiler:2.42"
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
implementation 'androidx.compose.runtime:runtime-livedata:1.0.0-beta01'
implementation "androidx.datastore:datastore-preferences:1.0.0"
implementation("androidx.room:room-paging:2.5.0")
implementation("androidx.paging:paging-compose:3.2.1")
// lab5
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
implementation("androidx.paging:paging-compose:3.2.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
}

21
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,208 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "fd664bd9d0a27511fb20675444548276",
"entities": [
{
"tableName": "users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `user_login` TEXT NOT NULL, `user_password` TEXT NOT NULL, `user_role` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "login",
"columnName": "user_login",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "user_password",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "role",
"columnName": "user_role",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "orders",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `order_status` TEXT NOT NULL, `user_id` INTEGER, `date` INTEGER NOT NULL, FOREIGN KEY(`user_id`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "status",
"columnName": "order_status",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "userId",
"columnName": "user_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "date",
"columnName": "date",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_orders_user_id",
"unique": false,
"columnNames": [
"user_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_orders_user_id` ON `${TABLE_NAME}` (`user_id`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"user_id"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "products",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `product_title` TEXT NOT NULL, `product_price` INTEGER NOT NULL, `product_old_price` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "product_title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "price",
"columnName": "product_price",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "oldPrice",
"columnName": "product_old_price",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "order_product",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`order_id` INTEGER NOT NULL, `product_id` INTEGER NOT NULL, `quantity` INTEGER NOT NULL, `total_price` INTEGER NOT NULL, PRIMARY KEY(`order_id`, `product_id`))",
"fields": [
{
"fieldPath": "orderId",
"columnName": "order_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "productId",
"columnName": "product_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "quantity",
"columnName": "quantity",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "totalPrice",
"columnName": "total_price",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"order_id",
"product_id"
]
},
"indices": [
{
"name": "index_order_product_order_id",
"unique": false,
"columnNames": [
"order_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_order_product_order_id` ON `${TABLE_NAME}` (`order_id`)"
},
{
"name": "index_order_product_product_id",
"unique": false,
"columnNames": [
"product_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_order_product_product_id` ON `${TABLE_NAME}` (`product_id`)"
}
],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'fd664bd9d0a27511fb20675444548276')"
]
}
}

View File

@ -0,0 +1,208 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "1ce8ad5b9b5decfebb42bc2f3c33393d",
"entities": [
{
"tableName": "users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `user_login` TEXT NOT NULL, `user_password` TEXT NOT NULL, `user_role` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "login",
"columnName": "user_login",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "user_password",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "role",
"columnName": "user_role",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "orders",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `order_status` TEXT NOT NULL, `user_id` INTEGER, `date` TEXT NOT NULL, FOREIGN KEY(`user_id`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "status",
"columnName": "order_status",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "userId",
"columnName": "user_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "date",
"columnName": "date",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_orders_user_id",
"unique": false,
"columnNames": [
"user_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_orders_user_id` ON `${TABLE_NAME}` (`user_id`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"user_id"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "products",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `product_title` TEXT NOT NULL, `product_price` INTEGER NOT NULL, `product_old_price` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "product_title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "price",
"columnName": "product_price",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "oldPrice",
"columnName": "product_old_price",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "order_product",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`order_id` INTEGER NOT NULL, `product_id` INTEGER NOT NULL, `quantity` INTEGER NOT NULL, `total_price` INTEGER NOT NULL, PRIMARY KEY(`order_id`, `product_id`))",
"fields": [
{
"fieldPath": "orderId",
"columnName": "order_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "productId",
"columnName": "product_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "quantity",
"columnName": "quantity",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "totalPrice",
"columnName": "total_price",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"order_id",
"product_id"
]
},
"indices": [
{
"name": "index_order_product_order_id",
"unique": false,
"columnNames": [
"order_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_order_product_order_id` ON `${TABLE_NAME}` (`order_id`)"
},
{
"name": "index_order_product_product_id",
"unique": false,
"columnNames": [
"product_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_order_product_product_id` ON `${TABLE_NAME}` (`product_id`)"
}
],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1ce8ad5b9b5decfebb42bc2f3c33393d')"
]
}
}

View File

@ -0,0 +1,196 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "12eb76256f54b2c513a3073a2e582c4c",
"entities": [
{
"tableName": "users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `user_login` TEXT NOT NULL, `user_password` TEXT NOT NULL, `user_role` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "login",
"columnName": "user_login",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "user_password",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "role",
"columnName": "user_role",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "orders",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `order_status` TEXT NOT NULL, `user_id` INTEGER, `date` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "status",
"columnName": "order_status",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "userId",
"columnName": "user_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "date",
"columnName": "date",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_orders_user_id",
"unique": false,
"columnNames": [
"user_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_orders_user_id` ON `${TABLE_NAME}` (`user_id`)"
}
],
"foreignKeys": []
},
{
"tableName": "products",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `product_title` TEXT NOT NULL, `product_price` INTEGER NOT NULL, `product_old_price` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "product_title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "price",
"columnName": "product_price",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "oldPrice",
"columnName": "product_old_price",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "order_product",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`order_id` INTEGER NOT NULL, `product_id` INTEGER NOT NULL, `quantity` INTEGER NOT NULL, `total_price` INTEGER NOT NULL, PRIMARY KEY(`order_id`, `product_id`))",
"fields": [
{
"fieldPath": "orderId",
"columnName": "order_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "productId",
"columnName": "product_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "quantity",
"columnName": "quantity",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "totalPrice",
"columnName": "total_price",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"order_id",
"product_id"
]
},
"indices": [
{
"name": "index_order_product_order_id",
"unique": false,
"columnNames": [
"order_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_order_product_order_id` ON `${TABLE_NAME}` (`order_id`)"
},
{
"name": "index_order_product_product_id",
"unique": false,
"columnNames": [
"product_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_order_product_product_id` ON `${TABLE_NAME}` (`product_id`)"
}
],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '12eb76256f54b2c513a3073a2e582c4c')"
]
}
}

View File

@ -0,0 +1,24 @@
package com.example.shawarma
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.shawarma", appContext.packageName)
}
}

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".ShawarmaApp"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Shawarma"
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:windowSoftInputMode="adjustResize"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Shawarma">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,89 @@
package com.example.shawarma
import android.app.Application
import androidx.room.Room
import com.example.shawarma.data.api.MyServerService
import com.example.shawarma.data.api.repos.RestOrderProductRepository
import com.example.shawarma.data.api.repos.RestOrderRepository
import com.example.shawarma.data.api.repos.RestProductRepository
import com.example.shawarma.data.api.repos.RestUserRepository
import com.example.shawarma.data.db.AppDatabase
import com.example.shawarma.data.repos.OrderProductRepository
import com.example.shawarma.data.repos.OrderRepository
import com.example.shawarma.data.repos.ProductRepository
import com.example.shawarma.data.repos.UserRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideDatabase(app: Application) : AppDatabase {
return Room.databaseBuilder(
app,
AppDatabase::class.java,
AppDatabase.DB_NAME
).build()
}
@Provides
@Singleton
fun provideServerService() : MyServerService {
return MyServerService.getInstance()
}
@Provides
@Singleton
fun provideUserRepository(db: AppDatabase) : UserRepository {
return UserRepository(db.userDao())
}
@Provides
@Singleton
fun provideRestUserRepository(service: MyServerService) : RestUserRepository {
return RestUserRepository(service)
}
@Provides
@Singleton
fun provideProductRepository(db: AppDatabase, restProductRepository: RestProductRepository) : ProductRepository {
return ProductRepository(database = db, db.productDao(), db.orderProductDao(), restProductRepository)
}
@Provides
@Singleton
fun provideRestProductRepository(service: MyServerService) : RestProductRepository {
return RestProductRepository(service)
}
@Provides
@Singleton
fun provideOrderRepository(db: AppDatabase, restOrderRepository: RestOrderRepository) : OrderRepository {
return OrderRepository(db, db.orderDao(), db.productDao(), db.orderProductDao(), restOrderRepository)
}
@Provides
@Singleton
fun provideRestOrderRepository(service: MyServerService) : RestOrderRepository {
return RestOrderRepository(service)
}
@Provides
@Singleton
fun provideOrderProductRepository(db: AppDatabase, restOrderProductRepository: RestOrderProductRepository) : OrderProductRepository {
return OrderProductRepository(db.orderProductDao(), restOrderProductRepository)
}
@Provides
@Singleton
fun provideRestOrderProductRepository(service: MyServerService) : RestOrderProductRepository {
return RestOrderProductRepository(service)
}
}

View File

@ -0,0 +1,29 @@
package com.example.shawarma
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Surface
import androidx.compose.ui.Modifier
import com.example.shawarma.screens.MainNavBar
import com.example.shawarma.screens.authorization.AuthorizationScreen
import com.example.shawarma.screens.registration.RegistrationScreen
import com.example.shawarma.ui.theme.MyLightYellow
import com.example.shawarma.ui.theme.ShawarmaTheme
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.HiltAndroidApp
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MainNavBar()
}
}
}

View File

@ -0,0 +1,11 @@
package com.example.shawarma
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class ShawarmaApp : Application() {
override fun onCreate() {
super.onCreate()
}
}

View File

@ -0,0 +1,134 @@
package com.example.shawarma.data.api
import com.example.shawarma.data.api.models.OrderListResponse
import com.example.shawarma.data.api.models.OrderModelRemote
import com.example.shawarma.data.api.models.OrderProductRemote
import com.example.shawarma.data.api.models.ProductListResponse
import com.example.shawarma.data.api.models.ProductModelRemote
import com.example.shawarma.data.api.models.TokenModelRemote
import com.example.shawarma.data.api.models.UserModelRemote
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
interface MyServerService {
//
// USER
//
@POST("register")
suspend fun createUser(
@Body user: UserModelRemote,
): UserModelRemote
@POST("auth")
suspend fun getToken(
@Body user: UserModelRemote
) : TokenModelRemote
@POST("check/login")
suspend fun checkLogin(
@Body user: UserModelRemote
) :UserModelRemote?
//
// PRODUCTS
//
@GET("user/products/{after}")
suspend fun getProductsList(@Path("after") after: Int, @Header("Authorization") token: String) : ProductListResponse
@GET("user/discounts/{after}")
suspend fun getDiscountsList(@Path("after") after: Int, @Header("Authorization") token: String) : ProductListResponse
@GET("user/items/{after}")
suspend fun getItemsList(@Path("after") after: Int, @Header("Authorization") token: String) : ProductListResponse
@POST("product")
suspend fun insertProduct(
@Body product: ProductModelRemote,
@Header("Authorization") token: String
) : ProductModelRemote
@PUT("product")
suspend fun updateProduct(
@Body product: ProductModelRemote,
@Header("Authorization") token: String
): ProductModelRemote
@DELETE("product/{id}")
suspend fun deleteProduct(@Path("id") id: Int, @Header("Authorization") token: String)
//
// ORDERS
//
@GET("order/unpaid")
suspend fun getUnpaidOrder(@Header("Authorization") token: String) : OrderModelRemote
@GET("order/paid/{after}")
suspend fun getPaidOrdersList(@Path("after") after: Int, @Header("Authorization") token: String) : OrderListResponse
@GET("order/all_paid/{after}")
suspend fun getAllPaidOrdersList(@Path("after") after: Int, @Header("Authorization") token: String) : OrderListResponse
@GET("order/all_ready/{after}")
suspend fun getAllReadyOrdersList(@Path("after") after: Int, @Header("Authorization") token: String) : OrderListResponse
@GET("order/all_served/{after}")
suspend fun getAllServedOrdersList(@Path("after") after: Int, @Header("Authorization") token: String) : OrderListResponse
@POST("order")
suspend fun insertOrder(@Body order: OrderModelRemote, @Header("Authorization") token: String) : OrderModelRemote?
@PUT("order")
suspend fun updateOrder(@Body order: OrderModelRemote, @Header("Authorization") token: String) : OrderModelRemote?
@DELETE("order/{id}")
suspend fun deleteOrder(@Path("id") id: Int, @Header("Authorization") token: String)
//
// ORDER PRODUCTS
//
@POST("order/product")
suspend fun insertOrderProduct(@Body orderProduct: OrderProductRemote, @Header("Authorization") token: String)
@PUT("order/product")
suspend fun updateOrderProduct(@Body orderProduct: OrderProductRemote, @Header("Authorization") token: String)
@POST("order/product/delete")
suspend fun deleteOrderProduct(@Body orderProduct: OrderProductRemote, @Header("Authorization") token: String)
companion object {
private const val BASE_URL = "https://10.0.2.2:80/api/"
@Volatile
private var INSTANCE: MyServerService? = null
fun getInstance(): MyServerService {
return INSTANCE ?: synchronized(this) {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BASIC
val client = OkHttpClientSettings.getUnsafeOkHttpClient()
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
.create(MyServerService::class.java)
.also { INSTANCE = it }
}
}
}
}

View File

@ -0,0 +1,57 @@
package com.example.shawarma.data.api;
import java.security.cert.CertificateException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
public class OkHttpClientSettings {
public static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,81 @@
package com.example.shawarma.data.api.mediators
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.example.shawarma.data.api.MyServerService
import com.example.shawarma.data.api.models.OrderListResponse
import com.example.shawarma.data.api.models.toOrderModel
import com.example.shawarma.data.db.AppDatabase
import com.example.shawarma.data.models.OrderModel
import com.example.shawarma.data.models.OrderWithProducts
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class OrderRemoteMediator (
private val database: AppDatabase,
private val serverService: MyServerService,
private val query: String,
private val token: String
) : RemoteMediator<Int, OrderWithProducts>(){
private val orderDao = database.orderDao()
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, OrderWithProducts>
): MediatorResult {
return try {
var loadKey = when (loadType) {
LoadType.REFRESH -> null
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> {
val lastItem = state.lastItemOrNull()
?: return MediatorResult.Success(endOfPaginationReached = true)
lastItem.order.id
}
}
if (loadKey == null) {
loadKey = 0
}
val response: OrderListResponse = when (query) {
"paid" -> {
serverService.getPaidOrdersList(after = loadKey, token = token)
}
"all_paid" -> {
serverService.getAllPaidOrdersList(after = loadKey, token = token)
}
"all_ready" -> {
serverService.getAllReadyOrdersList(after = loadKey, token = token)
}
"all_served" -> {
serverService.getAllServedOrdersList(after = loadKey, token = token)
}
else -> {
OrderListResponse()
}
}
database.withTransaction {
if (loadType == LoadType.REFRESH) {
orderDao.deleteByQuery(query)
}
val orders = mutableListOf<OrderModel>()
for (order in response.orders) {
orders.add(order.toOrderModel())
}
orderDao.insertAll(orders)
}
MediatorResult.Success(endOfPaginationReached = response.nextKey == -1)
} catch (e: IOException) {
MediatorResult.Error(e)
}
}
}

View File

@ -0,0 +1,86 @@
package com.example.shawarma.data.api.mediators
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import androidx.room.withTransaction
import com.example.shawarma.data.api.MyServerService
import com.example.shawarma.data.api.models.ProductListResponse
import com.example.shawarma.data.api.models.toProductModel
import com.example.shawarma.data.db.AppDatabase
import com.example.shawarma.data.models.ProductModel
import kotlinx.coroutines.flow.first
import java.io.IOException
@OptIn(ExperimentalPagingApi::class)
class ProductRemoteMediator (
private val database: AppDatabase,
private val serverService: MyServerService,
private val query: String,
private val token: String
) : RemoteMediator<Int, ProductModel>(){
private val productDao = database.productDao()
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, ProductModel>
): MediatorResult {
return try {
var loadKey = when (loadType) {
LoadType.REFRESH -> null
LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> {
val lastItem = state.lastItemOrNull()
?: return MediatorResult.Success(endOfPaginationReached = true)
lastItem.id
}
}
if (loadKey == null) {
loadKey = 0
}
val response: ProductListResponse = when (query) {
"home" -> {
serverService.getProductsList(after = loadKey, token = token)
}
"discounts" -> {
serverService.getDiscountsList(after = loadKey, token = token)
}
"items" -> {
serverService.getItemsList(after = loadKey, token = token)
}
else -> {ProductListResponse()}
}
database.withTransaction {
if (loadType == LoadType.REFRESH) {
if (query != "items") {
productDao.deleteByQuery(query)
}
else {
val present = productDao.getItemsByLoadKey(loadKey).first()
val responseProducts = response.products.map { it -> it.toProductModel() }
for (product in present) {
if (product !in responseProducts ) {
productDao.delete(product)
}
}
}
}
val products = mutableListOf<ProductModel>()
for (prod in response.products) {
products.add(prod.toProductModel())
}
productDao.insertAll(products)
}
MediatorResult.Success(endOfPaginationReached = response.nextKey == -1)
} catch (e: IOException) {
MediatorResult.Error(e)
}
}
}

View File

@ -0,0 +1,48 @@
package com.example.shawarma.data.api.models
import com.example.shawarma.data.models.OrderModel
import com.example.shawarma.data.models.OrderProductModel
import kotlinx.serialization.Serializable
@Serializable
data class OrderModelRemote(
val id: Int? = null,
val status: String = "",
val user_id: Int? = -1,
val date: String = "",
val order_products: List<OrderProductRemote> = listOf()
)
@Serializable
data class OrderListResponse(
val orders: List<OrderModelRemote> = listOf(),
val nextKey: Int? = null
)
fun OrderModelRemote.toOrderModel() : OrderModel = OrderModel(
id, status, user_id, date = date
)
fun OrderModel.toOrderModelRemote() : OrderModelRemote = OrderModelRemote(
id, status, userId, date.toString()
)
@Serializable
data class OrderProductRemote(
val id: Int? = null,
val order_id: Int = -1,
val product_id: Int = -1,
val quantity: Int = 0,
val total_price: Int = 0,
val order: OrderModelRemote? = null,
val product: ProductModelRemote? = null
)
fun OrderProductRemote.toOrderProductModel() : OrderProductModel = OrderProductModel(
order_id, product_id, quantity, total_price
)
fun OrderProductModel.toOrderProductRemote() : OrderProductRemote = OrderProductRemote(
order_id = orderId, product_id = productId, quantity = quantity, total_price = totalPrice
)

View File

@ -0,0 +1,28 @@
package com.example.shawarma.data.api.models
import com.example.shawarma.data.models.ProductModel
import kotlinx.serialization.Serializable
@Serializable
data class ProductModelRemote(
val id: Int? = null,
val title: String = "",
val price: Int = 0,
val old_price: Int? = null,
val order_products: List<OrderProductRemote> = listOf()
)
@Serializable
data class ProductListResponse(
val products: List<ProductModelRemote> = listOf(),
val nextKey: Int? = null
)
fun ProductModelRemote.toProductModel(): ProductModel = ProductModel(
id, title, price, old_price
)
fun ProductModel.toProductModelRemote(): ProductModelRemote = ProductModelRemote(
title = title, price = price, old_price = oldPrice, id = id
)

View File

@ -0,0 +1,27 @@
package com.example.shawarma.data.api.models
import com.example.shawarma.data.models.UserModel
import kotlinx.serialization.Serializable
@Serializable
data class TokenModelRemote(
val access_token: String = "",
val message: String = ""
)
@Serializable
data class UserModelRemote(
val id: Int = 0,
val login: String = "",
val password:String = "",
val role:String = "",
val message: String = ""
)
fun UserModelRemote.toUserModel(): UserModel = UserModel(
id, login, password, role
)
fun UserModel.toUserModelRemote(): UserModelRemote = UserModelRemote(
login = login, password = password, role = role
)

View File

@ -0,0 +1,21 @@
package com.example.shawarma.data.api.repos
import com.example.shawarma.data.api.MyServerService
import com.example.shawarma.data.api.models.OrderProductRemote
import javax.inject.Inject
class RestOrderProductRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun insertOrderProduct(token: String, orderProduct: OrderProductRemote) {
service.insertOrderProduct(orderProduct, token)
}
suspend fun updateOrderProduct(token: String, orderProduct: OrderProductRemote) {
service.updateOrderProduct(orderProduct, token)
}
suspend fun deleteOrderProduct(token: String, orderProduct: OrderProductRemote) {
service.deleteOrderProduct(orderProduct, token)
}
}

View File

@ -0,0 +1,25 @@
package com.example.shawarma.data.api.repos
import com.example.shawarma.data.api.MyServerService
import com.example.shawarma.data.api.models.OrderModelRemote
import javax.inject.Inject
class RestOrderRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun getUnpaidOrder(token:String) : OrderModelRemote {
return service.getUnpaidOrder(token)
}
suspend fun insertOrder(token: String, order: OrderModelRemote): OrderModelRemote? {
return service.insertOrder(order, token)
}
suspend fun updateOrder(token: String, order: OrderModelRemote): OrderModelRemote? {
return service.updateOrder(order, token)
}
suspend fun deleteOrder(token: String, orderId: Int) {
service.deleteOrder(orderId, token)
}
}

View File

@ -0,0 +1,22 @@
package com.example.shawarma.data.api.repos
import com.example.shawarma.data.api.MyServerService
import com.example.shawarma.data.api.models.toProductModelRemote
import com.example.shawarma.data.models.ProductModel
import javax.inject.Inject
class RestProductRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun insert(product: ProductModel, token: String) {
service.insertProduct(product.toProductModelRemote(), token)
}
suspend fun update(product: ProductModel, token: String) {
service.updateProduct((product.toProductModelRemote()), token)
}
suspend fun delete(id: Int, token: String) {
service.deleteProduct(id, token)
}
}

View File

@ -0,0 +1,24 @@
package com.example.shawarma.data.api.repos
import com.example.shawarma.data.api.MyServerService
import com.example.shawarma.data.api.models.TokenModelRemote
import com.example.shawarma.data.api.models.UserModelRemote
import com.example.shawarma.data.api.models.toUserModelRemote
import com.example.shawarma.data.models.UserModel
import javax.inject.Inject
class RestUserRepository @Inject constructor(
private val service: MyServerService
) {
suspend fun insert(user: UserModel) {
service.createUser(user.toUserModelRemote())
}
suspend fun getToken(user: UserModel): TokenModelRemote {
return service.getToken(user.toUserModelRemote())
}
suspend fun checkLogin(user: UserModel): UserModelRemote? {
return service.checkLogin(user.toUserModelRemote())
}
}

View File

@ -0,0 +1,73 @@
package com.example.shawarma.data.db
import android.content.Context
import androidx.room.AutoMigration
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.shawarma.data.interfaces.dao.OrderDao
import com.example.shawarma.data.interfaces.dao.OrderProductDao
import com.example.shawarma.data.interfaces.dao.ProductDao
import com.example.shawarma.data.interfaces.dao.UserDao
import com.example.shawarma.data.models.OrderModel
import com.example.shawarma.data.models.OrderProductModel
import com.example.shawarma.data.models.ProductModel
import com.example.shawarma.data.models.UserModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Database(
entities =
[
UserModel::class,
OrderModel::class,
ProductModel::class,
OrderProductModel::class,
],
version = 3,
autoMigrations = [AutoMigration (from = 1, to = 2), AutoMigration (from = 2, to = 3)],
exportSchema = true
)
@TypeConverters(Converter::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao() : UserDao
abstract fun productDao() : ProductDao
abstract fun orderDao() : OrderDao
abstract fun orderProductDao() : OrderProductDao
companion object {
const val DB_NAME: String = "shawarma-db"
@Volatile
private var INSTANCE: AppDatabase? = null
private suspend fun populateDatabase() {
INSTANCE?.let { database ->
}
}
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 }
}
}
}
}

View File

@ -0,0 +1,16 @@
package com.example.shawarma.data.db
import androidx.room.TypeConverter
import java.util.Date
class Converter {
@TypeConverter
fun fromTimestamp(value: Long?): Date? {
return value?.let { Date(it) }
}
@TypeConverter
fun dateToTimestamp(date: Date?): Long? {
return date?.time?.toLong()
}
}

View File

@ -0,0 +1,69 @@
package com.example.shawarma.data.interfaces.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy.Companion.REPLACE
import androidx.room.Query
import androidx.room.Update
import com.example.shawarma.data.models.OrderModel
import com.example.shawarma.data.models.OrderWithProducts
import kotlinx.coroutines.flow.Flow
@Dao
interface OrderDao {
@Insert(onConflict = REPLACE)
suspend fun insert(order: OrderModel) : Long
@Update
suspend fun update(order: OrderModel)
@Delete
suspend fun delete(order: OrderModel)
@Query("select * from orders")
fun getAll(): Flow<List<OrderWithProducts>>
@Query("select * from orders where orders.id =:id")
fun getById(id: Int): Flow<OrderWithProducts?>
@Query("select * from orders where orders.user_id =:userId")
fun getByUserId(userId: Int): Flow<List<OrderWithProducts>>
@Query("select * from orders where orders.user_id =:userId and orders.order_status = 'Неоплачено'")
fun getUnpaidByUser(userId: Int) : Flow<OrderWithProducts>
@Query("select * from orders where orders.user_id =:userId and (orders.order_status = 'Готовится' or orders.order_status = 'Готово')")
fun getPaidByUser(userId: Int) : Flow<List<OrderWithProducts>>
suspend fun insertAll(orders: List<OrderModel>) {
for (order in orders) {
insert(order)
}
}
@Query("select * from orders where orders.order_status = 'Готовится' or orders.order_status = 'Готово'")
fun getPaidPaged(): PagingSource<Int, OrderWithProducts>
@Query("select * from orders where orders.order_status = 'Готовится'")
fun getAllPaid(): PagingSource<Int, OrderWithProducts>
@Query("select * from orders where orders.order_status = 'Готово'")
fun getAllReady(): PagingSource<Int, OrderWithProducts>
@Query("select * from orders where orders.order_status = 'Выдано'")
fun getAllServed(): PagingSource<Int, OrderWithProducts>
@Query("delete from orders where orders.order_status = 'Готовится'")
fun deleteAllPaid()
@Query("delete from orders where orders.order_status = 'Готово'")
fun deleteAllReady()
@Query("delete from orders where orders.order_status = 'Выдано'")
fun deleteAllServed()
fun deleteByQuery(query: String) {
if (query == "paid" || query == "all_paid") {
deleteAllPaid()
}
if (query == "all_ready") {
deleteAllReady()
}
if (query == "all_served") {
deleteAllServed()
}
}
}

View File

@ -0,0 +1,22 @@
package com.example.shawarma.data.interfaces.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy.Companion.REPLACE
import androidx.room.Query
import androidx.room.Update
import com.example.shawarma.data.models.OrderProductModel
@Dao
interface OrderProductDao {
@Insert(onConflict = REPLACE)
suspend fun insert(order: OrderProductModel)
@Update
suspend fun update(order: OrderProductModel)
@Query("delete from order_product WHERE product_id = :productId")
suspend fun deleteByProductId(productId: Int);
@Query("delete from order_product WHERE order_id = :orderId")
suspend fun deleteByOrderId(orderId: Int);
@Delete
suspend fun delete(order: OrderProductModel)
}

View File

@ -0,0 +1,74 @@
package com.example.shawarma.data.interfaces.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy.Companion.REPLACE
import androidx.room.Query
import androidx.room.Update
import com.example.shawarma.data.models.ProductModel
import kotlinx.coroutines.flow.Flow
@Dao
interface ProductDao {
@Insert(onConflict = REPLACE)
suspend fun insert(product: ProductModel)
suspend fun insertAll(products: List<ProductModel>) {
for (product in products) {
insert(product)
}
}
@Update
suspend fun update(product: ProductModel)
@Delete()
suspend fun delete(product: ProductModel)
@Query("select * from products where products.product_old_price is null")
fun getAll() : Flow<List<ProductModel>>
@Query("select * from products where products.product_old_price is not null")
fun getDiscounts() : Flow<List<ProductModel>>
@Query("select * from products")
fun getItems() : Flow<List<ProductModel>>
@Query("select * from products where products.id = :id")
fun getById(id: Int): Flow<ProductModel>
@Query("select * from products where products.product_old_price is null")
fun getPaged(): PagingSource<Int, ProductModel>
@Query("select * from products where products.product_old_price is not null")
fun getPagedDiscounts(): PagingSource<Int, ProductModel>
@Query("select * from products")
fun getPagedItems(): PagingSource<Int, ProductModel>
@Query("select * from products where products.id > :loadKey limit 20")
fun getItemsByLoadKey(loadKey: Int): Flow<List<ProductModel>>
@Query("delete from products where products.product_old_price is null")
fun deleteAllProducts()
@Query("delete from products where products.product_old_price is not null")
fun deleteAllDiscountProducts()
@Query("delete from products")
fun deleteAllItems()
fun deleteByQuery(query: String) {
if (query == "home") {
deleteAllProducts()
}
if (query == "discounts") {
deleteAllDiscountProducts()
}
if (query == "items") {
deleteAllItems()
}
}
}

View File

@ -0,0 +1,26 @@
package com.example.shawarma.data.interfaces.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy.Companion.ABORT
import androidx.room.Query
import androidx.room.Update
import com.example.shawarma.data.models.UserModel
import kotlinx.coroutines.flow.Flow
@Dao
interface UserDao {
@Insert(onConflict = ABORT)
suspend fun insert(user: UserModel)
@Update
suspend fun update(user: UserModel)
@Delete
suspend fun delete(user: UserModel)
@Query("select * from users order by user_login collate nocase asc")
fun getAll(): Flow<List<UserModel>>
@Query("select * from users where id = :id")
fun getById(id: Int): Flow<UserModel>
@Query("select * from users where user_login = :login and user_password = :password limit 1")
fun login(login: String, password: String) : Flow<UserModel?>
}

View File

@ -0,0 +1,22 @@
package com.example.shawarma.data.models
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(
tableName = "orders"
)
data class OrderModel(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Int?,
@ColumnInfo(name = "order_status")
var status: String,
@ColumnInfo(name = "user_id", index = true)
val userId: Int?,
@ColumnInfo(name = "date")
val date: String
)

View File

@ -0,0 +1,16 @@
package com.example.shawarma.data.models
import androidx.room.ColumnInfo
import androidx.room.Entity
@Entity(tableName = "order_product", primaryKeys = ["order_id", "product_id"])
data class OrderProductModel(
@ColumnInfo(name = "order_id", index = true)
var orderId: Int,
@ColumnInfo(name = "product_id", index = true)
var productId: Int,
@ColumnInfo(name = "quantity")
var quantity: Int,
@ColumnInfo(name = "total_price")
var totalPrice: Int
)

View File

@ -0,0 +1,12 @@
package com.example.shawarma.data.models
import androidx.room.Embedded
import androidx.room.Relation
data class OrderProductModelWithProduct(
@Embedded
val orderProductModel: OrderProductModel,
@Relation(entity = ProductModel::class, parentColumn = "product_id", entityColumn = "id")
val product: ProductModel?,
)

View File

@ -0,0 +1,11 @@
package com.example.shawarma.data.models
import androidx.room.Embedded
import androidx.room.Relation
data class OrderWithProducts(
@Embedded
val order: OrderModel,
@Relation(entity = OrderProductModel::class, parentColumn = "id", entityColumn = "order_id")
val orderWithProducts: List<OrderProductModelWithProduct>
)

View File

@ -0,0 +1,31 @@
package com.example.shawarma.data.models
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "products")
data class ProductModel(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Int?,
@ColumnInfo(name = "product_title")
val title: String,
@ColumnInfo(name = "product_price")
val price: Int,
@ColumnInfo(name = "product_old_price")
val oldPrice: Int?,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as ProductModel
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -0,0 +1,5 @@
package com.example.shawarma.data.models
enum class OrderStatus {
Неоплачено, Готовится, Готово, Выдано
}

View File

@ -0,0 +1,30 @@
package com.example.shawarma.data.models
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "users")
data class UserModel(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Int?,
@ColumnInfo(name = "user_login")
val login: String,
@ColumnInfo(name = "user_password")
val password: String,
@ColumnInfo(name = "user_role")
val role: String
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as UserModel
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id ?: -1
}
}

View File

@ -0,0 +1,26 @@
package com.example.shawarma.data.repos
import com.example.shawarma.data.api.models.toOrderProductRemote
import com.example.shawarma.data.api.repos.RestOrderProductRepository
import com.example.shawarma.data.interfaces.dao.OrderProductDao
import com.example.shawarma.data.models.OrderProductModel
import javax.inject.Inject
class OrderProductRepository @Inject constructor(
private val orderProductDao: OrderProductDao,
private val restOrderProductRepository: RestOrderProductRepository
) {
suspend fun insert(token: String, orderProduct: OrderProductModel) {
orderProductDao.insert(orderProduct)
return restOrderProductRepository.insertOrderProduct(token, orderProduct.toOrderProductRemote())
}
suspend fun update(token: String, orderProduct: OrderProductModel) {
orderProductDao.update(orderProduct)
return restOrderProductRepository.updateOrderProduct(token, orderProduct.toOrderProductRemote())
}
suspend fun delete(token: String, orderProduct: OrderProductModel) {
orderProductDao.delete(orderProduct)
restOrderProductRepository.deleteOrderProduct(token, orderProduct.toOrderProductRemote())
}
}

View File

@ -0,0 +1,106 @@
package com.example.shawarma.data.repos
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.shawarma.data.api.MyServerService
import com.example.shawarma.data.api.mediators.OrderRemoteMediator
import com.example.shawarma.data.api.models.toOrderModel
import com.example.shawarma.data.api.models.toOrderModelRemote
import com.example.shawarma.data.api.models.toOrderProductModel
import com.example.shawarma.data.api.repos.RestOrderRepository
import com.example.shawarma.data.db.AppDatabase
import com.example.shawarma.data.interfaces.dao.OrderDao
import com.example.shawarma.data.interfaces.dao.OrderProductDao
import com.example.shawarma.data.interfaces.dao.ProductDao
import com.example.shawarma.data.models.OrderModel
import com.example.shawarma.data.models.OrderWithProducts
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import javax.inject.Inject
class OrderRepository @Inject constructor(
private val database: AppDatabase,
private val orderDao: OrderDao,
private val productDao: ProductDao,
private val orderProductDao: OrderProductDao,
private val restRepository: RestOrderRepository
){
suspend fun insert(token: String, order: OrderModel): OrderModel? {
orderDao.insert(order)
val result = restRepository.insertOrder(token, order.toOrderModelRemote())
if (result == null) {
return result
}
return result.toOrderModel()
}
suspend fun update(token: String, order:OrderModel) {
orderDao.update(order)
restRepository.updateOrder(token, order.toOrderModelRemote())
}
suspend fun delete(token: String, order: OrderModel) {
orderProductDao.deleteByOrderId(order.id!!)
orderDao.delete(order)
restRepository.deleteOrder(token, order.id!!)
}
fun getById(id: Int): Flow<OrderWithProducts?>{
return orderDao.getById(id)
}
suspend fun getUnpaidByUser(token: String) : OrderWithProducts? {
val order = restRepository.getUnpaidOrder(token)
if (order!!.id == null) {
return null
}
if (order!!.id != null) {
orderDao.insert(order.toOrderModel())
for (product in order.order_products) {
orderProductDao.insert(product.toOrderProductModel())
}
return orderDao.getUnpaidByUser(order.user_id!!).first()
}
return null
}
@OptIn(ExperimentalPagingApi::class)
fun getPaidPaged(token: String): Flow<PagingData<OrderWithProducts>> = Pager(
config = PagingConfig(
pageSize = 6,
enablePlaceholders = false
),
pagingSourceFactory = orderDao::getPaidPaged,
remoteMediator = OrderRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = "paid", token = token)
).flow
@OptIn(ExperimentalPagingApi::class)
fun getAllPaidPaged(token: String): Flow<PagingData<OrderWithProducts>> = Pager(
config = PagingConfig(
pageSize = 6,
enablePlaceholders = false
),
pagingSourceFactory = orderDao::getAllPaid,
remoteMediator = OrderRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = "all_paid", token = token)
).flow
@OptIn(ExperimentalPagingApi::class)
fun getAllReadyPaged(token: String): Flow<PagingData<OrderWithProducts>> = Pager(
config = PagingConfig(
pageSize = 6,
enablePlaceholders = false
),
pagingSourceFactory = orderDao::getAllReady,
remoteMediator = OrderRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = "all_ready", token = token)
).flow
@OptIn(ExperimentalPagingApi::class)
fun getAllServedPaged(token: String): Flow<PagingData<OrderWithProducts>> = Pager(
config = PagingConfig(
pageSize = 6,
enablePlaceholders = false
),
pagingSourceFactory = orderDao::getAllServed,
remoteMediator = OrderRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = "all_served", token = token)
).flow
}

View File

@ -0,0 +1,66 @@
package com.example.shawarma.data.repos
import androidx.paging.ExperimentalPagingApi
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.example.shawarma.data.api.MyServerService
import com.example.shawarma.data.api.mediators.ProductRemoteMediator
import com.example.shawarma.data.api.repos.RestProductRepository
import com.example.shawarma.data.db.AppDatabase
import com.example.shawarma.data.interfaces.dao.OrderProductDao
import com.example.shawarma.data.interfaces.dao.ProductDao
import com.example.shawarma.data.models.ProductModel
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class ProductRepository @Inject constructor(
private val database: AppDatabase,
private val productDao: ProductDao,
private val orderProductDao: OrderProductDao,
private val restRepository: RestProductRepository
) {
suspend fun insert(product: ProductModel, token: String) {
return restRepository.insert(product, token)
}
suspend fun update(product: ProductModel, token: String) {
return restRepository.update(product, token)
}
suspend fun delete(product: ProductModel, token: String) {
productDao.delete(product)
return restRepository.delete(product.id!!, token)
}
fun getById(id: Int): Flow<ProductModel> {
return productDao.getById(id)
}
@OptIn(ExperimentalPagingApi::class)
fun getAllProductsPaged(token: String): Flow<PagingData<ProductModel>> = Pager(
config = PagingConfig(
pageSize = 6,
enablePlaceholders = false
),
pagingSourceFactory = productDao::getPaged,
remoteMediator = ProductRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = "home", token = token)
).flow
@OptIn(ExperimentalPagingApi::class)
fun getAllDiscountsPaged(token: String): Flow<PagingData<ProductModel>> = Pager(
config = PagingConfig(
pageSize = 6,
enablePlaceholders = false
),
pagingSourceFactory = productDao::getPagedDiscounts,
remoteMediator = ProductRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = "discounts", token = token)
).flow
@OptIn(ExperimentalPagingApi::class)
fun getAllItemsPaged(token: String): Flow<PagingData<ProductModel>> = Pager(
config = PagingConfig(
pageSize = 6,
enablePlaceholders = false
),
pagingSourceFactory = productDao::getPagedItems,
remoteMediator = ProductRemoteMediator(database = database, serverService = MyServerService.getInstance(), query = "items", token = token)
).flow
}

View File

@ -0,0 +1,26 @@
package com.example.shawarma.data.repos
import com.example.shawarma.data.interfaces.dao.UserDao
import com.example.shawarma.data.models.UserModel
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class UserRepository @Inject constructor(
private val userDao: UserDao
) {
suspend fun insert(user: UserModel) {
return userDao.insert(user)
}
suspend fun update (user: UserModel) {
return userDao.update(user)
}
suspend fun delete (user: UserModel) {
return userDao.delete(user)
}
fun getById(id: Int): Flow<UserModel> {
return userDao.getById(id)
}
fun login(login: String, password: String): Flow<UserModel?> {
return userDao.login(login, password)
}
}

View File

@ -0,0 +1,19 @@
package com.example.shawarma.data.sharedpref
import android.content.Context
import android.content.SharedPreferences
class PreferencesManager(context: Context) {
private val sharedPreferences: SharedPreferences =
context.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)
fun saveData(key: String, value: String) {
val editor = sharedPreferences.edit()
editor.putString(key, value)
editor.apply()
}
fun getData(key: String, defaultValue: String): String {
return sharedPreferences.getString(key, defaultValue) ?: defaultValue
}
}

View File

@ -0,0 +1,82 @@
package com.example.shawarma.screens
import android.annotation.SuppressLint
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
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.shawarma.screens.authorization.AuthorizationScreen
import com.example.shawarma.screens.cart.CartScreen
import com.example.shawarma.screens.discount.DiscountScreen
import com.example.shawarma.screens.home.HomeScreen
import com.example.shawarma.screens.orders.OrdersScreen
import com.example.shawarma.screens.products.ProductScreen
import com.example.shawarma.screens.products.ProductsScreen
import com.example.shawarma.screens.registration.RegistrationScreen
import com.example.shawarma.ui.theme.MyLightYellow
import com.example.shawarma.utils.ScreenPaths
import com.example.shawarma.widgets.BottomNavBar
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun MainNavBar() {
val navController = rememberNavController()
Scaffold(
backgroundColor = MyLightYellow,
modifier = Modifier.fillMaxSize(),
bottomBar = {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
if ( currentRoute != ScreenPaths.authorization.name && currentRoute != ScreenPaths.registration.name) {
BottomNavBar(navController = navController)
}
}
) {
NavHost(navController = navController, startDestination = ScreenPaths.authorization.name) {
composable(ScreenPaths.authorization.name) {
AuthorizationScreen(navController)
}
composable(ScreenPaths.registration.name) {
RegistrationScreen(navController)
}
composable(ScreenPaths.home.name) {
HomeScreen()
}
composable(ScreenPaths.discount.name) {
DiscountScreen()
}
composable(ScreenPaths.cart.name) {
CartScreen()
}
composable(ScreenPaths.orders.name) {
OrdersScreen()
}
composable(ScreenPaths.products.name) {
ProductsScreen(navController)
}
composable(
route = ScreenPaths.product.name + "?productId={productId}",
arguments = listOf(
navArgument("productId") {
defaultValue = 0
type = NavType.IntType
}
)
) { navBackStackEntry ->
/* Extracting the id from the route */
val productId = navBackStackEntry.arguments?.getInt("productId")
ProductScreen(navController, productId)
}
}
}
}

View File

@ -0,0 +1,205 @@
package com.example.shawarma.screens.authorization
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.AlertDialog
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import com.example.shawarma.data.sharedpref.PreferencesManager
import com.example.shawarma.ui.theme.JejuFamily
import com.example.shawarma.ui.theme.MyLightRed
import com.example.shawarma.ui.theme.NunitoFamily
import com.example.shawarma.utils.ScreenPaths
import com.example.shawarma.viewmodels.UserViewModel
import com.example.shawarma.widgets.MyTextField
import com.example.shawarma.widgets.ShawarmaLogo1
@Composable
fun AuthorizationScreen(navHostController: NavHostController) {
Box(contentAlignment = Alignment.TopCenter){
ShawarmaLogo1()
AuthorizationCard(navHostController)
}
}
@Composable
fun AuthorizationCard(navHostController: NavHostController) {
val login = remember { mutableStateOf(TextFieldValue("")) }
val password = remember { mutableStateOf(TextFieldValue("")) }
val userViewModel: UserViewModel = hiltViewModel<UserViewModel>()
val preferencesManager = PreferencesManager(LocalContext.current)
if (userViewModel.token.observeAsState().value != null) {
preferencesManager.saveData("token", userViewModel.token.value.toString())
if (login.value.text == "admin") {
preferencesManager.saveData("user_role", "ADMIN")
}
else {
preferencesManager.saveData("user_role", "USER")
}
navHostController.navigate(ScreenPaths.home.name) {
popUpTo(ScreenPaths.authorization.name) {
inclusive = true
}
}
}
if (userViewModel.authorizationState.observeAsState().value == false) {
AlertDialog(
title = {
Text(
text = "Ошибка входа в аккаунт",
fontFamily = NunitoFamily,
fontWeight = FontWeight.Bold,
fontSize = 20.sp
)
},
text = {
Text(
text = "Проверьте корректность введенных данных",
fontFamily = NunitoFamily,
fontWeight = FontWeight.Normal,
fontSize = 16.sp
)
},
onDismissRequest = {
userViewModel.calmAuthorizationState()
},
buttons = {
TextButton(
onClick = {
userViewModel.calmAuthorizationState()
}
) {
Text("ОК")
}
}
)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.zIndex(2f)
.verticalScroll(rememberScrollState())
.imePadding()
.padding(10.dp)
.fillMaxHeight()
) {
Card(
shape = RoundedCornerShape(20.dp),
modifier = Modifier
.size(275.dp, 290.dp + 72.dp)
.padding(top = 72.dp)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Авторизация",
fontSize = 20.sp,
modifier = Modifier.padding(
top = 20.dp
),
style = TextStyle(
fontFamily = JejuFamily
)
)
MyTextField(
text = login,
onTextChanged = {login.value = it},
modifier = Modifier
.padding(
top = (20).dp
)
.size(208.dp, (50).dp),
placeholder = "Логин",
singleLine = true
)
MyTextField(
text = password,
onTextChanged = {password.value = it},
modifier = Modifier
.padding(
top = (20).dp
)
.size(208.dp, (50).dp),
placeholder = "Пароль",
singleLine = true,
visualTransformation = PasswordVisualTransformation('*')
)
Button(
onClick = {
userViewModel.login(login.value.text, password.value.text)
},
colors = ButtonDefaults.buttonColors(MyLightRed, Color.White),
shape = RoundedCornerShape(20.dp),
modifier = Modifier
.padding(
top = (20).dp
)
.size(208.dp, (50).dp)
) {
Text(
text = "Войти",
style = TextStyle(
fontFamily = JejuFamily,
fontSize = 16.sp
)
)
}
Button(
onClick = {
navHostController.navigate(ScreenPaths.registration.name) {
popUpTo(ScreenPaths.registration.name) {
inclusive = true
}
}
},
colors = ButtonDefaults.buttonColors(Color.White),
elevation = ButtonDefaults.elevation(0.dp)
) {
Text(
text = "У меня нет аккаунта!",
textDecoration = TextDecoration.Underline,
style = TextStyle(
fontFamily = JejuFamily,
fontSize = 12.sp
)
)
}
}
}
}
}

View File

@ -0,0 +1,342 @@
package com.example.shawarma.screens.cart
import androidx.compose.foundation.BorderStroke
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.fillMaxHeight
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.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.shawarma.data.models.OrderWithProducts
import com.example.shawarma.data.sharedpref.PreferencesManager
import com.example.shawarma.ui.theme.MarckFamily
import com.example.shawarma.ui.theme.MyLightYellow
import com.example.shawarma.ui.theme.MyMainBackground
import com.example.shawarma.ui.theme.MyOrange
import com.example.shawarma.ui.theme.NunitoFamily
import com.example.shawarma.viewmodels.CartViewModel
import com.example.shawarma.widgets.ShawarmaLogo2
@Composable
fun CartScreen() {
Box(
contentAlignment = Alignment.TopCenter
) {
CartWidget()
ShawarmaLogo2()
}
}
@Composable
fun CartWidget(){
val preferencesManager = PreferencesManager(LocalContext.current)
val searchToken = preferencesManager.getData("token", "")
val cartViewModel: CartViewModel = hiltViewModel<CartViewModel>()
cartViewModel.getOrders(searchToken)
var unpaidOrder: OrderWithProducts? = cartViewModel.unpaidOrder.observeAsState().value
val paidOrders = cartViewModel.getPaidList(searchToken).collectAsLazyPagingItems()
Box(
modifier = Modifier
.clip(shape = RoundedCornerShape(30.dp))
.padding(top = 100.dp)
.fillMaxSize()
.background(color = MyMainBackground)
.zIndex(2f),
contentAlignment = Alignment.TopCenter
) {
Text(
text = "Корзина",
fontFamily = MarckFamily,
fontSize = 40.sp,
modifier = Modifier.padding(top = 15.dp)
)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.padding(top = 55.dp)
.verticalScroll(rememberScrollState())
) {
Text(
text = "Оплачено:",
fontFamily = NunitoFamily,
fontSize = 20.sp,
modifier = Modifier.padding(top = 15.dp),
fontWeight = FontWeight.Bold
)
LazyColumn(
modifier = Modifier
.width(340.dp)
.height(200.dp)
) {
if (paidOrders != null) {
items(paidOrders.itemCount) { index ->
PaidItem(paidOrders[index]!!)
}
}
}
Text(
text = "Ожидает оплаты:",
fontFamily = NunitoFamily,
fontSize = 20.sp,
modifier = Modifier.padding(top = 15.dp),
fontWeight = FontWeight.Bold
)
if (unpaidOrder != null) {
CartItem(order = unpaidOrder)
}
Spacer(modifier = Modifier.height(20.dp))
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = Color(0xFF91FF87)
),
shape = RoundedCornerShape(20.dp),
border = BorderStroke(2.dp, Color(0x66000000)),
modifier = Modifier.size(240.dp, 60.dp),
onClick = {
if (unpaidOrder != null) {
cartViewModel.payForOrder(searchToken, unpaidOrder)
}
}
) {
Text(
"Оплатить",
fontSize = 20.sp,
fontFamily = NunitoFamily,
fontWeight = FontWeight(700),
)
}
Spacer(modifier = Modifier.height(70.dp))
}
}
}
@Composable
fun PaidItem(order : OrderWithProducts) {
Card(
border = BorderStroke(width = 2.dp, color = MyOrange),
shape = RoundedCornerShape(size = 20.dp),
backgroundColor = Color.White,
modifier = Modifier.size(340.dp, 150.dp)
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
.padding(start = 20.dp, end = 20.dp)
){
Text(
text = "Статус: ",
fontFamily = NunitoFamily,
fontSize = 20.sp,
modifier = Modifier.padding(top = 15.dp),
fontWeight = FontWeight.Bold,
color = Color.Gray
)
Text(
text = order.order.status,
fontFamily = NunitoFamily,
fontSize = 20.sp,
modifier = Modifier.padding(top = 15.dp),
fontWeight = FontWeight.Bold,
color = Color.Gray
)
}
LazyColumn(
modifier = Modifier.padding(top = 40.dp)
) {
items(order.orderWithProducts.size) { index ->
if (order.orderWithProducts[index].product != null) {
if (order.orderWithProducts.isNotEmpty()) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
) {
Column(
modifier = Modifier.fillMaxWidth(0.5f)
) {
Text(
text = order.orderWithProducts[index].product!!.title,
fontFamily = NunitoFamily,
fontSize = 20.sp,
modifier = Modifier.padding(top = 15.dp),
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
Text(
text = "x" + order.orderWithProducts[index].orderProductModel.quantity,
fontFamily = NunitoFamily,
fontSize = 20.sp,
modifier = Modifier.padding(top = 15.dp),
fontWeight = FontWeight.Bold
)
Text(
text = (order.orderWithProducts[index].orderProductModel.quantity * order.orderWithProducts[index].product!!.price).toString() + " руб.",
fontFamily = NunitoFamily,
fontSize = 20.sp,
modifier = Modifier.padding(top = 15.dp),
fontWeight = FontWeight.Bold
)
}
}
}
}
}
}
Spacer(modifier = Modifier.height(20.dp))
}
@Composable
fun CartItem(order : OrderWithProducts) {
val cartViewModel: CartViewModel = hiltViewModel<CartViewModel>()
val preferencesManager = PreferencesManager(LocalContext.current)
val searchToken = preferencesManager.getData("token", "")
Card(
border = BorderStroke(width = 2.dp, color = MyOrange),
shape = RoundedCornerShape(size = 20.dp),
backgroundColor = Color.White,
modifier = Modifier.size(340.dp, 180.dp)
) {
LazyColumn (
horizontalAlignment = Alignment.CenterHorizontally
) {
items(order.orderWithProducts.size) {index ->
if (order.orderWithProducts[index].product != null) {
var count = remember { mutableStateOf(0)}
count.value = order.orderWithProducts[index].orderProductModel.quantity
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.padding(20.dp)
.size(340.dp, 80.dp)
) {
Column(
modifier = Modifier.fillMaxWidth()
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.fillMaxWidth(0.5f)
) {
Text(
text = order.orderWithProducts[index].product!!.title,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
Text(
text = (order.orderWithProducts[index].orderProductModel.quantity * order.orderWithProducts[index].product!!.price).toString() + " руб.",
fontFamily = NunitoFamily,
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
}
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
) {
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = MyLightYellow
),
shape = RoundedCornerShape(size = 20.dp),
modifier = Modifier
.fillMaxHeight()
.weight(1f)
.fillMaxSize(0.5f),
onClick = {
cartViewModel.removeProductFromOrder(searchToken, order, index)
count.value -= 1
}
) {
Text(
text = "-",
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
}
Spacer(modifier = Modifier.fillMaxWidth(0.2f))
Text(
text = "x" + count.value + " ",
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.fillMaxWidth(0.2f))
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = MyLightYellow
),
shape = RoundedCornerShape(size = 20.dp),
modifier = Modifier
.fillMaxHeight()
.weight(1f)
.fillMaxSize(0.5f),
onClick = {
cartViewModel.addProductToOrder(searchToken, order, index)
count.value += 1
}
) {
Text(
text = "+",
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
}
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,203 @@
package com.example.shawarma.screens.discount
import androidx.compose.foundation.BorderStroke
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.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.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.shawarma.R
import com.example.shawarma.data.models.ProductModel
import com.example.shawarma.data.sharedpref.PreferencesManager
import com.example.shawarma.ui.theme.MarckFamily
import com.example.shawarma.ui.theme.MyLightYellow
import com.example.shawarma.ui.theme.MyMainBackground
import com.example.shawarma.ui.theme.MyOrange
import com.example.shawarma.ui.theme.MyPriceBackground
import com.example.shawarma.ui.theme.NunitoFamily
import com.example.shawarma.viewmodels.HomeViewModel
import com.example.shawarma.widgets.ShawarmaLogo2
@Composable
fun DiscountScreen() {
Box(
contentAlignment = Alignment.TopCenter
) {
DiscountList()
ShawarmaLogo2()
}
}
@Composable
fun DiscountList(){
val preferencesManager = PreferencesManager(LocalContext.current)
val searchToken = preferencesManager.getData("token", "")
val homeViewModel: HomeViewModel = hiltViewModel<HomeViewModel>()
val productsListUiState = homeViewModel.getDiscountList(searchToken).collectAsLazyPagingItems()
Box(
modifier = Modifier
.clip(shape = RoundedCornerShape(30.dp))
.padding(top = 100.dp)
.fillMaxSize()
.background(color = MyMainBackground)
.zIndex(2f),
contentAlignment = Alignment.TopCenter
){
Text(
text = "Акции",
fontFamily = MarckFamily,
fontSize = 40.sp,
modifier = Modifier.padding(top = 15.dp)
)
LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(top = 80.dp)
)
{
items(productsListUiState.itemCount) { index ->
if (index % 2 == 0 && index == productsListUiState.itemCount - 1) {
Row(
horizontalArrangement = Arrangement.SpaceAround,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)
) {
DiscountCard(productsListUiState[index]!!)
}
} else {
if (index % 2 != 1) {
Row(
horizontalArrangement = Arrangement.SpaceAround,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)
) {
DiscountCard(productsListUiState[index]!!)
DiscountCard(productsListUiState[index+1]!!)
}
}
}
if (index == productsListUiState.itemCount - 1) {
Spacer(modifier = Modifier.height(70.dp))
}
}
}
}
}
@Composable
fun DiscountCard(product : ProductModel){
val homeViewModel: HomeViewModel = hiltViewModel<HomeViewModel>()
val preferencesManager = PreferencesManager(LocalContext.current)
Card(
shape = RoundedCornerShape(20.dp),
backgroundColor = Color.White,
border = BorderStroke(2.dp, MyOrange),
modifier = Modifier
.size(160.dp)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = product.title,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(top = 10.dp),
maxLines = 1,
softWrap = true,
overflow = TextOverflow.Ellipsis
)
Image(
painter = painterResource(id = R.drawable.shawarma2),
contentDescription = "Shawarma",
Modifier.size(135.dp, 70.dp)
)
Spacer(modifier = Modifier.height(16.dp))
Card(
shape = RoundedCornerShape(20.dp),
backgroundColor = MyPriceBackground,
border = BorderStroke(2.dp, MyOrange),
modifier = Modifier
.size(160.dp, 36.dp)
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween
){
Box(
modifier = Modifier.padding(start = 12.dp)
) {
Text(
text = product.oldPrice.toString() + "руб. ",
fontFamily = NunitoFamily,
fontSize = 10.sp,
fontWeight = FontWeight.Bold,
textDecoration = TextDecoration.LineThrough
)
Text(
text = product.price.toString() + "руб. ",
fontFamily = NunitoFamily,
fontSize = 16.sp,
fontWeight = FontWeight.ExtraBold,
color = Color.Red,
modifier = Modifier.padding(top = 8.dp)
)
}
Button(
onClick = {
product.id?.let { homeViewModel.addProductToCart(it, preferencesManager.getData("token", "null")) }
},
colors = ButtonDefaults.buttonColors(
backgroundColor = MyLightYellow,
contentColor = Color.Black
),
shape = RoundedCornerShape(20.dp),
) {
Text(
text = "Купить",
fontSize = 14.sp,
fontWeight = FontWeight.ExtraBold,
fontFamily = NunitoFamily,
)
}
}
}
}
}
}

View File

@ -0,0 +1,193 @@
package com.example.shawarma.screens.home
import androidx.compose.foundation.BorderStroke
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.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.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.shawarma.R
import com.example.shawarma.data.models.ProductModel
import com.example.shawarma.data.sharedpref.PreferencesManager
import com.example.shawarma.ui.theme.MarckFamily
import com.example.shawarma.ui.theme.MyLightYellow
import com.example.shawarma.ui.theme.MyMainBackground
import com.example.shawarma.ui.theme.MyOrange
import com.example.shawarma.ui.theme.MyPriceBackground
import com.example.shawarma.ui.theme.NunitoFamily
import com.example.shawarma.viewmodels.HomeViewModel
import com.example.shawarma.widgets.ShawarmaLogo2
@Composable
fun HomeScreen() {
Box(
contentAlignment = Alignment.TopCenter
) {
HomeList()
ShawarmaLogo2()
}
}
@Composable
fun HomeList(){
val preferencesManager = PreferencesManager(LocalContext.current)
val searchToken = preferencesManager.getData("token", "")
val homeViewModel: HomeViewModel = hiltViewModel<HomeViewModel>()
val productsListUiState = homeViewModel.getProductList(searchToken).collectAsLazyPagingItems()
Box(
modifier = Modifier
.clip(shape = RoundedCornerShape(30.dp))
.padding(top = 100.dp)
.fillMaxSize()
.background(color = MyMainBackground)
.zIndex(2f),
contentAlignment = Alignment.TopCenter
){
Text(
text = "Шавармашка",
fontFamily = MarckFamily,
fontSize = 40.sp,
modifier = Modifier.padding(top = 15.dp)
)
LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(top = 80.dp)
)
{
items(
count = productsListUiState.itemCount,
key = productsListUiState.itemKey()
) { index ->
if (index % 2 == 0 && index == productsListUiState.itemCount - 1) {
Row(
horizontalArrangement = Arrangement.SpaceAround,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)
) {
ProductCard(productsListUiState[index]!!)
}
} else {
if (index % 2 != 1) {
Row(
horizontalArrangement = Arrangement.SpaceAround,
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp)
) {
ProductCard(productsListUiState[index]!!)
ProductCard(productsListUiState[index + 1]!!)
}
}
}
if (index == productsListUiState.itemCount - 1) {
Spacer(modifier = Modifier.height(70.dp))
}
}
}
}
}
@Composable
fun ProductCard(product: ProductModel){
val homeViewModel: HomeViewModel = hiltViewModel<HomeViewModel>()
val preferencesManager = PreferencesManager(LocalContext.current)
Card(
shape = RoundedCornerShape(20.dp),
backgroundColor = Color.White,
border = BorderStroke(2.dp, MyOrange),
modifier = Modifier
.size(160.dp)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = product.title,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(top = 10.dp),
maxLines = 1,
softWrap = true,
overflow = TextOverflow.Ellipsis
)
Image(
painter = painterResource(id = R.drawable.shawarma2),
contentDescription = "Shawarma",
Modifier.size(135.dp, 70.dp)
)
Spacer(modifier = Modifier.height(16.dp))
Card(
shape = RoundedCornerShape(20.dp),
backgroundColor = MyPriceBackground,
border = BorderStroke(2.dp, MyOrange),
modifier = Modifier
.size(160.dp, 36.dp)
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween
){
Text(
text = product.price.toString() + " руб.",
fontFamily = NunitoFamily,
fontSize = 16.sp,
fontWeight = FontWeight.ExtraBold,
modifier = Modifier.padding(start = 12.dp, top = 6.dp)
)
Button(
onClick = {
product.id?.let { homeViewModel.addProductToCart(it, preferencesManager.getData("token", "null")) }
},
colors = ButtonDefaults.buttonColors(
backgroundColor = MyLightYellow,
contentColor = Color.Black
),
shape = RoundedCornerShape(20.dp),
) {
Text(
text = "Купить",
fontSize = 14.sp,
fontWeight = FontWeight.ExtraBold,
fontFamily = NunitoFamily,
)
}
}
}
}
}
}

View File

@ -0,0 +1,436 @@
package com.example.shawarma.screens.orders
import androidx.compose.foundation.BorderStroke
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.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.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.compose.collectAsLazyPagingItems
import com.example.shawarma.R
import com.example.shawarma.data.models.OrderStatus
import com.example.shawarma.data.models.OrderWithProducts
import com.example.shawarma.data.sharedpref.PreferencesManager
import com.example.shawarma.ui.theme.MarckFamily
import com.example.shawarma.ui.theme.MyLightRed
import com.example.shawarma.ui.theme.MyLightYellow
import com.example.shawarma.ui.theme.MyMainBackground
import com.example.shawarma.ui.theme.MyOrange
import com.example.shawarma.ui.theme.NunitoFamily
import com.example.shawarma.viewmodels.OrdersViewModel
import com.example.shawarma.widgets.ShawarmaLogo2
@Composable
fun OrdersScreen() {
Box(
contentAlignment = Alignment.Center
) {
ShawarmaLogo2()
OrdersList()
}
}
@Composable
fun OrdersList(){
val ordersViewModel = hiltViewModel<OrdersViewModel>()
val preferencesManager = PreferencesManager(LocalContext.current)
val searchToken = preferencesManager.getData("token", "")
val preparingOrders = ordersViewModel.getAllPaidList(searchToken).collectAsLazyPagingItems()
val preparedOrders = ordersViewModel.getAllReadyList(searchToken).collectAsLazyPagingItems()
val processedOrders = ordersViewModel.getAllServedList(searchToken).collectAsLazyPagingItems()
Box(
modifier = Modifier
.clip(shape = RoundedCornerShape(30.dp))
.padding(top = 100.dp)
.fillMaxSize()
.background(color = MyMainBackground)
.zIndex(2f),
contentAlignment = Alignment.TopCenter
) {
Text(
text = "Заказы",
fontFamily = MarckFamily,
fontSize = 40.sp,
modifier = Modifier.padding(top = 15.dp)
)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.padding(top = 55.dp)
.verticalScroll(rememberScrollState())
){
Text(
text = "Готовится:",
fontFamily = NunitoFamily,
fontSize = 20.sp,
modifier = Modifier.padding(top = 15.dp),
fontWeight = FontWeight.Bold
)
LazyColumn(
modifier = Modifier
.width(340.dp)
.height(250.dp)
) {
if (preparingOrders != null) {
if (preparingOrders.itemCount > 0) {
items(preparingOrders.itemCount) { index ->
PreparingItem(preparingOrders[index]!!)
}
}
}
}
Text(
text = "Готово:",
fontFamily = NunitoFamily,
fontSize = 20.sp,
modifier = Modifier.padding(top = 15.dp),
fontWeight = FontWeight.Bold
)
LazyColumn(
modifier = Modifier
.width(340.dp)
.height(250.dp)
) {
if (preparedOrders != null) {
if (preparedOrders.itemCount > 0) {
items(preparedOrders.itemCount) { index ->
PreparedItem(preparedOrders[index]!!)
}
}
}
}
Text(
text = "Выдано:",
fontFamily = NunitoFamily,
fontSize = 20.sp,
modifier = Modifier.padding(top = 15.dp),
fontWeight = FontWeight.Bold
)
LazyColumn(
modifier = Modifier
.width(340.dp)
.height(250.dp)
) {
if (processedOrders != null) {
if (processedOrders.itemCount > 0) {
items(processedOrders.itemCount) {index ->
ProcessedItem(processedOrders[index]!!)
}
}
}
}
Spacer(modifier = Modifier.height(70.dp))
}
}
}
@Composable
fun PreparingItem(order : OrderWithProducts){
val ordersViewModel = hiltViewModel<OrdersViewModel>()
val preferencesManager = PreferencesManager(LocalContext.current)
val searchToken = preferencesManager.getData("token", "")
Card(
border = BorderStroke(width = 2.dp, color = MyOrange),
shape = RoundedCornerShape(size = 20.dp),
backgroundColor = Color.White,
modifier = Modifier.size(340.dp, 200.dp)
){
Column(
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.padding(20.dp)
.size(340.dp, 60.dp)
){
Column(
modifier = Modifier.fillMaxWidth(0.5f)
){
Text(
text = order.order.date,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = MyLightYellow
),
shape = RoundedCornerShape(size = 10.dp),
modifier = Modifier
.size(170.dp, 80.dp)
.fillMaxSize(),
onClick = {
ordersViewModel.changeOrderStatus(searchToken, order, OrderStatus.Готово.name)
}
) {
Text(
text = "Готово!",
fontFamily = NunitoFamily,
fontSize = 14.sp,
fontWeight = FontWeight.Bold
)
}
}
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
){
items(order.orderWithProducts.size) {index ->
if (order.orderWithProducts[index].product != null) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = order.orderWithProducts[index].product!!.title,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
Text(
text = "x" + order.orderWithProducts[index].orderProductModel.quantity,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
}
}
}
}
}
Spacer(modifier = Modifier.height(20.dp))
}
@Composable
fun PreparedItem(order : OrderWithProducts){
val ordersViewModel = hiltViewModel<OrdersViewModel>()
val preferencesManager = PreferencesManager(LocalContext.current)
val searchToken = preferencesManager.getData("token", "")
Card(
border = BorderStroke(width = 2.dp, color = MyOrange),
shape = RoundedCornerShape(size = 20.dp),
backgroundColor = Color.White,
modifier = Modifier.size(340.dp, 200.dp)
){
Column(
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.padding(20.dp)
.size(340.dp, 60.dp)
){
Column(
modifier = Modifier.fillMaxWidth(0.5f)
){
Text(
text = order.order.date,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = MyLightYellow
),
shape = RoundedCornerShape(size = 10.dp),
modifier = Modifier
.size(170.dp, 80.dp)
.fillMaxSize(),
onClick = {
ordersViewModel.changeOrderStatus(searchToken, order, OrderStatus.Выдано.name)
}
) {
Text(
text = "Выдано!",
fontFamily = NunitoFamily,
fontSize = 14.sp,
fontWeight = FontWeight.Bold
)
}
}
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
){
items(order.orderWithProducts.size) {index ->
if (order.orderWithProducts[index].product != null) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = order.orderWithProducts[index].product!!.title,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
Text(
text = "x" + order.orderWithProducts[index].orderProductModel.quantity,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
}
}
}
}
}
Spacer(modifier = Modifier.height(20.dp))
}
@Composable
fun ProcessedItem(order : OrderWithProducts){
val ordersViewModel = hiltViewModel<OrdersViewModel>()
val preferencesManager = PreferencesManager(LocalContext.current)
val searchToken = preferencesManager.getData("token", "")
Card(
border = BorderStroke(width = 2.dp, color = MyOrange),
shape = RoundedCornerShape(size = 20.dp),
backgroundColor = Color.White,
modifier = Modifier.size(340.dp, 200.dp)
){
Column(
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.padding(20.dp)
.size(340.dp, 60.dp)
){
Column(
modifier = Modifier.fillMaxWidth(0.3f)
){
Text(
text = order.order.date,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
Column(
modifier = Modifier.fillMaxWidth(0.3f)
){
Text(
text = order.order.date.toString(),
fontFamily = NunitoFamily,
fontSize = 16.sp,
fontWeight = FontWeight.Bold
)
}
Button(
modifier = Modifier
.size(80.dp)
,
colors = ButtonDefaults.buttonColors(MyLightRed),
shape = RoundedCornerShape(20.dp),
onClick = {
ordersViewModel.deleteOrder(searchToken, order)
}
) {
Icon(
painter = painterResource(id = R.drawable.trash),
contentDescription = "trash",
modifier = Modifier.size(80.dp)
)
}
}
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
){
items(order.orderWithProducts.size) {index ->
if (order.orderWithProducts[index].product != null) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = order.orderWithProducts[index].product!!.title,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
Text(
text = "x" + order.orderWithProducts[index].orderProductModel.quantity,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
}
}
}
}
}
Spacer(modifier = Modifier.height(20.dp))
}

View File

@ -0,0 +1,165 @@
package com.example.shawarma.screens.products
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
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.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import com.example.shawarma.data.sharedpref.PreferencesManager
import com.example.shawarma.ui.theme.MarckFamily
import com.example.shawarma.ui.theme.MyLightYellow
import com.example.shawarma.ui.theme.MyMainBackground
import com.example.shawarma.ui.theme.MyOrange
import com.example.shawarma.ui.theme.NunitoFamily
import com.example.shawarma.utils.ScreenPaths
import com.example.shawarma.viewmodels.ProductViewModel
import com.example.shawarma.widgets.MyTextField
import com.example.shawarma.widgets.ShawarmaLogo2
@Composable
fun ProductScreen(navHostController: NavHostController, productId: Int?) {
Box(
contentAlignment = Alignment.TopCenter
) {
ProductWidget(navHostController, productId)
ShawarmaLogo2()
}
}
@Composable
fun ProductWidget(navHostController: NavHostController, productId: Int?) {
val preferencesManager = PreferencesManager(LocalContext.current)
val searchToken = preferencesManager.getData("token", "")
val title = remember { mutableStateOf(TextFieldValue(""))}
val price = remember { mutableStateOf(TextFieldValue(""))}
val oldPrice = remember { mutableStateOf(TextFieldValue(""))}
val productViewModel: ProductViewModel = hiltViewModel<ProductViewModel>()
val product = productViewModel.product.observeAsState().value
if (productViewModel.addingProductState.observeAsState().value == true) {
navHostController.navigate(ScreenPaths.products.name) {
popUpTo(ScreenPaths.product.name) {
inclusive = true
}
}
}
if (productId != null) {
productViewModel.getProduct(productId)
}
if (product != null) {
title.value = TextFieldValue(text = product.title)
price.value = TextFieldValue(text = product.price.toString())
if (product.oldPrice != null) {
oldPrice.value = TextFieldValue(text = product.oldPrice.toString())
}
}
Box(
modifier = Modifier
.clip(shape = RoundedCornerShape(30.dp))
.padding(top = 100.dp)
.fillMaxSize()
.background(color = MyMainBackground)
.zIndex(2f),
contentAlignment = Alignment.TopCenter
){
Text(
text = "Товар",
fontFamily = MarckFamily,
fontSize = 40.sp,
modifier = Modifier.padding(top = 15.dp)
)
Column(
modifier = Modifier
.padding(top = 60.dp)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
MyTextField(
text = title,
onTextChanged = {title.value = it},
modifier = Modifier
.padding(
top = (20).dp
)
.size(300.dp, (60).dp),
placeholder = "Наименование",
singleLine = true
)
MyTextField(
text = price,
onTextChanged = {price.value = it},
modifier = Modifier
.padding(
top = (20).dp
)
.size(300.dp, (60).dp),
placeholder = "Цена",
singleLine = true
)
MyTextField(
text = oldPrice,
onTextChanged = {oldPrice.value = it},
modifier = Modifier
.padding(
top = (20).dp
)
.size(300.dp, (60).dp),
placeholder = "Старая цена",
singleLine = true
)
Button(
modifier = Modifier
.padding(top = 80.dp)
.size(300.dp, 50.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = MyLightYellow
),
border = BorderStroke(2.dp, color = MyOrange),
shape = RoundedCornerShape(20.dp),
onClick = {
if (product == null)
productViewModel.addProduct(title.value.text, price.value.text.toInt(), if (!oldPrice.value.text.isNullOrEmpty()) oldPrice.value.text.toInt() else null, searchToken)
else
productViewModel.updateProduct(title.value.text, price.value.text.toInt(), if (!oldPrice.value.text.isNullOrEmpty()) oldPrice.value.text.toInt() else null, searchToken)
}
) {
Text(
text = if (product != null) "Изменить" else "Добавить",
fontFamily = NunitoFamily,
fontSize = 24.sp,
fontWeight = FontWeight.Bold
)
}
}
}
}

View File

@ -0,0 +1,207 @@
package com.example.shawarma.screens.products
import androidx.compose.foundation.BorderStroke
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.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.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey
import com.example.shawarma.R
import com.example.shawarma.data.models.ProductModel
import com.example.shawarma.data.sharedpref.PreferencesManager
import com.example.shawarma.ui.theme.MarckFamily
import com.example.shawarma.ui.theme.MyLightRed
import com.example.shawarma.ui.theme.MyLightYellow
import com.example.shawarma.ui.theme.MyMainBackground
import com.example.shawarma.ui.theme.MyOrange
import com.example.shawarma.ui.theme.NunitoFamily
import com.example.shawarma.utils.ScreenPaths
import com.example.shawarma.viewmodels.ProductsViewModel
import com.example.shawarma.widgets.ShawarmaLogo2
@Composable
fun ProductsScreen(navHostController: NavHostController) {
val productsViewModel: ProductsViewModel = hiltViewModel<ProductsViewModel>()
Box(
contentAlignment = Alignment.TopCenter
) {
ProductsList(navHostController, productsViewModel)
ShawarmaLogo2()
}
}
@Composable
fun ProductsList(navHostController: NavHostController, productsViewModel: ProductsViewModel){
val preferencesManager = PreferencesManager(LocalContext.current)
val searchToken = preferencesManager.getData("token", "")
val products = productsViewModel.getItemsList(searchToken).collectAsLazyPagingItems()
Box(
modifier = Modifier
.clip(shape = RoundedCornerShape(30.dp))
.padding(top = 100.dp)
.fillMaxSize()
.background(color = MyMainBackground)
.zIndex(2f),
contentAlignment = Alignment.TopCenter
){
Text(
text = "Товары",
fontFamily = MarckFamily,
fontSize = 40.sp,
modifier = Modifier.padding(top = 15.dp)
)
Button(
modifier = Modifier
.padding(top = 80.dp)
.size(340.dp, 60.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = MyLightYellow
),
border = BorderStroke(2.dp, color = MyOrange),
shape = RoundedCornerShape(20.dp),
onClick = {
navHostController.navigate(ScreenPaths.product.name)
}
) {
Text(
text = "Добавить товар",
fontFamily = NunitoFamily,
fontSize = 24.sp,
fontWeight = FontWeight.Bold
)
}
LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(top = 160.dp)
)
{
items(
products.itemCount,
key = products.itemKey()
) { index ->
ProductItem(products[index]!!, navHostController, searchToken, productsViewModel)
Spacer(modifier = Modifier.height(20.dp))
if (index == products.itemCount - 1) {
Spacer(modifier = Modifier.height(70.dp))
}
}
}
}
}
@Composable
fun ProductItem(product: ProductModel, navHostController: NavHostController, token: String, productsViewModel: ProductsViewModel){
Card(
border = BorderStroke(width = 2.dp, color = MyOrange),
shape = RoundedCornerShape(size = 20.dp),
backgroundColor = Color.White,
modifier = Modifier.size(340.dp, 100.dp)
) {
Row(
modifier = Modifier
.padding(20.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceAround
) {
Column(
modifier = Modifier.fillMaxWidth(0.5f)
) {
Text(
text = product.title,
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
if (product.oldPrice != null) {
Text(
text = product.price.toString() + " руб.",
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = Color.Red
)
}
else {
Text(
text = product.price.toString() + " руб.",
fontFamily = NunitoFamily,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
}
Button(
modifier = Modifier.size(60.dp),
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = MyLightYellow
),
onClick = {
navHostController.navigate(
route = ScreenPaths.product.name + "?productId=" + product.id.toString()
)
}
) {
Icon(
painter = painterResource(id = R.drawable.pen_icon),
contentDescription = "pen",
modifier = Modifier.fillMaxSize()
)
}
Button(
modifier = Modifier.size(60.dp),
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = MyLightRed
),
onClick = {
productsViewModel.deleteProduct(product, token)
}
) {
Icon(
painter = painterResource(id = R.drawable.trash),
contentDescription = "trash",
modifier = Modifier.fillMaxSize()
)
}
}
}
}

View File

@ -0,0 +1,207 @@
package com.example.shawarma.screens.registration
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.AlertDialog
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import com.example.shawarma.ui.theme.JejuFamily
import com.example.shawarma.ui.theme.MyLightRed
import com.example.shawarma.ui.theme.NunitoFamily
import com.example.shawarma.utils.ScreenPaths
import com.example.shawarma.viewmodels.UserViewModel
import com.example.shawarma.widgets.MyTextField
import com.example.shawarma.widgets.ShawarmaLogo1
@Composable
fun RegistrationScreen(navHostController: NavHostController) {
Box(contentAlignment = Alignment.TopCenter){
ShawarmaLogo1()
RegistrationCard(navHostController)
}
}
@Composable
fun RegistrationCard(navHostController: NavHostController){
val login = remember { mutableStateOf(TextFieldValue("")) }
val password = remember { mutableStateOf(TextFieldValue("")) }
val passwordRepeat = remember { mutableStateOf(TextFieldValue("")) }
val userViewModel: UserViewModel = hiltViewModel<UserViewModel>()
if (userViewModel.registrationState.observeAsState().value == true) {
navHostController.navigate(ScreenPaths.authorization.name) {
popUpTo(ScreenPaths.authorization.name) {
inclusive = true
}
}
}
if (userViewModel.registrationState.observeAsState().value == false) {
AlertDialog(
title = {
Text(
text = "Ошибка регистрации",
fontFamily = NunitoFamily,
fontWeight = FontWeight.Bold,
fontSize = 20.sp
)
},
text = {
Text(
text = "Проверьте корректность введенных данных",
fontFamily = NunitoFamily,
fontWeight = FontWeight.Normal,
fontSize = 16.sp
)
},
onDismissRequest = {
userViewModel.calmRegistrationState()
},
buttons = {
TextButton(
onClick = {
userViewModel.calmRegistrationState()
}
) {
Text("ОК")
}
}
)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.zIndex(2f)
.verticalScroll(rememberScrollState())
.imePadding()
.padding(10.dp)
.fillMaxHeight()
) {
Card(
shape = RoundedCornerShape(20.dp),
modifier = Modifier
.size(275.dp, 380.dp + 72.dp)
.padding(top = 72.dp)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Регистрация",
fontSize = 20.sp,
modifier = Modifier.padding(
top = 20.dp
),
style = TextStyle(
fontFamily = JejuFamily
)
)
MyTextField(
text = login,
onTextChanged = {login.value = it},
modifier = Modifier
.padding(
top = (20).dp
)
.size(208.dp, (50).dp),
placeholder = "Логин",
singleLine = true
)
MyTextField(
text = password,
onTextChanged = {password.value = it},
modifier = Modifier
.padding(
top = (20).dp
)
.size(208.dp, (50).dp),
placeholder = "Пароль",
singleLine = true,
visualTransformation = PasswordVisualTransformation('*')
)
MyTextField(
text = passwordRepeat,
onTextChanged = {passwordRepeat.value = it},
modifier = Modifier
.padding(
top = (20).dp
)
.size(208.dp, (50).dp),
placeholder = "Повторите пароль",
singleLine = true,
visualTransformation = PasswordVisualTransformation('*')
)
Button(
onClick = {
userViewModel.register(login.value.text, password.value.text, passwordRepeat.value.text)
},
colors = ButtonDefaults.buttonColors(MyLightRed, Color.White),
shape = RoundedCornerShape(20.dp),
modifier = Modifier
.padding(
top = (20).dp
)
.size(208.dp, (50).dp)
) {
Text(
text = "Зарегистрироваться",
style = TextStyle(
fontFamily = JejuFamily,
fontSize = 16.sp
)
)
}
Button(
onClick = {
navHostController.navigate(ScreenPaths.authorization.name) {
popUpTo(ScreenPaths.authorization.name) {
inclusive = true
}
}
},
colors = ButtonDefaults.buttonColors(Color.White),
elevation = ButtonDefaults.elevation(0.dp)
) {
Text(
text = "У меня уже есть аккаунт!",
textDecoration = TextDecoration.Underline,
style = TextStyle(
fontFamily = JejuFamily,
fontSize = 12.sp
)
)
}
}
}
}
}

View File

@ -0,0 +1,10 @@
package com.example.shawarma.ui.theme
import androidx.compose.ui.graphics.Color
val MyLightYellow = Color(255,225,120,255)
val MyLightRed = Color(255,100,100,255)
val MyTextFieldBackground = Color(232,232,232,255)
val MyPriceBackground = Color(0xFFE8E8E8)
val MyMainBackground = Color(0x80FFFFFF)
val MyOrange = Color(0xFFFF9600)

View File

@ -0,0 +1,11 @@
package com.example.shawarma.ui.theme
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Shapes
import androidx.compose.ui.unit.dp
val Shapes = Shapes(
small = RoundedCornerShape(4.dp),
medium = RoundedCornerShape(4.dp),
large = RoundedCornerShape(0.dp)
)

View File

@ -0,0 +1,38 @@
package com.example.shawarma.ui.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.MaterialTheme
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.runtime.Composable
private val DarkColorPalette = darkColors(
)
private val LightColorPalette = lightColors(
/* Other default colors to override
background = Color.White,
surface = Color.White,
onPrimary = Color.White,
onSecondary = Color.Black,
onBackground = Color.Black,
onSurface = Color.Black,
*/
)
@Composable
fun ShawarmaTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
}

View File

@ -0,0 +1,41 @@
package com.example.shawarma.ui.theme
import androidx.compose.material.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.example.shawarma.R
// Set of Material typography styles to start with
val Typography = Typography(
body1 = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp
)
/* Other default text styles to override
button = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.W500,
fontSize = 14.sp
),
caption = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 12.sp
)
*/
)
val JejuFamily = FontFamily(
Font(R.font.jejugothic_regular, FontWeight.Normal)
)
val MarckFamily = FontFamily(
Font(R.font.marckscript_regular, FontWeight.Normal)
)
val NunitoFamily = FontFamily(
Font(R.font.nunito_wght, FontWeight.Normal)
)

View File

@ -0,0 +1,12 @@
package com.example.shawarma.utils
import com.example.shawarma.R
sealed class BottomNavItem(var title:String, var icon:Int, var screen_route:String) {
object Home : BottomNavItem("Home", R.drawable.home_icon,ScreenPaths.home.name)
object Discount : BottomNavItem("Discount", R.drawable.discount_icon,ScreenPaths.discount.name)
object Cart : BottomNavItem("Cart", R.drawable.cart_icon,ScreenPaths.cart.name)
object Orders: BottomNavItem("Orders", R.drawable.orders_icon,ScreenPaths.orders.name)
object Products: BottomNavItem("Products", R.drawable.pen_icon, ScreenPaths.products.name)
}

View File

@ -0,0 +1,5 @@
package com.example.shawarma.utils
enum class ScreenPaths {
authorization, registration, home, discount, cart, orders, products, product
}

View File

@ -0,0 +1,75 @@
package com.example.shawarma.viewmodels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.example.shawarma.data.models.OrderStatus
import com.example.shawarma.data.models.OrderWithProducts
import com.example.shawarma.data.repos.OrderProductRepository
import com.example.shawarma.data.repos.OrderRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class CartViewModel @Inject constructor(
private val orderRepository: OrderRepository,
private val orderProductRepository: OrderProductRepository
) : ViewModel(){
private val _unpaidOrder = MutableLiveData<OrderWithProducts>()
val unpaidOrder: LiveData<OrderWithProducts>
get() = _unpaidOrder
fun getOrders(token: String) {
viewModelScope.launch {
_unpaidOrder.postValue(orderRepository.getUnpaidByUser(token))
}
}
fun getPaidList(token: String) : Flow<PagingData<OrderWithProducts>> {
return orderRepository.getPaidPaged(token)
}
fun payForOrder(token: String, order: OrderWithProducts) {
if (order.orderWithProducts.isEmpty()) {
return
}
val model = order.order
model.status = OrderStatus.Готовится.name
viewModelScope.launch {
orderRepository.update(token, model)
}
_unpaidOrder.postValue(null)
}
fun removeProductFromOrder(token: String, order: OrderWithProducts, productId: Int) {
val model = order.orderWithProducts[productId].orderProductModel
if(model.quantity == 1) {
// delete
viewModelScope.launch {
orderProductRepository.delete(token, model)
}
getOrders(token)
}
else{
// update
model.quantity -= 1
viewModelScope.launch {
orderProductRepository.update(token, model)
}
}
}
fun addProductToOrder(token: String, order: OrderWithProducts, productId: Int) {
val model = order.orderWithProducts[productId].orderProductModel
// update
model.quantity += 1
viewModelScope.launch {
orderProductRepository.update(token, model)
}
}
}

View File

@ -0,0 +1,69 @@
package com.example.shawarma.viewmodels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.example.shawarma.data.models.OrderModel
import com.example.shawarma.data.models.OrderProductModel
import com.example.shawarma.data.models.OrderStatus
import com.example.shawarma.data.models.ProductModel
import com.example.shawarma.data.repos.OrderProductRepository
import com.example.shawarma.data.repos.OrderRepository
import com.example.shawarma.data.repos.ProductRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import java.util.Calendar
import java.util.Date
import javax.inject.Inject
@HiltViewModel
class HomeViewModel @Inject constructor(
private val productRepository: ProductRepository,
private val orderRepository: OrderRepository,
private val orderProductRepository: OrderProductRepository
) : ViewModel() {
fun getProductList(token:String): Flow<PagingData<ProductModel>> {
return productRepository.getAllProductsPaged(token)
}
fun getDiscountList(token: String): Flow<PagingData<ProductModel>> {
return productRepository.getAllDiscountsPaged(token)
}
fun addProductToCart(productId: Int, token: String) {
viewModelScope.launch {
val product = productRepository.getById(productId).first()
val order = orderRepository.getUnpaidByUser(token)
if (order == null) {
val calendar: Calendar = Calendar.getInstance()
calendar.time = Date()
calendar.add(Calendar.HOUR_OF_DAY, 4)
val newOrder = orderRepository.insert(token, OrderModel(null, OrderStatus.Неоплачено.name, null, calendar.time.toString()))
if (newOrder != null) {
orderProductRepository.insert(token, OrderProductModel(newOrder.id!!, productId, 1, product.price))
}
}
else {
var isAlreadyAdded = false
for (prod in order.orderWithProducts) {
if (prod.product != null) {
if (prod.product!!.id == productId) {
val model = prod.orderProductModel
model.quantity += 1
model.totalPrice += prod.product!!.price
orderProductRepository.update(token, model)
isAlreadyAdded = true
}
}
}
if (!isAlreadyAdded) {
orderProductRepository.insert(token, OrderProductModel(order.order.id!!, productId, 1, product.price))
}
}
}
}
}

View File

@ -0,0 +1,46 @@
package com.example.shawarma.viewmodels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.example.shawarma.data.models.OrderWithProducts
import com.example.shawarma.data.repos.OrderRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class OrdersViewModel @Inject constructor(
private val orderRepository: OrderRepository
) : ViewModel() {
fun getAllPaidList(token: String) : Flow<PagingData<OrderWithProducts>> {
return orderRepository.getAllPaidPaged(token)
}
fun getAllReadyList(token: String) : Flow<PagingData<OrderWithProducts>> {
return orderRepository.getAllReadyPaged(token)
}
fun getAllServedList(token: String) : Flow<PagingData<OrderWithProducts>> {
return orderRepository.getAllServedPaged(token)
}
fun changeOrderStatus(token: String, order: OrderWithProducts, newStatus: String) {
val model = order.order
model.status = newStatus
viewModelScope.launch{
orderRepository.update(token, model)
}
}
fun deleteOrder(token: String, order: OrderWithProducts) {
viewModelScope.launch{
orderRepository.delete(token, order.order)
}
}
}

View File

@ -0,0 +1,46 @@
package com.example.shawarma.viewmodels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.shawarma.data.models.ProductModel
import com.example.shawarma.data.repos.ProductRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class ProductViewModel @Inject constructor(
private val productRepository: ProductRepository
) : ViewModel() {
private val _addingProductState = MutableLiveData<Boolean>(false)
val addingProductState: LiveData<Boolean?>
get() = _addingProductState
private val _product = MutableLiveData<ProductModel>()
val product: LiveData<ProductModel>
get() = _product
fun addProduct(name: String, price: Int, oldPrice: Int? = null, token: String) {
viewModelScope.launch {
productRepository.insert(ProductModel(null, name, price, oldPrice), token)
_addingProductState.postValue(true)
}
}
fun getProduct(productId: Int) {
viewModelScope.launch {
productRepository.getById(productId).collect {
_product.postValue(it)
}
}
}
fun updateProduct(name: String, price: Int, oldPrice: Int? = null, token: String) {
viewModelScope.launch {
productRepository.update(ProductModel(product.value?.id, name, price, oldPrice), token)
_addingProductState.postValue(true)
}
}
}

View File

@ -0,0 +1,29 @@
package com.example.shawarma.viewmodels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.example.shawarma.data.models.ProductModel
import com.example.shawarma.data.repos.ProductRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class ProductsViewModel @Inject constructor(
private val productRepository: ProductRepository
) : ViewModel() {
fun getItemsList(token:String): Flow<PagingData<ProductModel>> {
return productRepository.getAllItemsPaged(token)
}
fun deleteProduct(product: ProductModel, token: String) {
viewModelScope.launch {
productRepository.delete(product, token)
}
}
}

View File

@ -0,0 +1,90 @@
package com.example.shawarma.viewmodels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.shawarma.data.api.repos.RestUserRepository
import com.example.shawarma.data.models.UserModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
@HiltViewModel
class UserViewModel @Inject constructor(
private val restUserRepository: RestUserRepository
) : ViewModel() {
private val _token = MutableLiveData<String?>()
val token: LiveData<String?>
get() = _token
private val _authorizationState = MutableLiveData<Boolean?>()
val authorizationState: LiveData<Boolean?>
get() = _authorizationState
fun login(login: String, password: String){
viewModelScope.launch {
withContext(Dispatchers.Main) {
val token_response = restUserRepository.getToken(UserModel(id = null, login = login, password = password, role = ""))
if (token_response.access_token.isNotEmpty()) {
_token.postValue(token_response.access_token)
_authorizationState.postValue(true)
println(token_response.access_token)
}
else {
_token.postValue(null)
_authorizationState.postValue(false)
}
}
}
}
fun calmAuthorizationState() {
_authorizationState.postValue(null)
}
private val _registrationState = MutableLiveData<Boolean>()
val registrationState: LiveData<Boolean>
get() = _registrationState
fun register(login: String, password: String, passwordRepeat: String) {
_registrationState.postValue(null)
if (password != passwordRepeat) {
_registrationState.postValue(false)
return
}
if (login.length < 5 || login.length > 20) {
_registrationState.postValue(false)
return
}
if (password.length < 5 || password.length > 20) {
_registrationState.postValue(false)
return
}
viewModelScope.launch {
withContext(Dispatchers.Main) {
val user_response = restUserRepository.checkLogin(UserModel(null, login, password, ""))
if (user_response != null) {
if (user_response.login.isNullOrEmpty()) {
if (login == "admin" && password == "admin") {
restUserRepository.insert(UserModel(null, login, password, "ADMIN"))
_registrationState.postValue(true)
} else {
restUserRepository.insert(UserModel(null, login, password, "USER"))
_registrationState.postValue(true)
}
} else {
if (registrationState.value != true) {
_registrationState.postValue(false)
}
}
}
}
}
}
fun calmRegistrationState() {
_registrationState.postValue(null)
}
}

View File

@ -0,0 +1,71 @@
package com.example.shawarma.widgets
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem
import androidx.compose.material.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import com.example.shawarma.data.sharedpref.PreferencesManager
import com.example.shawarma.utils.BottomNavItem
@Composable
fun BottomNavBar(navController: NavController) {
val preferencesManager = PreferencesManager(LocalContext.current)
val user_role = preferencesManager.getData("user_role", "USER")
val adminItems = listOf(
BottomNavItem.Discount,
BottomNavItem.Home,
BottomNavItem.Cart,
BottomNavItem.Orders,
BottomNavItem.Products
)
val userItems = listOf(
BottomNavItem.Discount,
BottomNavItem.Home,
BottomNavItem.Cart
)
BottomNavigation(
backgroundColor = Color.White,
contentColor = Color.Black,
modifier = Modifier.height(60.dp)
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
val items = if (user_role == "ADMIN") adminItems else userItems
items.forEach { item ->
BottomNavigationItem(
icon = {
Icon(
painterResource(id = item.icon),
contentDescription = item.title,
modifier = Modifier.size(42.dp)
) },
selectedContentColor = Color.Black,
unselectedContentColor = Color.Black.copy(0.4f),
alwaysShowLabel = true,
selected = currentRoute == item.screen_route,
onClick = {
navController.navigate(item.screen_route) {
navController.graph.startDestinationRoute?.let { screen_route ->
popUpTo(screen_route) {
saveState = true
}
}
launchSingleTop = true
restoreState = true
}
},
)
}
}
}

View File

@ -0,0 +1,57 @@
package com.example.shawarma.widgets
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.shawarma.ui.theme.JejuFamily
import com.example.shawarma.ui.theme.MyTextFieldBackground
@Composable
fun MyTextField(
text: MutableState<TextFieldValue>,
onTextChanged: (TextFieldValue) -> Unit,
modifier: Modifier,
placeholder: String,
singleLine: Boolean,
visualTransformation: VisualTransformation = VisualTransformation.None
) {
return TextField(
value = text.value,
onValueChange = onTextChanged,
placeholder = {
Text(
text = placeholder,
fontSize = 16.sp,
style = TextStyle(
fontFamily = JejuFamily
)
)
},
singleLine = singleLine,
shape = RoundedCornerShape(20.dp),
textStyle = TextStyle(
fontSize = 16.sp,
fontFamily = JejuFamily
),
colors = TextFieldDefaults.textFieldColors(
textColor = Color.Black,
disabledTextColor = Color.Transparent,
backgroundColor = MyTextFieldBackground,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
),
visualTransformation = visualTransformation,
modifier = modifier
)
}

View File

@ -0,0 +1,45 @@
package com.example.shawarma.widgets
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import com.example.shawarma.R
@Composable
fun ShawarmaLogo1(){
Column(modifier = Modifier
.zIndex(-1f)
.fillMaxSize()
) {
Image(
painterResource(
id = R.drawable.shawarma1
),
contentDescription = "Logo",
modifier = Modifier
.size(256.dp, 256.dp)
.rotate(degrees = 19.25f)
.offset((-70).dp, (-5).dp),
)
Image(
painterResource(
id = R.drawable.shawarma1
),
contentDescription = "Logo",
modifier = Modifier
.size(256.dp, 256.dp)
.offset((200).dp, (100).dp)
.rotate(degrees = -136f)
)
}
}

View File

@ -0,0 +1,30 @@
package com.example.shawarma.widgets
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import com.example.shawarma.R
@Composable
fun ShawarmaLogo2() {
Column(
modifier = Modifier
.zIndex(-1f)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = R.drawable.shawarma1),
contentDescription = null,
modifier = Modifier
.size(256.dp, 256.dp)
)
}
}

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 B

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Some files were not shown because too many files have changed in this diff Show More