labs
16
.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
*.iml
|
||||
.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
|
||||
/server/node_modules/
|
3
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
1
.idea/.name
Normal file
@ -0,0 +1 @@
|
||||
My Application
|
6
.idea/compiler.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
20
.idea/gradle.xml
Normal 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>
|
41
.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
6
.idea/kotlinc.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.8.20" />
|
||||
</component>
|
||||
</project>
|
9
.idea/misc.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<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$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
16
app/.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
node_modules/
|
||||
*.iml
|
||||
.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
|
103
app/build.gradle.kts
Normal file
@ -0,0 +1,103 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("com.google.devtools.ksp")
|
||||
id("org.jetbrains.kotlin.plugin.serialization")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.myapplication"
|
||||
compileSdk = 33
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.example.myapplication"
|
||||
minSdk = 24
|
||||
targetSdk = 33
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
useSupportLibrary = true
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.4.5"
|
||||
}
|
||||
packaging {
|
||||
resources {
|
||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation("androidx.core:core-ktx:1.9.0")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
|
||||
|
||||
implementation("androidx.activity:activity-compose:1.7.2")
|
||||
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||
implementation("androidx.navigation:navigation-compose:2.6.0")
|
||||
implementation("androidx.compose.ui:ui")
|
||||
implementation("androidx.compose.ui:ui-graphics")
|
||||
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||
implementation("androidx.compose.material3:material3:1.1.2")
|
||||
|
||||
// Room
|
||||
val room_version = "2.5.2"
|
||||
implementation("androidx.room:room-runtime:$room_version")
|
||||
annotationProcessor("androidx.room:room-compiler:$room_version")
|
||||
ksp("androidx.room:room-compiler:$room_version")
|
||||
implementation("androidx.room:room-ktx:$room_version")
|
||||
implementation("androidx.room:room-paging:$room_version")
|
||||
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||
|
||||
//Paging
|
||||
implementation ("androidx.paging:paging-compose:3.2.1")
|
||||
implementation ("androidx.paging:paging-runtime:3.2.1")
|
||||
|
||||
// retrofit
|
||||
val retrofitVersion = "2.9.0"
|
||||
implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
|
||||
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
|
||||
implementation("androidx.paging:paging-compose:3.2.1")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
|
||||
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
|
||||
|
||||
// Tests
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||
}
|
21
app/proguard-rules.pro
vendored
Normal 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
|
@ -0,0 +1,24 @@
|
||||
package com.example.myapplication
|
||||
|
||||
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.myapplication", appContext.packageName)
|
||||
}
|
||||
}
|
33
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?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" />
|
||||
|
||||
<application
|
||||
android:name=".LessonApplication"
|
||||
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:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Pmudemo"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".MainComposeActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Pmudemo">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
|
||||
</manifest>
|
56
app/src/main/java/com/example/myapplication/BrDance.kt
Normal file
@ -0,0 +1,56 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
|
||||
@Composable
|
||||
fun BrDance() {
|
||||
val localContext = LocalContext.current
|
||||
val aboutText = localContext.resources.getText(R.string.brdance_text)
|
||||
|
||||
Column(Modifier.padding(all = 10.dp)) {
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
factory = { context -> TextView(context) },
|
||||
update = { it.text = aboutText }
|
||||
)
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.brdance),
|
||||
modifier = Modifier
|
||||
.size(400.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(19.dp), // Добавьте отступы, если необходимо,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun BrDancePreview() {
|
||||
PmudemoTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
BrDance()
|
||||
}
|
||||
}
|
||||
}
|
56
app/src/main/java/com/example/myapplication/Contemp.kt
Normal file
@ -0,0 +1,56 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
|
||||
@Composable
|
||||
fun Contemp() {
|
||||
val localContext = LocalContext.current
|
||||
val aboutText = localContext.resources.getText(R.string.contemp_text)
|
||||
|
||||
Column(Modifier.padding(all = 10.dp)) {
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
factory = { context -> TextView(context) },
|
||||
update = { it.text = aboutText }
|
||||
)
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.contemp),
|
||||
modifier = Modifier
|
||||
.size(400.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(19.dp), // Добавьте отступы, если необходимо,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun ContempPreview() {
|
||||
PmudemoTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
Contemp()
|
||||
}
|
||||
}
|
||||
}
|
99
app/src/main/java/com/example/myapplication/DirectionView.kt
Normal file
@ -0,0 +1,99 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
|
||||
@Composable
|
||||
fun DirectionView(navController: NavHostController?) {
|
||||
val localContext = LocalContext.current
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.kpop_button),
|
||||
modifier = Modifier.clickable { navController?.navigate("kpop") }
|
||||
.size(180.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(16.dp), // Добавьте отступы, если необходимо,
|
||||
contentDescription = null
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.house_button),
|
||||
modifier = Modifier.clickable { navController?.navigate("house") }
|
||||
.size(180.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(16.dp), // Добавьте отступы, если необходимо,
|
||||
|
||||
contentDescription = null
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.img_7),
|
||||
modifier = Modifier.clickable { }
|
||||
.size(180.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(16.dp), // Добавьте отступы, если необходимо,
|
||||
|
||||
contentDescription = null
|
||||
)
|
||||
|
||||
}
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 11.dp)
|
||||
.padding(start = 180.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.contemp_button),
|
||||
modifier = Modifier.clickable { navController?.navigate("contemp") }
|
||||
.size(180.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(16.dp), // Добавьте отступы, если необходимо,
|
||||
contentDescription = null
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.brdance_button),
|
||||
modifier = Modifier.clickable { navController?.navigate("brdance") }
|
||||
.size(180.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(19.dp), // Добавьте отступы, если необходимо,
|
||||
contentDescription = null
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.jazz_button),
|
||||
modifier = Modifier.clickable { }
|
||||
.size(180.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(16.dp), // Добавьте отступы, если необходимо,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun DirectionViewPreview() {
|
||||
PmudemoTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
DirectionView(navController = null)
|
||||
}
|
||||
}
|
||||
}
|
242
app/src/main/java/com/example/myapplication/Enter.kt
Normal file
@ -0,0 +1,242 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.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.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.requiredWidth
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Done
|
||||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import com.example.myapplication.Graph.AuthScreen
|
||||
import com.example.myapplication.Graph.Graph
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import com.example.myapplication.ui.AppViewModelProvider
|
||||
import com.example.myapplication.ui.navigation.Screen
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
import com.example.myapplication.ui.user.EntryViewModel
|
||||
|
||||
@SuppressLint("UnrememberedMutableState")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Enter(navController: NavController, modifier: Modifier = Modifier, entryScreenViewModel: EntryViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
||||
|
||||
var emailValue by rememberSaveable { mutableStateOf("") }
|
||||
var passwordValue by rememberSaveable { mutableStateOf("") }
|
||||
entryScreenViewModel.setUserList()
|
||||
val users = mutableStateOf<List<User>>(entryScreenViewModel.userList)
|
||||
val argument = currentUserViewModel.argument.value
|
||||
var passwordVisibility by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.requiredWidth(width = 412.dp)
|
||||
.requiredHeight(height = 1200.dp)
|
||||
.background(color = Color.White)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = 128.dp,
|
||||
y = 730.dp
|
||||
)
|
||||
.requiredWidth(width = 381.dp)
|
||||
.requiredHeight(height = 268.dp)
|
||||
.rotate(degrees = 8.33f)
|
||||
) {
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = (-111.28436279296875).dp,
|
||||
y = (-96.86965942382812).dp
|
||||
)
|
||||
.requiredWidth(width = 250.dp)
|
||||
.requiredHeight(height = 290.dp)
|
||||
.rotate(degrees = 12.96f)
|
||||
) {
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = (-111).dp,
|
||||
y = (-96).dp
|
||||
)
|
||||
.requiredWidth(width = 250.dp)
|
||||
.requiredHeight(height = 290.dp)
|
||||
.rotate(degrees = 12.96f)
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(0.8f)
|
||||
.clip(RoundedCornerShape(15.dp))
|
||||
.padding(10.dp)
|
||||
) {
|
||||
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
, contentAlignment = Alignment.TopCenter
|
||||
) {
|
||||
|
||||
|
||||
}
|
||||
Text(
|
||||
text = "Добро пожаловать!",
|
||||
color = Color.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TextStyle(
|
||||
fontSize = 20.sp
|
||||
),
|
||||
modifier = modifier
|
||||
.requiredWidth(width = 436.dp)
|
||||
.requiredHeight(height = 27.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(10.dp))
|
||||
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Spacer(modifier = Modifier.padding(3.dp))
|
||||
OutlinedTextField(
|
||||
value = emailValue,
|
||||
onValueChange = { emailValue = it },
|
||||
modifier = modifier
|
||||
.requiredWidth(width = 300.dp)
|
||||
.requiredHeight(height = 80.dp)
|
||||
.background(Color.White),
|
||||
label = { Text("Логин") },
|
||||
singleLine = true,
|
||||
placeholder = { Text("Введите логин") },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = passwordValue,
|
||||
onValueChange = { passwordValue = it },
|
||||
modifier = modifier
|
||||
.requiredWidth(width = 300.dp)
|
||||
.requiredHeight(height = 80.dp)
|
||||
.background(Color.White),
|
||||
label = { Text("Пароль") },
|
||||
singleLine = true,
|
||||
placeholder = { Text("Введите пароль") },
|
||||
visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
||||
trailingIcon = {
|
||||
val image = if (passwordVisibility)
|
||||
Icons.Filled.Done
|
||||
else Icons.Filled.Lock
|
||||
|
||||
val description =
|
||||
if (passwordVisibility) "Hide password" else "Show password"
|
||||
|
||||
IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
|
||||
Icon(imageVector = image, description)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.padding(10.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
if (passwordValue.isNotEmpty()) {
|
||||
users.value.forEach { user ->
|
||||
if (user.password == passwordValue && user.userName == emailValue) {
|
||||
currentUserViewModel.setArgument(user.uid.toString())
|
||||
Log.d("CurrentUserViewModel1", "Текущий пользователь: $user")
|
||||
navController.navigate(route = Graph.passUserId(user.uid.toString())) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.requiredWidth(width = 300.dp)
|
||||
.height(50.dp),
|
||||
shape = RoundedCornerShape(0.dp)
|
||||
) {
|
||||
Text(text = "Войти", fontSize = 20.sp)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.padding(3.dp))
|
||||
|
||||
Text(
|
||||
text = "Нет аккаунта? Зарегистрироваться",
|
||||
color = Color.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TextStyle(
|
||||
fontSize = 15.sp
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.offset(
|
||||
x = 0.dp,
|
||||
y = 75.dp
|
||||
)
|
||||
.clickable {
|
||||
navController?.navigate(route = AuthScreen.Register.route)
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(20.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.example.myapplication.Graph
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navigation
|
||||
import com.example.myapplication.Enter
|
||||
import com.example.myapplication.Registration
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
import com.example.myapplication.ui.user.EntryViewModel
|
||||
import com.example.myapplication.ui.user.RegisterViewModel
|
||||
|
||||
fun NavGraphBuilder.authNavGraph(navController: NavHostController, registerScreenViewModel: RegisterViewModel, entryScreenViewModel: EntryViewModel, currentUserViewModel: CurrentUserViewModel){
|
||||
navigation(
|
||||
route=Graph.AUTHENTICATION,
|
||||
startDestination = AuthScreen.Enter.route
|
||||
){
|
||||
composable(route=AuthScreen.Enter.route){
|
||||
Enter(navController = navController, Modifier,entryScreenViewModel,currentUserViewModel)
|
||||
}
|
||||
composable(route=AuthScreen.Register.route){
|
||||
Registration(navController = navController, Modifier,registerScreenViewModel,currentUserViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AuthScreen(val route: String){
|
||||
object Enter : AuthScreen(route = "ENTER")
|
||||
object Register : AuthScreen(route="REGISTER")
|
||||
}
|
112
app/src/main/java/com/example/myapplication/Graph/BottomBar.kt
Normal file
@ -0,0 +1,112 @@
|
||||
package com.example.myapplication.Graph
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.NavDestination.Companion.hierarchy
|
||||
import androidx.navigation.NavGraph.Companion.findStartDestination
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
|
||||
@Composable
|
||||
fun BottomBar(navController: NavHostController){
|
||||
val screens = listOf(
|
||||
BottomBarScreen.LessonList,
|
||||
BottomBarScreen.DirectionView,
|
||||
BottomBarScreen.HomeView,
|
||||
BottomBarScreen.Profile,
|
||||
BottomBarScreen.About,
|
||||
BottomBarScreen.Contemp,
|
||||
BottomBarScreen.BrDance,
|
||||
BottomBarScreen.House,
|
||||
BottomBarScreen.Kpop,
|
||||
BottomBarScreen.LessonEdit,
|
||||
BottomBarScreen.LessonRecord
|
||||
)
|
||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
val currentDestination=navBackStackEntry?.destination
|
||||
val bottomBarDestination=screens.any{ it.route==currentDestination?.route }
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.background(Color.Transparent),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (bottomBarDestination) {
|
||||
NavigationBar(
|
||||
containerColor = Color.Black,
|
||||
modifier = Modifier
|
||||
.height(90.dp)
|
||||
) {
|
||||
screens.forEach { screen ->
|
||||
AddItem(
|
||||
screen = screen,
|
||||
currentDestination = currentDestination,
|
||||
navController = navController
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RowScope.AddItem(
|
||||
screen: BottomBarScreen,
|
||||
currentDestination: NavDestination?,
|
||||
navController: NavController
|
||||
){
|
||||
val selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true
|
||||
|
||||
val background = Color.Black
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(90.dp)
|
||||
.background(background)
|
||||
.clickable(onClick = {
|
||||
navController.navigate(screen.route) {
|
||||
popUpTo(navController.graph.findStartDestination().id)
|
||||
launchSingleTop = true
|
||||
}
|
||||
})
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
|
||||
) {
|
||||
Icon(
|
||||
imageVector = screen.icon,
|
||||
contentDescription = "icon",
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(60.dp).padding(start=13.dp, end = 10.dp)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.example.myapplication.Graph
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.DateRange
|
||||
import androidx.compose.material.icons.filled.Face
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material.icons.filled.List
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.example.myapplication.R
|
||||
|
||||
sealed class BottomBarScreen(
|
||||
val route: String,
|
||||
val title: String,
|
||||
val icon: ImageVector = Icons.Filled.Favorite
|
||||
){
|
||||
object LessonList: BottomBarScreen(
|
||||
route = "LESSONLIST",
|
||||
title="",
|
||||
icon= Icons.Filled.DateRange,
|
||||
)
|
||||
object Profile: BottomBarScreen(
|
||||
route = "PROFILE",
|
||||
title="",
|
||||
icon= Icons.Filled.Face,
|
||||
)
|
||||
object About: BottomBarScreen(
|
||||
route = "ABOUT",
|
||||
title="",
|
||||
icon= Icons.Filled.Info,
|
||||
)
|
||||
object HomeView: BottomBarScreen(
|
||||
route = "HOME",
|
||||
title="",
|
||||
icon= Icons.Filled.Home,
|
||||
)
|
||||
object LessonEdit: BottomBarScreen(
|
||||
route = "lesson-edit/{id}",
|
||||
title=""
|
||||
)
|
||||
|
||||
object House: BottomBarScreen(
|
||||
route = "HOUSE",
|
||||
title=""
|
||||
)
|
||||
object Contemp: BottomBarScreen(
|
||||
route = "CONTEMP",
|
||||
title=""
|
||||
)
|
||||
object BrDance: BottomBarScreen(
|
||||
route = "BRDANCE",
|
||||
title=""
|
||||
)
|
||||
object Kpop: BottomBarScreen(
|
||||
route = "KPOP",
|
||||
title=""
|
||||
)
|
||||
object DirectionView: BottomBarScreen(
|
||||
route = "DIRECTIONVIEW",
|
||||
title="",
|
||||
icon= Icons.Filled.List
|
||||
)
|
||||
|
||||
object LessonRecord: BottomBarScreen(
|
||||
route = "lesson-record/{id}",
|
||||
title=""
|
||||
)
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.example.myapplication.Graph
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navArgument
|
||||
import com.example.myapplication.BrDance
|
||||
import com.example.myapplication.Contemp
|
||||
import com.example.myapplication.DirectionView
|
||||
import com.example.myapplication.Enter
|
||||
import com.example.myapplication.HomeView
|
||||
import com.example.myapplication.House
|
||||
import com.example.myapplication.Kpop
|
||||
import com.example.myapplication.Profile
|
||||
import com.example.myapplication.Registration
|
||||
import com.example.myapplication.ui.About
|
||||
import com.example.myapplication.ui.AppViewModelProvider
|
||||
import com.example.myapplication.ui.edit.DayDropDownViewModel
|
||||
import com.example.myapplication.ui.edit.DirectionDropDownViewModel
|
||||
import com.example.myapplication.ui.edit.LessonEdit
|
||||
import com.example.myapplication.ui.edit.LessonRecord
|
||||
import com.example.myapplication.ui.edit.LessonEditViewModel
|
||||
import com.example.myapplication.ui.lesson.LessonList
|
||||
import com.example.myapplication.ui.lesson.LessonListViewModel
|
||||
import com.example.myapplication.ui.navigation.Screen
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
|
||||
@Composable
|
||||
fun HomeNavGraph(navController: NavHostController, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory), lessonListViewModel: LessonListViewModel = viewModel(factory = AppViewModelProvider.Factory)){
|
||||
Column {
|
||||
TopBar()
|
||||
NavHost(
|
||||
navController = navController,
|
||||
route = Graph.MAIN,
|
||||
startDestination = BottomBarScreen.HomeView.route
|
||||
) {
|
||||
composable(route = BottomBarScreen.LessonList.route) { LessonList(navController, lessonListViewModel, currentUserViewModel) }
|
||||
composable(route = BottomBarScreen.About.route) { About() }
|
||||
composable(route = BottomBarScreen.HomeView.route) { HomeView(navController, Modifier) }
|
||||
composable(route = BottomBarScreen.House.route) { House() }
|
||||
composable(route = BottomBarScreen.Contemp.route) { Contemp() }
|
||||
composable(route = BottomBarScreen.BrDance.route) { BrDance() }
|
||||
composable(route = BottomBarScreen.Kpop.route) { Kpop() }
|
||||
composable(
|
||||
BottomBarScreen.LessonEdit.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
) {
|
||||
LessonEdit(navController)
|
||||
}
|
||||
composable(
|
||||
BottomBarScreen.LessonRecord.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
) {
|
||||
LessonRecord(navController)
|
||||
}
|
||||
composable(route = BottomBarScreen.DirectionView.route) { DirectionView(navController) }
|
||||
composable(route = BottomBarScreen.Profile.route) {
|
||||
Profile(
|
||||
navController,
|
||||
Modifier,
|
||||
currentUserViewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.example.myapplication.Graph
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHost
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navArgument
|
||||
import com.example.myapplication.LoadScreen
|
||||
import com.example.myapplication.ui.AppViewModelProvider
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
import com.example.myapplication.ui.user.EntryViewModel
|
||||
import com.example.myapplication.ui.user.RegisterViewModel
|
||||
|
||||
const val USERID_ARGUMENT="uid"
|
||||
|
||||
@Composable
|
||||
fun RootNavigationGraph(navController: NavHostController, registerScreenViewModel: RegisterViewModel = viewModel(factory = AppViewModelProvider.Factory), entryScreenViewModel: EntryViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
|
||||
NavHost(
|
||||
navController=navController,
|
||||
route = Graph.ROOT,
|
||||
startDestination = Graph.AUTHENTICATION
|
||||
){
|
||||
authNavGraph(navController=navController,registerScreenViewModel,entryScreenViewModel,currentUserViewModel)
|
||||
composable(route=Graph.MAIN,
|
||||
arguments = listOf(navArgument(USERID_ARGUMENT){
|
||||
type= NavType.StringType
|
||||
})){
|
||||
LoadScreen(currentUserViewModel = currentUserViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Graph{
|
||||
const val ROOT="root_graph"
|
||||
const val AUTHENTICATION="auth_graph"
|
||||
const val MAIN="main_graph/{$USERID_ARGUMENT}"
|
||||
fun passUserId(uid: String): String{
|
||||
return "main_graph/$uid"
|
||||
}
|
||||
}
|
37
app/src/main/java/com/example/myapplication/Graph/TopBar.kt
Normal file
@ -0,0 +1,37 @@
|
||||
package com.example.myapplication.Graph
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.myapplication.R
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun TopBar() {
|
||||
TopAppBar(
|
||||
modifier = Modifier.requiredHeight(height = 70.dp),
|
||||
colors = TopAppBarDefaults.smallTopAppBarColors(containerColor = Color.Black ),
|
||||
title = {
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
69
app/src/main/java/com/example/myapplication/HomeView.kt
Normal file
@ -0,0 +1,69 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.Configuration
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
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.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.example.myapplication.Graph.BottomBar
|
||||
import com.example.myapplication.Graph.HomeNavGraph
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
|
||||
@Composable
|
||||
fun HomeView(navController: NavController, modifier: Modifier = Modifier) {
|
||||
val localContext = LocalContext.current
|
||||
Box(modifier = Modifier.fillMaxSize().padding(all = 0.dp).background(Color.Black)) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.img_5),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
Column(Modifier.padding(all = 10.dp)) {
|
||||
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
factory = { context -> TextView(context) }
|
||||
)
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun LoadScreen(navController: NavHostController = rememberNavController(), currentUserViewModel: CurrentUserViewModel){
|
||||
Scaffold(
|
||||
bottomBar = { BottomBar(navController = navController) },
|
||||
) {
|
||||
Modifier
|
||||
.padding(it)
|
||||
HomeNavGraph(navController = navController, currentUserViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
|
56
app/src/main/java/com/example/myapplication/House.kt
Normal file
@ -0,0 +1,56 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
|
||||
@Composable
|
||||
fun House() {
|
||||
val localContext = LocalContext.current
|
||||
val aboutText = localContext.resources.getText(R.string.house_text)
|
||||
|
||||
Column(Modifier.padding(all = 10.dp)) {
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
factory = { context -> TextView(context) },
|
||||
update = { it.text = aboutText }
|
||||
)
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.house),
|
||||
modifier = Modifier
|
||||
.size(400.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(19.dp), // Добавьте отступы, если необходимо,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun HousePreview() {
|
||||
PmudemoTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
House()
|
||||
}
|
||||
}
|
||||
}
|
56
app/src/main/java/com/example/myapplication/Kpop.kt
Normal file
@ -0,0 +1,56 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
|
||||
@Composable
|
||||
fun Kpop() {
|
||||
val localContext = LocalContext.current
|
||||
val aboutText = localContext.resources.getText(R.string.kpop_text)
|
||||
|
||||
Column(Modifier.padding(all = 10.dp)) {
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
factory = { context -> TextView(context) },
|
||||
update = { it.text = aboutText }
|
||||
)
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.kpop),
|
||||
modifier = Modifier
|
||||
.size(400.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(19.dp), // Добавьте отступы, если необходимо,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun KpopPreview() {
|
||||
PmudemoTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
Kpop()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.app.Application
|
||||
import com.example.myapplication.dataBase.AppContainer
|
||||
import com.example.myapplication.dataBase.AppDataContainer
|
||||
|
||||
class LessonApplication : Application() {
|
||||
lateinit var container: AppContainer
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
container = AppDataContainer(this)
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.example.myapplication.Graph.RootNavigationGraph
|
||||
import com.example.myapplication.ui.AppViewModelProvider
|
||||
import com.example.myapplication.ui.navigation.MainNavbar
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
|
||||
class MainComposeActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
PmudemoTheme {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
//MainNavbar()
|
||||
RootNavigationGraph(navController = rememberNavController(),currentUserViewModel = viewModel(factory = AppViewModelProvider.Factory))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
453
app/src/main/java/com/example/myapplication/Profile.kt
Normal file
@ -0,0 +1,453 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.requiredWidth
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.Graph.AuthScreen
|
||||
import com.example.myapplication.ui.AppViewModelProvider
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@SuppressLint("UnrememberedMutableState")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Profile(navController: NavController, modifier: Modifier = Modifier, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
||||
val context = LocalContext.current
|
||||
|
||||
var getUser by remember { mutableStateOf(currentUserViewModel.user) }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
Log.d("Profile", "getUser: $getUser")
|
||||
var openDialogUser by remember { mutableStateOf(false) }
|
||||
var userName by remember { mutableStateOf(getUser?.userName) }
|
||||
var password by remember { mutableStateOf(getUser?.password) }
|
||||
var fio by remember { mutableStateOf(getUser?.fio) }
|
||||
|
||||
// Вывод лога о параметрах пользователя
|
||||
Log.d("Profile", "userName: $userName, password: $password, fio: $fio")
|
||||
|
||||
if (openDialogUser) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
openDialogUser = false
|
||||
userName = getUser?.userName.toString()
|
||||
password = getUser?.password.toString()
|
||||
fio = getUser?.fio.toString()
|
||||
},
|
||||
content = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
.background(Color.White),
|
||||
) {
|
||||
Text(
|
||||
text = "Редактирование профиля"
|
||||
)
|
||||
userName?.let {
|
||||
OutlinedTextField(
|
||||
value = it,
|
||||
onValueChange = {
|
||||
userName = it
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(10.dp),
|
||||
shape = RoundedCornerShape(0.dp),
|
||||
label = { Text("Логин") },
|
||||
placeholder = { Text("Введите логин...") },
|
||||
minLines = 1,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
password?.let {
|
||||
OutlinedTextField(
|
||||
value = it,
|
||||
onValueChange = {
|
||||
password = it
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(10.dp),
|
||||
shape = RoundedCornerShape(0.dp),
|
||||
label = { Text("Пароль") },
|
||||
placeholder = { Text("Введите пароль...") },
|
||||
minLines = 1,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
fio?.let {
|
||||
OutlinedTextField(
|
||||
value = it,
|
||||
onValueChange = {
|
||||
fio = it
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.padding(10.dp),
|
||||
shape = RoundedCornerShape(0.dp),
|
||||
label = { Text("ФИО") },
|
||||
placeholder = { Text("Введите ФИО...") },
|
||||
minLines = 1,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.padding(all = 8.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
openDialogUser = false
|
||||
if (password?.isNotEmpty() == true && userName?.isNotEmpty() == true && fio?.isNotEmpty() == true
|
||||
) {
|
||||
getUser?.userName = userName as String
|
||||
getUser?.password = password as String
|
||||
getUser?.fio = fio as String
|
||||
coroutineScope.launch {
|
||||
getUser?.let {
|
||||
currentUserViewModel.updateUser(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(start = 100.dp)
|
||||
.fillMaxWidth()
|
||||
.height(40.dp),
|
||||
shape = RoundedCornerShape(0.dp)
|
||||
) {
|
||||
Text(text = "Редактировать", fontSize = 15.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.requiredWidth(width = 412.dp)
|
||||
.requiredHeight(height = 605.dp)
|
||||
.background(color = Color.White)
|
||||
) {
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.offset(
|
||||
x = 9.dp,
|
||||
y = 80.dp
|
||||
)
|
||||
.requiredWidth(width = 393.dp)
|
||||
.requiredHeight(height = 70.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = 0.dp,
|
||||
y = 27.dp
|
||||
)
|
||||
.requiredWidth(width = 393.dp)
|
||||
.requiredHeight(height = 70.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.requiredWidth(width = 393.dp)
|
||||
.requiredHeight(height = 70.dp)
|
||||
.clip(shape = RoundedCornerShape(5.dp))
|
||||
.background(color = Color.White)
|
||||
.border(
|
||||
border = BorderStroke(3.dp, Color.Black),
|
||||
shape = RoundedCornerShape(5.dp)
|
||||
)
|
||||
)
|
||||
Text(
|
||||
text = "Мой профиль",
|
||||
color = Color.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TextStyle(
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.offset(
|
||||
x = 106.dp,
|
||||
y = 95.dp
|
||||
)
|
||||
.requiredWidth(width = 200.dp)
|
||||
.requiredHeight(height = 310.dp)
|
||||
) {
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = 0.dp,
|
||||
y = 90.dp
|
||||
)
|
||||
.requiredWidth(width = 200.dp)
|
||||
.requiredHeight(height = 44.dp)
|
||||
)
|
||||
{
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.requiredWidth(width = 300.dp)
|
||||
.requiredHeight(height = 80.dp)
|
||||
.background(Color.White)
|
||||
.border(width = 1.dp, color = Color.Black) // Добавляем черную границу,
|
||||
)
|
||||
Text(
|
||||
text = "${getUser?.fio}",
|
||||
color = Color.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TextStyle(
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
modifier = Modifier
|
||||
.requiredWidth(width = 200.dp)
|
||||
.requiredHeight(height = 44.dp)
|
||||
.wrapContentHeight(align = Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = 0.dp,
|
||||
y = 180.dp
|
||||
)
|
||||
.requiredWidth(width = 200.dp)
|
||||
.requiredHeight(height = 44.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.requiredWidth(width = 300.dp)
|
||||
.requiredHeight(height = 80.dp)
|
||||
.background(Color.White)
|
||||
.border(width = 1.dp, color = Color.Black) // Добавляем черную границу
|
||||
)
|
||||
Text(
|
||||
text = "${getUser?.userName}",
|
||||
color = Color.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TextStyle(
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
modifier = Modifier
|
||||
.requiredWidth(width = 200.dp)
|
||||
.requiredHeight(height = 44.dp)
|
||||
.wrapContentHeight(align = Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = 0.dp,
|
||||
y = 250.dp
|
||||
)
|
||||
.requiredWidth(width = 200.dp)
|
||||
.requiredHeight(height = 44.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.requiredWidth(width = 300.dp)
|
||||
.height(50.dp)
|
||||
.background(Color.Black),
|
||||
)
|
||||
Text(
|
||||
text = "Редактировать",
|
||||
color = Color.White,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TextStyle(
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
modifier = Modifier
|
||||
.requiredWidth(width = 200.dp)
|
||||
.requiredHeight(height = 44.dp)
|
||||
.wrapContentHeight(align = Alignment.CenterVertically)
|
||||
.clickable { openDialogUser = true })
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = 0.dp,
|
||||
y = 300.dp
|
||||
)
|
||||
.requiredWidth(width = 200.dp)
|
||||
.requiredHeight(height = 44.dp)
|
||||
)
|
||||
// {
|
||||
// Box(
|
||||
// modifier = Modifier
|
||||
// .fillMaxWidth()
|
||||
// .requiredWidth(width = 300.dp)
|
||||
// .height(50.dp)
|
||||
// .background(Color.Black),
|
||||
// )
|
||||
// Text(
|
||||
// text = "Выйти",
|
||||
// color = Color.White,
|
||||
// textAlign = TextAlign.Center,
|
||||
// style = TextStyle(
|
||||
// fontSize = 17.sp,
|
||||
// fontWeight = FontWeight.Bold
|
||||
// ),
|
||||
// modifier = Modifier
|
||||
// .requiredWidth(width = 200.dp)
|
||||
// .requiredHeight(height = 44.dp)
|
||||
// .wrapContentHeight(align = Alignment.CenterVertically)
|
||||
// .clickable { navController.navigate(route = AuthScreen.Enter.route); getUser = null })
|
||||
// }
|
||||
}
|
||||
}
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.offset(
|
||||
x = 9.dp,
|
||||
y = 220.dp
|
||||
)
|
||||
.requiredWidth(width = 393.dp)
|
||||
.requiredHeight(height = 70.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = 0.dp,
|
||||
y = 27.dp
|
||||
)
|
||||
.requiredWidth(width = 393.dp)
|
||||
.requiredHeight(height = 70.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.requiredWidth(width = 393.dp)
|
||||
.requiredHeight(height = 70.dp)
|
||||
.clip(shape = RoundedCornerShape(5.dp))
|
||||
.background(color = Color.White)
|
||||
|
||||
)
|
||||
Text(
|
||||
text = "Ближайшая запись:",
|
||||
color = Color.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TextStyle(
|
||||
fontSize = 24.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.offset(
|
||||
x = 9.dp,
|
||||
y = 220.dp
|
||||
)
|
||||
.requiredWidth(width = 393.dp)
|
||||
.requiredHeight(height = 70.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = 0.dp,
|
||||
y = 27.dp
|
||||
)
|
||||
.requiredWidth(width = 393.dp)
|
||||
.requiredHeight(height = 70.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.requiredWidth(width = 393.dp)
|
||||
.requiredHeight(height = 70.dp)
|
||||
.clip(shape = RoundedCornerShape(5.dp))
|
||||
.background(color = Color.White)
|
||||
|
||||
)
|
||||
Text(
|
||||
text = "${getUser?.lessonId}",
|
||||
color = Color.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TextStyle(
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
.background(Color.LightGray)
|
||||
.requiredWidth(300.dp)
|
||||
.requiredWidth(70.dp)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
281
app/src/main/java/com/example/myapplication/Registration.kt
Normal file
@ -0,0 +1,281 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.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.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.requiredWidth
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Done
|
||||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.Graph.AuthScreen
|
||||
import com.example.myapplication.Graph.Graph
|
||||
import com.example.myapplication.dataBase.model.RoleEnum
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import com.example.myapplication.ui.AppViewModelProvider
|
||||
import com.example.myapplication.ui.navigation.Screen
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
import com.example.myapplication.ui.user.RegisterViewModel
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@SuppressLint("UnrememberedMutableState")
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Registration(navController: NavController, modifier: Modifier = Modifier, registerScreenViewModel: RegisterViewModel = viewModel(factory = AppViewModelProvider.Factory), currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
||||
|
||||
var loginValue by rememberSaveable { mutableStateOf("") }
|
||||
var passwordValue by rememberSaveable { mutableStateOf("") }
|
||||
var fioValue by rememberSaveable { mutableStateOf("") }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
registerScreenViewModel.setUserList()
|
||||
var users = mutableStateOf<List<User>>(emptyList())
|
||||
registerScreenViewModel.users.observeForever { userList ->
|
||||
users.value = userList
|
||||
}
|
||||
|
||||
var passwordVisibility by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.requiredWidth(width = 412.dp)
|
||||
.requiredHeight(height = 915.dp)
|
||||
.background(color = Color.White)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = 128.dp,
|
||||
y = 730.dp
|
||||
)
|
||||
.requiredWidth(width = 381.dp)
|
||||
.requiredHeight(height = 268.dp)
|
||||
.rotate(degrees = 8.33f)
|
||||
) {
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(alignment = Alignment.TopStart)
|
||||
.offset(
|
||||
x = (-111.28436279296875).dp,
|
||||
y = (-96.86965942382812).dp
|
||||
)
|
||||
.requiredWidth(width = 250.dp)
|
||||
.requiredHeight(height = 290.dp)
|
||||
.rotate(degrees = 12.96f)
|
||||
) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(0.8f)
|
||||
.clip(RoundedCornerShape(15.dp))
|
||||
.background(Color.Transparent)
|
||||
.padding(10.dp)
|
||||
) {
|
||||
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
text = "Регистрация",
|
||||
color = Color.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TextStyle(
|
||||
fontSize = 20.sp
|
||||
),
|
||||
modifier = modifier
|
||||
.requiredWidth(width = 436.dp)
|
||||
.requiredHeight(height = 27.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(10.dp))
|
||||
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
OutlinedTextField(
|
||||
value = loginValue,
|
||||
onValueChange = {
|
||||
loginValue = it
|
||||
},
|
||||
colors = TextFieldDefaults.textFieldColors(
|
||||
containerColor = Color.White
|
||||
),
|
||||
modifier = Modifier
|
||||
.requiredWidth(width = 300.dp)
|
||||
.requiredHeight(height = 80.dp)
|
||||
.background(Color.White),
|
||||
label = { Text("Логин") },
|
||||
placeholder = { Text("Логин") },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email),
|
||||
singleLine = true,
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(3.dp))
|
||||
OutlinedTextField(
|
||||
value = fioValue,
|
||||
onValueChange = {
|
||||
fioValue = it
|
||||
},
|
||||
colors = TextFieldDefaults.textFieldColors(
|
||||
containerColor = Color.White
|
||||
),
|
||||
modifier = Modifier
|
||||
.requiredWidth(width = 300.dp)
|
||||
.requiredHeight(height = 80.dp)
|
||||
.background(Color.White),
|
||||
label = { Text("ФИО") },
|
||||
placeholder = { Text("ФИО") },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email),
|
||||
singleLine = true,
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(3.dp))
|
||||
OutlinedTextField(
|
||||
value = passwordValue,
|
||||
onValueChange = { passwordValue = it },
|
||||
colors = TextFieldDefaults.textFieldColors(
|
||||
containerColor = Color.White
|
||||
),
|
||||
modifier = modifier
|
||||
.requiredWidth(width = 300.dp)
|
||||
.requiredHeight(height = 80.dp)
|
||||
.background(Color.White),
|
||||
label = { Text("Пароль") },
|
||||
singleLine = true,
|
||||
placeholder = { Text("Пароль") },
|
||||
visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
||||
trailingIcon = {
|
||||
val image = if (passwordVisibility)
|
||||
Icons.Filled.Done
|
||||
else Icons.Filled.Lock
|
||||
|
||||
val description =
|
||||
if (passwordVisibility) "Hide password" else "Show password"
|
||||
|
||||
IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
|
||||
Icon(imageVector = image, description)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.padding(10.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
var isExist = false;
|
||||
if (passwordValue.isNotEmpty() && loginValue.isNotEmpty() && fioValue.isNotEmpty()) {
|
||||
users.value.forEach { user ->
|
||||
if (user.userName == loginValue || user.fio == fioValue) {
|
||||
Log.d("User already exist. User id: ", user.uid.toString())
|
||||
isExist = true
|
||||
}
|
||||
}
|
||||
if (!isExist) {
|
||||
val newUser = User(0, loginValue, passwordValue, fioValue, RoleEnum.User, null)
|
||||
coroutineScope.launch {
|
||||
val insertResult = async {
|
||||
registerScreenViewModel.insertUser(newUser)
|
||||
}
|
||||
|
||||
insertResult.await()
|
||||
|
||||
registerScreenViewModel.setUserList()
|
||||
registerScreenViewModel.users.observeForever { userList ->
|
||||
users.value = userList
|
||||
Log.println(Log.ASSERT, "UsersList", users.value.toString())
|
||||
users.value?.forEach { user ->
|
||||
if (user.password == passwordValue && user.userName == loginValue) {
|
||||
currentUserViewModel.setArgument(user.uid.toString())
|
||||
navController.navigate(route = Graph.passUserId(user.uid.toString())) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.requiredWidth(width = 300.dp)
|
||||
.height(50.dp),
|
||||
shape = RoundedCornerShape(0.dp)
|
||||
) {
|
||||
Text(text = "Зарегистироваться", fontSize = 20.sp)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.padding(0.dp))
|
||||
|
||||
Text(
|
||||
text = "Уже есть аккаунт? Войти",
|
||||
color = Color.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TextStyle(
|
||||
fontSize = 15.sp
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.offset(
|
||||
x = 0.dp,
|
||||
y = 75.dp
|
||||
)
|
||||
.clickable {
|
||||
navController.navigate(route = AuthScreen.Enter.route)
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(20.dp))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package com.example.myapplication.api
|
||||
|
||||
import com.example.myapplication.api.model.DayOfWeekRemote
|
||||
import com.example.myapplication.api.model.DirectionRemote
|
||||
import com.example.myapplication.api.model.LessonRemote
|
||||
import com.example.myapplication.api.model.UserRemote
|
||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.DELETE
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.PUT
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface MyServerService {
|
||||
@GET("days")
|
||||
suspend fun getDays(): List<DayOfWeekRemote>
|
||||
|
||||
@GET("users")
|
||||
suspend fun getUsers(): List<UserRemote>
|
||||
|
||||
@GET("directions")
|
||||
suspend fun getDirections(): List<DirectionRemote>
|
||||
|
||||
@GET("lessons")
|
||||
suspend fun getLessons(
|
||||
@Query("_page") page: Int,
|
||||
@Query("_limit") limit: Int,
|
||||
): List<LessonRemote>
|
||||
|
||||
@GET("lessons/{id}")
|
||||
suspend fun getLesson(
|
||||
@Path("id") id: Int,
|
||||
): LessonRemote
|
||||
|
||||
@POST("lessons")
|
||||
suspend fun createLesson(
|
||||
@Body lesson: LessonRemote,
|
||||
): LessonRemote
|
||||
|
||||
@PUT("lessons/{id}")
|
||||
suspend fun updateLesson(
|
||||
@Path("id") id: Int,
|
||||
@Body lesson: LessonRemote,
|
||||
): LessonRemote
|
||||
|
||||
@DELETE("lessons/{id}")
|
||||
suspend fun deleteLesson(
|
||||
@Path("id") id: Int,
|
||||
): LessonRemote
|
||||
|
||||
@GET("users/{id}")
|
||||
suspend fun getUserById(
|
||||
@Path("id") id: Int,
|
||||
): UserRemote
|
||||
|
||||
@POST("users")
|
||||
suspend fun createUser(
|
||||
@Body user: UserRemote,
|
||||
): UserRemote
|
||||
|
||||
@PUT("users/{id}")
|
||||
suspend fun updateUser(
|
||||
@Path("id") id: Int,
|
||||
@Body user: UserRemote,
|
||||
): UserRemote
|
||||
|
||||
@DELETE("users/{id}")
|
||||
suspend fun deleteUser(
|
||||
@Path("id") id: Int,
|
||||
): UserRemote
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL = "http://192.168.1.67:8079/"
|
||||
|
||||
@Volatile
|
||||
private var INSTANCE: MyServerService? = null
|
||||
|
||||
fun getInstance(): MyServerService {
|
||||
return INSTANCE ?: synchronized(this) {
|
||||
val logger = HttpLoggingInterceptor()
|
||||
logger.level = HttpLoggingInterceptor.Level.BASIC
|
||||
val client = OkHttpClient.Builder()
|
||||
.addInterceptor(logger)
|
||||
.build()
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(BASE_URL)
|
||||
.client(client)
|
||||
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
|
||||
.build()
|
||||
.create(MyServerService::class.java)
|
||||
.also { INSTANCE = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.example.myapplication.api.day
|
||||
|
||||
import android.util.Log
|
||||
import com.example.myapplication.api.MyServerService
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import com.example.myapplication.dataBase.repository.DayOfWeekRepository
|
||||
import com.example.myapplication.dataBase.repository.OfflineDayOfWeekRepository
|
||||
import com.example.myapplication.api.lesson.RestLessonRepository
|
||||
import com.example.myapplication.api.model.toDayOfWeek
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class RestDayOfWeekRepository(
|
||||
private val service: MyServerService,
|
||||
private val dbDayOfWeekRepository: OfflineDayOfWeekRepository,
|
||||
): DayOfWeekRepository {
|
||||
override suspend fun getAllDays(): List<DayOfWeek> {
|
||||
Log.d(RestLessonRepository::class.simpleName, "Get days")
|
||||
|
||||
val existDayOfWeeks = dbDayOfWeekRepository.getAllDays().associateBy { it.uid }.toMutableMap()
|
||||
|
||||
service.getDays()
|
||||
.map { it.toDayOfWeek() }
|
||||
.forEach { dayOfWeek ->
|
||||
val existDayOfWeek = existDayOfWeeks[dayOfWeek.uid]
|
||||
if (existDayOfWeek == null) {
|
||||
dbDayOfWeekRepository.createDayOfWeek(dayOfWeek)
|
||||
} else if (existDayOfWeek != dayOfWeek) {
|
||||
dbDayOfWeekRepository.updateDayOfWeek(dayOfWeek)
|
||||
}
|
||||
existDayOfWeeks[dayOfWeek.uid] = dayOfWeek
|
||||
}
|
||||
|
||||
return existDayOfWeeks.map { it.value }.sortedBy { it.uid }
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.example.myapplication.api.direction
|
||||
|
||||
import android.util.Log
|
||||
import com.example.myapplication.api.MyServerService
|
||||
import com.example.myapplication.api.lesson.RestLessonRepository
|
||||
import com.example.myapplication.api.model.toDirection
|
||||
import com.example.myapplication.dataBase.model.Direction
|
||||
import com.example.myapplication.dataBase.repository.DirectionRepository
|
||||
import com.example.myapplication.dataBase.repository.OfflineDirectionRepository
|
||||
|
||||
class RestDirectionRepository(
|
||||
private val service: MyServerService,
|
||||
private val dbDirectionRepository: OfflineDirectionRepository,
|
||||
): DirectionRepository {
|
||||
override suspend fun getAllDirections(): List<Direction> {
|
||||
Log.d(RestLessonRepository::class.simpleName, "Get directions")
|
||||
|
||||
val existDirections = dbDirectionRepository.getAllDirections().associateBy { it.uid }.toMutableMap()
|
||||
|
||||
service.getDirections()
|
||||
.map { it.toDirection() }
|
||||
.forEach { dayOfWeek ->
|
||||
val existDirection = existDirections[dayOfWeek.uid]
|
||||
if (existDirection == null) {
|
||||
dbDirectionRepository.createDirection(dayOfWeek)
|
||||
} else if (existDirection != dayOfWeek) {
|
||||
dbDirectionRepository.updateDirection(dayOfWeek)
|
||||
}
|
||||
existDirections[dayOfWeek.uid] = dayOfWeek
|
||||
}
|
||||
|
||||
return existDirections.map { it.value }.sortedBy { it.uid }
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package com.example.myapplication.api.lesson
|
||||
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.LoadType
|
||||
import androidx.paging.PagingState
|
||||
import androidx.paging.RemoteMediator
|
||||
import androidx.room.withTransaction
|
||||
import com.example.myapplication.api.MyServerService
|
||||
import com.example.myapplication.api.day.RestDayOfWeekRepository
|
||||
import com.example.myapplication.api.direction.RestDirectionRepository
|
||||
import com.example.myapplication.api.model.toLesson
|
||||
import com.example.myapplication.dataBase.AppDatabase
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import com.example.myapplication.dataBase.remotekeys.model.RemoteKeyType
|
||||
import com.example.myapplication.dataBase.remotekeys.model.RemoteKeys
|
||||
import com.example.myapplication.dataBase.remotekeys.repository.OfflineRemoteKeyRepository
|
||||
import com.example.myapplication.dataBase.repository.OfflineLessonRepository
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
class LessonRemoteMediator(
|
||||
private val service: MyServerService,
|
||||
private val dbLessonRepository: OfflineLessonRepository,
|
||||
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
|
||||
private val dayOfWeekRestRepository: RestDayOfWeekRepository,
|
||||
private val directionRestRepository: RestDirectionRepository,
|
||||
private val database: AppDatabase
|
||||
) : RemoteMediator<Int, Lesson>() {
|
||||
|
||||
override suspend fun initialize(): InitializeAction {
|
||||
return InitializeAction.LAUNCH_INITIAL_REFRESH
|
||||
}
|
||||
|
||||
override suspend fun load(
|
||||
loadType: LoadType,
|
||||
state: PagingState<Int, Lesson>
|
||||
): MediatorResult {
|
||||
val page = when (loadType) {
|
||||
LoadType.REFRESH -> {
|
||||
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
|
||||
remoteKeys?.nextKey?.minus(1) ?: 1
|
||||
}
|
||||
|
||||
LoadType.PREPEND -> {
|
||||
val remoteKeys = getRemoteKeyForFirstItem(state)
|
||||
remoteKeys?.prevKey
|
||||
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
|
||||
}
|
||||
|
||||
LoadType.APPEND -> {
|
||||
val remoteKeys = getRemoteKeyForLastItem(state)
|
||||
remoteKeys?.nextKey
|
||||
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
val lessons = service.getLessons(page, state.config.pageSize).map { it.toLesson() }
|
||||
val endOfPaginationReached = lessons.isEmpty()
|
||||
database.withTransaction {
|
||||
if (loadType == LoadType.REFRESH) {
|
||||
dbRemoteKeyRepository.deleteRemoteKey(RemoteKeyType.LESSON)
|
||||
dbLessonRepository.clearLessons()
|
||||
}
|
||||
val prevKey = if (page == 1) null else page - 1
|
||||
val nextKey = if (endOfPaginationReached) null else page + 1
|
||||
val keys = lessons.map {
|
||||
RemoteKeys(
|
||||
entityId = it.uid,
|
||||
type = RemoteKeyType.LESSON,
|
||||
prevKey = prevKey,
|
||||
nextKey = nextKey
|
||||
)
|
||||
}
|
||||
dayOfWeekRestRepository.getAllDays()
|
||||
directionRestRepository.getAllDirections()
|
||||
dbRemoteKeyRepository.createRemoteKeys(keys)
|
||||
dbLessonRepository.insertLessons(lessons)
|
||||
}
|
||||
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
|
||||
} catch (exception: IOException) {
|
||||
return MediatorResult.Error(exception)
|
||||
} catch (exception: HttpException) {
|
||||
return MediatorResult.Error(exception)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, Lesson>): RemoteKeys? {
|
||||
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
|
||||
?.let { student ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(student.uid, RemoteKeyType.LESSON)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Lesson>): RemoteKeys? {
|
||||
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
|
||||
?.let { student ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(student.uid, RemoteKeyType.LESSON)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getRemoteKeyClosestToCurrentPosition(
|
||||
state: PagingState<Int, Lesson>
|
||||
): RemoteKeys? {
|
||||
return state.anchorPosition?.let { position ->
|
||||
state.closestItemToPosition(position)?.uid?.let { studentUid ->
|
||||
dbRemoteKeyRepository.getAllRemoteKeys(studentUid, RemoteKeyType.LESSON)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package com.example.myapplication.api.lesson
|
||||
|
||||
import android.util.Log
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingSource
|
||||
import com.example.myapplication.api.MyServerService
|
||||
import com.example.myapplication.api.day.RestDayOfWeekRepository
|
||||
import com.example.myapplication.api.direction.RestDirectionRepository
|
||||
import com.example.myapplication.api.model.toLesson
|
||||
import com.example.myapplication.api.model.toLessonRemote
|
||||
import com.example.myapplication.dataBase.AppContainer
|
||||
import com.example.myapplication.dataBase.AppDatabase
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import com.example.myapplication.dataBase.remotekeys.repository.OfflineRemoteKeyRepository
|
||||
import com.example.myapplication.dataBase.repository.LessonRepository
|
||||
import com.example.myapplication.dataBase.repository.OfflineLessonRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class RestLessonRepository(
|
||||
private val service: MyServerService,
|
||||
private val dbLessonRepository: OfflineLessonRepository,
|
||||
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
|
||||
private val dayOfWeekRestRepository: RestDayOfWeekRepository,
|
||||
private val directionRestRepository: RestDirectionRepository,
|
||||
private val database: AppDatabase
|
||||
) : LessonRepository {
|
||||
override fun getAllLessons(): Flow<PagingData<Lesson>> {
|
||||
Log.d(RestLessonRepository::class.simpleName, "Get lessons")
|
||||
|
||||
val pagingSourceFactory = { dbLessonRepository.getAllLessonsPagingSource() }
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
return Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = AppContainer.LIMIT,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
remoteMediator = LessonRemoteMediator(
|
||||
service,
|
||||
dbLessonRepository,
|
||||
dbRemoteKeyRepository,
|
||||
dayOfWeekRestRepository,
|
||||
directionRestRepository,
|
||||
database,
|
||||
),
|
||||
pagingSourceFactory = pagingSourceFactory
|
||||
).flow
|
||||
}
|
||||
|
||||
override suspend fun getLesson(uid: Int): Lesson =
|
||||
service.getLesson(uid).toLesson()
|
||||
|
||||
override suspend fun insertLesson(lesson: Lesson) {
|
||||
service.createLesson(lesson.toLessonRemote()).toLesson()
|
||||
}
|
||||
|
||||
override suspend fun updateLesson(lesson: Lesson) {
|
||||
service.updateLesson(lesson.uid, lesson.toLessonRemote()).toLesson()
|
||||
}
|
||||
|
||||
override suspend fun deleteLesson(lesson: Lesson) {
|
||||
service.deleteLesson(lesson.uid).toLesson()
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.example.myapplication.api.model
|
||||
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class DayOfWeekRemote(
|
||||
val id: Int = 0,
|
||||
val dayName: String
|
||||
)
|
||||
|
||||
fun DayOfWeekRemote.toDayOfWeek(): DayOfWeek = DayOfWeek(
|
||||
id,
|
||||
dayName
|
||||
)
|
@ -0,0 +1,15 @@
|
||||
package com.example.myapplication.api.model
|
||||
|
||||
import com.example.myapplication.dataBase.model.Direction
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class DirectionRemote(
|
||||
val id: Int = 0,
|
||||
val directionName: String
|
||||
)
|
||||
|
||||
fun DirectionRemote.toDirection(): Direction = Direction(
|
||||
id,
|
||||
directionName
|
||||
)
|
@ -0,0 +1,34 @@
|
||||
package com.example.myapplication.api.model
|
||||
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class LessonRemote(
|
||||
val id: Int = 0,
|
||||
val teacher: String = "",
|
||||
val time: String = "",
|
||||
val classNumber: Int = 0,
|
||||
|
||||
val dayOfWeekId: Int = 0,
|
||||
val directionId: Int = 0
|
||||
|
||||
)
|
||||
|
||||
fun LessonRemote.toLesson(): Lesson = Lesson(
|
||||
id,
|
||||
teacher,
|
||||
time,
|
||||
classNumber,
|
||||
dayOfWeekId,
|
||||
directionId,
|
||||
)
|
||||
|
||||
fun Lesson.toLessonRemote(): LessonRemote = LessonRemote(
|
||||
uid,
|
||||
teacher,
|
||||
time,
|
||||
classNumber,
|
||||
dayOfWeekId,
|
||||
directionId
|
||||
)
|
@ -0,0 +1,34 @@
|
||||
package com.example.myapplication.api.model
|
||||
|
||||
import com.example.myapplication.dataBase.model.Direction
|
||||
import com.example.myapplication.dataBase.model.RoleEnum
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class UserRemote(
|
||||
val id: Int=0,
|
||||
var userName: String="",
|
||||
var password: String="",
|
||||
var fio: String="",
|
||||
val role: RoleEnum,
|
||||
val lessonId: Int?=0
|
||||
)
|
||||
|
||||
fun UserRemote.toUser(): User = User(
|
||||
id,
|
||||
userName,
|
||||
password,
|
||||
fio,
|
||||
role,
|
||||
lessonId
|
||||
)
|
||||
|
||||
fun User.toUserRemote(): UserRemote = UserRemote(
|
||||
uid,
|
||||
userName,
|
||||
password,
|
||||
fio,
|
||||
role,
|
||||
lessonId
|
||||
)
|
@ -0,0 +1,70 @@
|
||||
package com.example.myapplication.api.user
|
||||
|
||||
import android.util.Log
|
||||
import androidx.paging.ExperimentalPagingApi
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import com.example.myapplication.api.MyServerService
|
||||
import com.example.myapplication.api.day.RestDayOfWeekRepository
|
||||
import com.example.myapplication.api.direction.RestDirectionRepository
|
||||
import com.example.myapplication.api.lesson.LessonRemoteMediator
|
||||
import com.example.myapplication.api.lesson.RestLessonRepository
|
||||
import com.example.myapplication.api.model.toDayOfWeek
|
||||
import com.example.myapplication.api.model.toLesson
|
||||
import com.example.myapplication.api.model.toLessonRemote
|
||||
import com.example.myapplication.api.model.toUser
|
||||
import com.example.myapplication.api.model.toUserRemote
|
||||
import com.example.myapplication.dataBase.AppContainer
|
||||
import com.example.myapplication.dataBase.AppDatabase
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import com.example.myapplication.dataBase.remotekeys.repository.OfflineRemoteKeyRepository
|
||||
import com.example.myapplication.dataBase.repository.DayOfWeekRepository
|
||||
import com.example.myapplication.dataBase.repository.LessonRepository
|
||||
import com.example.myapplication.dataBase.repository.OfflineDayOfWeekRepository
|
||||
import com.example.myapplication.dataBase.repository.OfflineUserRepository
|
||||
import com.example.myapplication.dataBase.repository.UserRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class RestUserRepository(
|
||||
private val service: MyServerService,
|
||||
private val dbUserRepository: OfflineUserRepository
|
||||
) : UserRepository {
|
||||
override suspend fun getAllUsers(): List<User> {
|
||||
Log.d(RestUserRepository::class.simpleName, "Get users")
|
||||
val existUsers = dbUserRepository.getAllUsers().associateBy { it.uid }.toMutableMap()
|
||||
|
||||
service.getUsers()
|
||||
.map { it.toUser() }
|
||||
.forEach { user ->
|
||||
val existUser = existUsers[user.uid]
|
||||
if (existUser == null) {
|
||||
dbUserRepository.createUser(user)
|
||||
} else if (existUser != user) {
|
||||
dbUserRepository.updateUser(user)
|
||||
}
|
||||
existUsers[user.uid] = user
|
||||
}
|
||||
|
||||
return existUsers.map { it.value }.sortedBy { it.uid }
|
||||
}
|
||||
|
||||
override suspend fun getUserById(uid: Int?): User? =
|
||||
uid?.let { service.getUserById(it).toUser() }
|
||||
|
||||
override suspend fun createUser(user: User) {
|
||||
service.createUser(user.toUserRemote()).toUser()
|
||||
}
|
||||
|
||||
override suspend fun updateUser(user: User) {
|
||||
service.updateUser(user.uid, user.toUserRemote())
|
||||
dbUserRepository.updateUser(user)
|
||||
}
|
||||
|
||||
override suspend fun deleteUser(user: User) {
|
||||
user.uid?.let { service.deleteUser(it).toUser() }
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package com.example.myapplication.dataBase
|
||||
|
||||
import android.content.Context
|
||||
import com.example.myapplication.api.MyServerService
|
||||
import com.example.myapplication.api.day.RestDayOfWeekRepository
|
||||
import com.example.myapplication.api.direction.RestDirectionRepository
|
||||
import com.example.myapplication.api.lesson.RestLessonRepository
|
||||
import com.example.myapplication.api.user.RestUserRepository
|
||||
import com.example.myapplication.dataBase.remotekeys.repository.OfflineRemoteKeyRepository
|
||||
import com.example.myapplication.dataBase.remotekeys.repository.RemoteKeyRepository
|
||||
import com.example.myapplication.dataBase.repository.DayOfWeekRepository
|
||||
import com.example.myapplication.dataBase.repository.DirectionRepository
|
||||
import com.example.myapplication.dataBase.repository.LessonRepository
|
||||
import com.example.myapplication.dataBase.repository.OfflineDayOfWeekRepository
|
||||
import com.example.myapplication.dataBase.repository.OfflineDirectionRepository
|
||||
import com.example.myapplication.dataBase.repository.OfflineLessonRepository
|
||||
import com.example.myapplication.dataBase.repository.OfflineUserRepository
|
||||
import com.example.myapplication.dataBase.repository.UserRepository
|
||||
|
||||
|
||||
interface AppContainer {
|
||||
// val lessonRepository: LessonRepository
|
||||
// val directionRepository: DirectionRepository
|
||||
// val dayRepository: DayOfWeekRepository
|
||||
val lessonRestRepository: RestLessonRepository
|
||||
val directionRestRepository: RestDirectionRepository
|
||||
val dayRestRepository: RestDayOfWeekRepository
|
||||
val userRestRepository: RestUserRepository
|
||||
|
||||
companion object {
|
||||
const val TIMEOUT = 5000L
|
||||
const val LIMIT = 10
|
||||
}
|
||||
}
|
||||
|
||||
class AppDataContainer(private val context: Context) : AppContainer {
|
||||
private val lessonRepository: OfflineLessonRepository by lazy {
|
||||
OfflineLessonRepository(AppDatabase.getInstance(context).lessonDao())
|
||||
}
|
||||
private val dayRepository: OfflineDayOfWeekRepository by lazy {
|
||||
OfflineDayOfWeekRepository(AppDatabase.getInstance(context).dayDao())
|
||||
}
|
||||
private val directionRepository: OfflineDirectionRepository by lazy {
|
||||
OfflineDirectionRepository(AppDatabase.getInstance(context).directionDao())
|
||||
}
|
||||
private val remoteKeyRepository: OfflineRemoteKeyRepository by lazy {
|
||||
OfflineRemoteKeyRepository(AppDatabase.getInstance(context).remoteKeysDao())
|
||||
}
|
||||
private val userRepository: OfflineUserRepository by lazy {
|
||||
OfflineUserRepository(AppDatabase.getInstance(context).userDao())
|
||||
}
|
||||
override val lessonRestRepository: RestLessonRepository by lazy {
|
||||
RestLessonRepository(
|
||||
MyServerService.getInstance(),
|
||||
lessonRepository,
|
||||
remoteKeyRepository,
|
||||
dayRestRepository,
|
||||
directionRestRepository,
|
||||
AppDatabase.getInstance(context)
|
||||
)
|
||||
}
|
||||
override val directionRestRepository: RestDirectionRepository by lazy {
|
||||
RestDirectionRepository(
|
||||
MyServerService.getInstance(),
|
||||
directionRepository
|
||||
)
|
||||
}
|
||||
override val dayRestRepository: RestDayOfWeekRepository by lazy {
|
||||
RestDayOfWeekRepository(
|
||||
MyServerService.getInstance(),
|
||||
dayRepository
|
||||
)
|
||||
}
|
||||
|
||||
override val userRestRepository: RestUserRepository by lazy {
|
||||
RestUserRepository(
|
||||
MyServerService.getInstance(),
|
||||
userRepository
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package com.example.myapplication.dataBase
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.example.myapplication.dataBase.dao.DayDao
|
||||
import com.example.myapplication.dataBase.dao.DirectionDao
|
||||
import com.example.myapplication.dataBase.dao.LessonDao
|
||||
import com.example.myapplication.dataBase.dao.UserDao
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import com.example.myapplication.dataBase.model.Direction
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import com.example.myapplication.dataBase.model.RoleEnum
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import com.example.myapplication.dataBase.remotekeys.dao.RemoteKeysDao
|
||||
import com.example.myapplication.dataBase.remotekeys.model.RemoteKeys
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Database(entities = [Lesson::class, DayOfWeek::class, Direction::class, User::class, RemoteKeys::class], version = 1, exportSchema = false)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun lessonDao(): LessonDao
|
||||
abstract fun dayDao(): DayDao
|
||||
abstract fun directionDao(): DirectionDao
|
||||
abstract fun userDao(): UserDao
|
||||
abstract fun remoteKeysDao(): RemoteKeysDao
|
||||
|
||||
companion object {
|
||||
private const val DB_NAME: String = "pmy-dbbbb4"
|
||||
|
||||
@Volatile
|
||||
private var INSTANCE: AppDatabase? = null
|
||||
|
||||
private suspend fun populateDatabase() {
|
||||
INSTANCE?.let { database ->
|
||||
// Days
|
||||
val dayDao = database.dayDao()
|
||||
val day1 = DayOfWeek(1, "Понедельник")
|
||||
val day2 = DayOfWeek(2, "Вторник")
|
||||
val day3 = DayOfWeek(3, "Среда")
|
||||
val day4 = DayOfWeek(4, "Четверг")
|
||||
val day5 = DayOfWeek(5, "Пятница")
|
||||
val day6 = DayOfWeek(6, "Суббота")
|
||||
val day7 = DayOfWeek(7, "Воскресенье")
|
||||
dayDao.insert(day1)
|
||||
dayDao.insert(day2)
|
||||
dayDao.insert(day3)
|
||||
dayDao.insert(day4)
|
||||
dayDao.insert(day5)
|
||||
dayDao.insert(day6)
|
||||
dayDao.insert(day7)
|
||||
// Direction
|
||||
val directionDao = database.directionDao()
|
||||
val direction1 = Direction(1, "Contemporary")
|
||||
val direction2 = Direction(2, "K-pop")
|
||||
val direction3 = Direction(3, "House")
|
||||
val direction4 = Direction(4, "BreakDance")
|
||||
val direction5 = Direction(5, "Dancehall")
|
||||
val direction6 = Direction(6, "Jazz-funk")
|
||||
directionDao.insert(direction1)
|
||||
directionDao.insert(direction2)
|
||||
directionDao.insert(direction3)
|
||||
directionDao.insert(direction4)
|
||||
directionDao.insert(direction5)
|
||||
directionDao.insert(direction6)
|
||||
// Lessons
|
||||
val lessonDao = database.lessonDao()
|
||||
val lesson1 = Lesson(1, "Anna", "9.00", 1, 1, 1)
|
||||
val lesson2 = Lesson(2, "Elena", "10.00", 2, 1, 2)
|
||||
val lesson3 = Lesson(3, "Anastasia", "18.00", 3, 2, 3)
|
||||
val lesson4 = Lesson(4, "Vika", "9.00", 4, 3, 4)
|
||||
val lesson5 = Lesson(5, "Tatyana", "11.00", 3, 5, 6)
|
||||
lessonDao.insert(lesson1)
|
||||
lessonDao.insert(lesson2)
|
||||
lessonDao.insert(lesson3)
|
||||
lessonDao.insert(lesson4)
|
||||
lessonDao.insert(lesson5)
|
||||
//users
|
||||
val userDao = database.userDao()
|
||||
val user1 = User(1, "user1", "1234", "FIO", RoleEnum.Admin, 1)
|
||||
val user2 = User(2, "user2", "5678", "FIO1", RoleEnum.User, 1)
|
||||
userDao.insert(user1)
|
||||
userDao.insert(user2)
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.example.myapplication.dataBase.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface DayDao {
|
||||
@Query("select * from days")
|
||||
suspend fun getAll(): List<DayOfWeek>
|
||||
@Query("select * from days where days.uid = :uid")
|
||||
fun getDayById(uid: Int): Flow<DayOfWeek>
|
||||
@Insert
|
||||
suspend fun insert(day: DayOfWeek)
|
||||
@Update
|
||||
suspend fun update(day: DayOfWeek)
|
||||
@Delete
|
||||
suspend fun delete(day: DayOfWeek)
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.example.myapplication.dataBase.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.example.myapplication.dataBase.model.Direction
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface DirectionDao {
|
||||
@Query("select * from directions")
|
||||
suspend fun getAll(): List<Direction>
|
||||
@Query("select * from directions where directions.uid = :uid")
|
||||
fun getDirectionById(uid: Int): Flow<Direction>
|
||||
@Insert
|
||||
suspend fun insert(direction: Direction)
|
||||
@Update
|
||||
suspend fun update(direction: Direction)
|
||||
@Delete
|
||||
suspend fun delete(direction: Direction)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.example.myapplication.dataBase.dao
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface LessonDao {
|
||||
@Query("select * from lessons")
|
||||
fun getAll(): PagingSource<Int, Lesson>
|
||||
@Query("select * from lessons where lessons.uid = :uid")
|
||||
fun getLessonByUid(uid: Int): Flow<Lesson>
|
||||
@Insert
|
||||
suspend fun insert(vararg lesson: Lesson)
|
||||
@Update
|
||||
suspend fun update(lesson: Lesson)
|
||||
@Delete
|
||||
suspend fun delete(lesson: Lesson)
|
||||
|
||||
@Query("DELETE FROM lessons")
|
||||
suspend fun deleteAll()
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.example.myapplication.dataBase.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface UserDao {
|
||||
@Query("select * from users")
|
||||
suspend fun getAll(): List<User>
|
||||
@Query("select * from users where users.uid = :uid")
|
||||
fun getUserById(uid: Int?): Flow<User>
|
||||
@Insert
|
||||
suspend fun insert(user: User)
|
||||
@Update
|
||||
suspend fun update(user: User)
|
||||
@Delete
|
||||
suspend fun delete(user: User)
|
||||
@Query("SELECT * FROM users WHERE user_name = :email")
|
||||
suspend fun getUserByLogin(email: String): User
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.example.myapplication.dataBase.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "days")
|
||||
data class DayOfWeek(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int = 0,
|
||||
@ColumnInfo(name = "day_name")
|
||||
val dayName: String
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as DayOfWeek
|
||||
if (uid != other.uid) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return uid ?: -1
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DEMO_DAY = DayOfWeek(
|
||||
0,
|
||||
"Понедельник"
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.example.myapplication.dataBase.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "directions")
|
||||
data class Direction(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int = 0,
|
||||
@ColumnInfo(name = "direction_name")
|
||||
val directionName: String
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as Direction
|
||||
if (uid != other.uid) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return uid ?: -1
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DEMO_DIRECTION = Direction(
|
||||
0,
|
||||
"K-pop"
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package com.example.myapplication.dataBase.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(
|
||||
tableName = "lessons", foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = DayOfWeek::class,
|
||||
parentColumns = ["uid"],
|
||||
childColumns = ["day_id"],
|
||||
onDelete = ForeignKey.RESTRICT,
|
||||
onUpdate = ForeignKey.RESTRICT
|
||||
),
|
||||
ForeignKey(
|
||||
entity = Direction::class,
|
||||
parentColumns = ["uid"],
|
||||
childColumns = ["direction_id"],
|
||||
onDelete = ForeignKey.RESTRICT,
|
||||
onUpdate = ForeignKey.RESTRICT
|
||||
)
|
||||
]
|
||||
)
|
||||
data class Lesson(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int = 0,
|
||||
@ColumnInfo(name = "teacher")
|
||||
val teacher: String,
|
||||
@ColumnInfo(name = "time")
|
||||
val time: String,
|
||||
@ColumnInfo(name = "classNumber")
|
||||
val classNumber: Int,
|
||||
@ColumnInfo(name = "day_id", index = true)
|
||||
val dayOfWeekId: Int,
|
||||
@ColumnInfo(name = "direction_id", index = true)
|
||||
val directionId: Int
|
||||
) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as Lesson
|
||||
if (uid != other.uid) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return uid ?: -1
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getLesson(index: Int = 0): Lesson {
|
||||
return Lesson(
|
||||
index,
|
||||
"teacher",
|
||||
"9.00",
|
||||
1,
|
||||
1,
|
||||
1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.example.myapplication.dataBase.model
|
||||
|
||||
enum class RoleEnum {
|
||||
Admin,
|
||||
User
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.example.myapplication.dataBase.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "users", foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Lesson::class,
|
||||
parentColumns = ["uid"],
|
||||
childColumns = ["lesson_id"],
|
||||
onDelete = ForeignKey.NO_ACTION,
|
||||
onUpdate = ForeignKey.NO_ACTION
|
||||
)])
|
||||
data class User(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val uid: Int,
|
||||
@ColumnInfo(name = "user_name")
|
||||
var userName: String,
|
||||
@ColumnInfo(name = "user_password")
|
||||
var password: String,
|
||||
@ColumnInfo(name = "user_fio")
|
||||
var fio: String,
|
||||
@ColumnInfo(name = "role")
|
||||
val role: RoleEnum,
|
||||
@ColumnInfo(name = "lesson_id", index = true)
|
||||
val lessonId: Int?
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as User
|
||||
if (uid != other.uid) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return uid?: -1
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getUser(index: Int = 0): User {
|
||||
return User(
|
||||
index,
|
||||
"useruseruser",
|
||||
"user",
|
||||
"useeeeer",
|
||||
RoleEnum.User,
|
||||
1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.example.myapplication.dataBase.remotekeys.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.example.myapplication.dataBase.remotekeys.model.RemoteKeyType
|
||||
import com.example.myapplication.dataBase.remotekeys.model.RemoteKeys
|
||||
|
||||
@Dao
|
||||
interface RemoteKeysDao {
|
||||
@Query("SELECT * FROM remote_keys WHERE entityId = :entityId AND type = :type")
|
||||
suspend fun getRemoteKeys(entityId: Int, type: RemoteKeyType): RemoteKeys?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertAll(remoteKey: List<RemoteKeys>)
|
||||
|
||||
@Query("DELETE FROM remote_keys WHERE type = :type")
|
||||
suspend fun clearRemoteKeys(type: RemoteKeyType)
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.example.myapplication.dataBase.remotekeys.model
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import androidx.room.TypeConverter
|
||||
import androidx.room.TypeConverters
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
|
||||
enum class RemoteKeyType(private val type: String) {
|
||||
LESSON(Lesson::class.simpleName ?: "Lesson");
|
||||
|
||||
@TypeConverter
|
||||
fun toRemoteKeyType(value: String) = RemoteKeyType.values().first { it.type == value }
|
||||
|
||||
@TypeConverter
|
||||
fun fromRemoteKeyType(value: RemoteKeyType) = value.type
|
||||
}
|
||||
|
||||
@Entity(tableName = "remote_keys")
|
||||
data class RemoteKeys(
|
||||
@PrimaryKey val entityId: Int,
|
||||
@TypeConverters(RemoteKeyType::class)
|
||||
val type: RemoteKeyType,
|
||||
val prevKey: Int?,
|
||||
val nextKey: Int?
|
||||
)
|
@ -0,0 +1,16 @@
|
||||
package com.example.myapplication.dataBase.remotekeys.repository
|
||||
|
||||
import com.example.myapplication.dataBase.remotekeys.dao.RemoteKeysDao
|
||||
import com.example.myapplication.dataBase.remotekeys.model.RemoteKeyType
|
||||
import com.example.myapplication.dataBase.remotekeys.model.RemoteKeys
|
||||
|
||||
class OfflineRemoteKeyRepository(private val remoteKeysDao: RemoteKeysDao) : RemoteKeyRepository {
|
||||
override suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType) =
|
||||
remoteKeysDao.getRemoteKeys(id, type)
|
||||
|
||||
override suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>) =
|
||||
remoteKeysDao.insertAll(remoteKeys)
|
||||
|
||||
override suspend fun deleteRemoteKey(type: RemoteKeyType) =
|
||||
remoteKeysDao.clearRemoteKeys(type)
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.example.myapplication.dataBase.remotekeys.repository
|
||||
|
||||
import com.example.myapplication.dataBase.remotekeys.model.RemoteKeyType
|
||||
import com.example.myapplication.dataBase.remotekeys.model.RemoteKeys
|
||||
|
||||
interface RemoteKeyRepository {
|
||||
suspend fun getAllRemoteKeys(id: Int, type: RemoteKeyType): RemoteKeys?
|
||||
suspend fun createRemoteKeys(remoteKeys: List<RemoteKeys>)
|
||||
suspend fun deleteRemoteKey(type: RemoteKeyType)
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.example.myapplication.dataBase.repository
|
||||
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface DayOfWeekRepository {
|
||||
suspend fun getAllDays(): List<DayOfWeek>
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.example.myapplication.dataBase.repository
|
||||
|
||||
import com.example.myapplication.dataBase.model.Direction
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface DirectionRepository {
|
||||
suspend fun getAllDirections(): List<Direction>
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.example.myapplication.dataBase.repository
|
||||
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingSource
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface LessonRepository {
|
||||
suspend fun insertLesson(lesson: Lesson)
|
||||
suspend fun updateLesson(lesson: Lesson)
|
||||
suspend fun deleteLesson(lesson: Lesson)
|
||||
fun getAllLessons(): Flow<PagingData<Lesson>>
|
||||
suspend fun getLesson(uid: Int): Lesson
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.example.myapplication.dataBase.repository
|
||||
|
||||
import com.example.myapplication.dataBase.dao.DayDao
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class OfflineDayOfWeekRepository(private val dayDao: DayDao) : DayOfWeekRepository{
|
||||
override suspend fun getAllDays(): List<DayOfWeek> = dayDao.getAll()
|
||||
suspend fun createDayOfWeek(dayOfWeek: DayOfWeek) = dayDao.insert(dayOfWeek)
|
||||
suspend fun updateDayOfWeek(dayOfWeek: DayOfWeek) = dayDao.update(dayOfWeek)
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.example.myapplication.dataBase.repository
|
||||
|
||||
import com.example.myapplication.dataBase.dao.DirectionDao
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import com.example.myapplication.dataBase.model.Direction
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class OfflineDirectionRepository(private val directionDao: DirectionDao) : DirectionRepository {
|
||||
override suspend fun getAllDirections(): List<Direction> = directionDao.getAll()
|
||||
suspend fun createDirection(direction: Direction) = directionDao.insert(direction)
|
||||
suspend fun updateDirection(direction: Direction) = directionDao.update(direction)
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.example.myapplication.dataBase.repository
|
||||
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingSource
|
||||
import com.example.myapplication.dataBase.AppContainer
|
||||
import com.example.myapplication.dataBase.dao.LessonDao
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
class OfflineLessonRepository(private val lessonDao: LessonDao) : LessonRepository {
|
||||
override fun getAllLessons (): Flow<PagingData<Lesson>> = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = AppContainer.LIMIT,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = lessonDao::getAll
|
||||
).flow
|
||||
fun getAllLessonsPagingSource(): PagingSource<Int, Lesson> = lessonDao.getAll()
|
||||
override suspend fun insertLesson(lesson: Lesson) = lessonDao.insert(lesson)
|
||||
override suspend fun updateLesson(lesson: Lesson) = lessonDao.update(lesson)
|
||||
override suspend fun deleteLesson(lesson: Lesson) = lessonDao.delete(lesson)
|
||||
suspend fun clearLessons() = lessonDao.deleteAll()
|
||||
override suspend fun getLesson(uid: Int): Lesson = lessonDao.getLessonByUid(uid).first()
|
||||
|
||||
suspend fun insertLessons(lessons: List<Lesson>) =
|
||||
lessonDao.insert(*lessons.toTypedArray())
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.example.myapplication.dataBase.repository
|
||||
|
||||
import com.example.myapplication.dataBase.dao.UserDao
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
|
||||
override suspend fun createUser(user: User) = userDao.insert(user)
|
||||
|
||||
override suspend fun updateUser(user: User) = userDao.update(user)
|
||||
|
||||
override suspend fun deleteUser(user: User) = userDao.delete(user)
|
||||
|
||||
override suspend fun getUserById(uid: Int?): User = userDao.getUserById(uid).first()
|
||||
|
||||
override suspend fun getAllUsers(): List<User> = userDao.getAll()
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.example.myapplication.dataBase.repository
|
||||
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface UserRepository {
|
||||
suspend fun createUser(user: User)
|
||||
suspend fun updateUser(user: User)
|
||||
suspend fun deleteUser(user: User)
|
||||
suspend fun getUserById(uid: Int?): User?
|
||||
suspend fun getAllUsers(): List<User>
|
||||
}
|
67
app/src/main/java/com/example/myapplication/ui/About.kt
Normal file
@ -0,0 +1,67 @@
|
||||
package com.example.myapplication.ui
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.widget.TextView
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
|
||||
@Composable
|
||||
fun About() {
|
||||
val localContext = LocalContext.current
|
||||
val aboutText = localContext.resources.getText(R.string.about_text)
|
||||
|
||||
val urlOnClick = {
|
||||
val openURL = Intent(Intent.ACTION_VIEW)
|
||||
openURL.data = Uri.parse("https://vk.com/id204968285")
|
||||
localContext.startActivity(openURL)
|
||||
}
|
||||
|
||||
Column(Modifier.padding(top = 70.dp)) {
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = urlOnClick).padding(start = 70.dp),
|
||||
factory = { context -> TextView(context) },
|
||||
update = { it.text = aboutText }
|
||||
)
|
||||
Spacer(Modifier.padding(bottom = 10.dp))
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.img_8),
|
||||
modifier = Modifier
|
||||
.size(400.dp) // Задайте требуемый размер картинке здесь
|
||||
.padding(19.dp), // Добавьте отступы, если необходимо,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun AboutPreview() {
|
||||
PmudemoTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
About()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.example.myapplication.ui
|
||||
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.createSavedStateHandle
|
||||
import androidx.lifecycle.viewmodel.CreationExtras
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.example.myapplication.LessonApplication
|
||||
import com.example.myapplication.ui.edit.DayDropDownViewModel
|
||||
import com.example.myapplication.ui.edit.DirectionDropDownViewModel
|
||||
import com.example.myapplication.ui.edit.LessonEditViewModel
|
||||
import com.example.myapplication.ui.lesson.LessonListViewModel
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
import com.example.myapplication.ui.user.EntryViewModel
|
||||
import com.example.myapplication.ui.user.RegisterViewModel
|
||||
|
||||
object AppViewModelProvider {
|
||||
val Factory = viewModelFactory {
|
||||
initializer {
|
||||
LessonListViewModel(lessonApplication().container.lessonRestRepository)
|
||||
}
|
||||
initializer {
|
||||
LessonEditViewModel(
|
||||
this.createSavedStateHandle(),
|
||||
lessonApplication().container.lessonRestRepository
|
||||
)
|
||||
}
|
||||
initializer {
|
||||
DayDropDownViewModel(lessonApplication().container.dayRestRepository)
|
||||
}
|
||||
initializer {
|
||||
DirectionDropDownViewModel(lessonApplication().container.directionRestRepository)
|
||||
}
|
||||
initializer {
|
||||
EntryViewModel(lessonApplication().container.userRestRepository)
|
||||
}
|
||||
initializer {
|
||||
RegisterViewModel(lessonApplication().container.userRestRepository)
|
||||
}
|
||||
initializer {
|
||||
CurrentUserViewModel(lessonApplication().container.userRestRepository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun CreationExtras.lessonApplication(): LessonApplication =
|
||||
(this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as LessonApplication)
|
@ -0,0 +1,48 @@
|
||||
package com.example.myapplication.ui.edit
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import com.example.myapplication.dataBase.repository.DayOfWeekRepository
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class DayDropDownViewModel(
|
||||
private val dayOfWeekRepository: DayOfWeekRepository
|
||||
) : ViewModel() {
|
||||
var daysListUiState by mutableStateOf(DayOfWeeksListUiState())
|
||||
private set
|
||||
|
||||
var dayOfWeekUiState by mutableStateOf(DayOfWeekUiState())
|
||||
private set
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
daysListUiState = DayOfWeeksListUiState(dayOfWeekRepository.getAllDays())
|
||||
}
|
||||
}
|
||||
|
||||
fun setCurrentDayOfWeek(dayOfWeekId: Int) {
|
||||
val dayOfWeek: DayOfWeek? =
|
||||
daysListUiState.dayOfWeekList.firstOrNull { dayOfWeek -> dayOfWeek.uid == dayOfWeekId }
|
||||
dayOfWeek?.let { updateUiState(it) }
|
||||
}
|
||||
|
||||
fun updateUiState(dayOfWeek: DayOfWeek) {
|
||||
dayOfWeekUiState = DayOfWeekUiState(
|
||||
dayOfWeek = dayOfWeek
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class DayOfWeeksListUiState(val dayOfWeekList: List<DayOfWeek> = listOf())
|
||||
|
||||
data class DayOfWeekUiState(
|
||||
val dayOfWeek: DayOfWeek? = null
|
||||
)
|
||||
|
||||
fun DayOfWeek.toUiState() = DayOfWeekUiState(dayOfWeek = DayOfWeek(uid = uid, dayName = dayName))
|
@ -0,0 +1,47 @@
|
||||
package com.example.myapplication.ui.edit
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.dataBase.model.Direction
|
||||
import com.example.myapplication.dataBase.repository.DirectionRepository
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class DirectionDropDownViewModel(
|
||||
private val directionRepository: DirectionRepository
|
||||
) : ViewModel() {
|
||||
var directionsListUiState by mutableStateOf(DirectionsListUiState())
|
||||
private set
|
||||
|
||||
var directionUiState by mutableStateOf(DirectionUiState())
|
||||
private set
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
directionsListUiState = DirectionsListUiState(directionRepository.getAllDirections())
|
||||
}
|
||||
}
|
||||
|
||||
fun setCurrentDirection(directionId: Int) {
|
||||
val direction: Direction? =
|
||||
directionsListUiState.directionList.firstOrNull { direction -> direction.uid == directionId }
|
||||
direction?.let { updateUiState(it) }
|
||||
}
|
||||
|
||||
fun updateUiState(direction: Direction) {
|
||||
directionUiState = DirectionUiState(
|
||||
direction = direction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class DirectionsListUiState(val directionList: List<Direction> = listOf())
|
||||
|
||||
data class DirectionUiState(
|
||||
val direction: Direction? = null
|
||||
)
|
||||
|
||||
fun Direction.toUiState() = DirectionUiState(direction = Direction(uid = uid, directionName = directionName))
|
@ -0,0 +1,262 @@
|
||||
package com.example.myapplication.ui.edit
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import com.example.myapplication.dataBase.model.Direction
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import com.example.myapplication.dataBase.model.RoleEnum
|
||||
import com.example.myapplication.ui.AppViewModelProvider
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun LessonEdit(
|
||||
navController: NavController,
|
||||
viewModel: LessonEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
directionViewModel: DirectionDropDownViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
dayViewModel: DayDropDownViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
directionViewModel.setCurrentDirection(viewModel.lessonUiState.lessonDetails.directionId)
|
||||
dayViewModel.setCurrentDayOfWeek(viewModel.lessonUiState.lessonDetails.dayOfWeekId)
|
||||
var getUser by remember { mutableStateOf(currentUserViewModel.user) }
|
||||
LessonEdit(
|
||||
lessonUiState = viewModel.lessonUiState,
|
||||
directionUiState = directionViewModel.directionUiState,
|
||||
directionsListUiState = directionViewModel.directionsListUiState,
|
||||
|
||||
daysUiState = dayViewModel.dayOfWeekUiState,
|
||||
daysListUiState = dayViewModel.daysListUiState,
|
||||
onClick = {
|
||||
if (getUser?.role == RoleEnum.Admin) {
|
||||
coroutineScope.launch {
|
||||
viewModel.saveLesson()
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
},
|
||||
onUpdate = viewModel::updateUiState,
|
||||
onDirectionUpdate = directionViewModel::updateUiState,
|
||||
onDayUpdate = dayViewModel::updateUiState
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun DirectionDropDown(
|
||||
directionUiState: DirectionUiState,
|
||||
directionsListUiState: DirectionsListUiState,
|
||||
onDirectionUpdate: (Direction) -> Unit
|
||||
) {
|
||||
var expanded: Boolean by remember { mutableStateOf(false) }
|
||||
ExposedDropdownMenuBox(
|
||||
modifier = Modifier
|
||||
.padding(top = 7.dp),
|
||||
expanded = expanded,
|
||||
onExpandedChange = {
|
||||
expanded = !expanded
|
||||
}
|
||||
) {
|
||||
TextField(
|
||||
value = directionUiState.direction?.directionName
|
||||
?: stringResource(id = R.string.lesson_direction),
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
trailingIcon = {
|
||||
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.menuAnchor()
|
||||
)
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
modifier = Modifier
|
||||
.background(Color.White)
|
||||
.exposedDropdownSize()
|
||||
) {
|
||||
directionsListUiState.directionList.forEach { direction ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(text = direction.directionName)
|
||||
},
|
||||
onClick = {
|
||||
onDirectionUpdate(direction)
|
||||
expanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun DayDropDown(
|
||||
daysUiState: DayOfWeekUiState,
|
||||
daysListUiState: DayOfWeeksListUiState,
|
||||
onDayUpdate: (DayOfWeek) -> Unit
|
||||
) {
|
||||
var expanded: Boolean by remember { mutableStateOf(false) }
|
||||
ExposedDropdownMenuBox(
|
||||
modifier = Modifier
|
||||
.padding(top = 7.dp),
|
||||
expanded = expanded,
|
||||
onExpandedChange = {
|
||||
expanded = !expanded
|
||||
}
|
||||
) {
|
||||
TextField(
|
||||
value = daysUiState.dayOfWeek?.dayName
|
||||
?: stringResource(id = R.string.lesson_day),
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
trailingIcon = {
|
||||
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.menuAnchor()
|
||||
)
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
modifier = Modifier
|
||||
.background(Color.White)
|
||||
.exposedDropdownSize()
|
||||
) {
|
||||
daysListUiState.dayOfWeekList.forEach { dayOfWeek ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(text = dayOfWeek.dayName)
|
||||
},
|
||||
onClick = {
|
||||
onDayUpdate(dayOfWeek)
|
||||
expanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun LessonEdit(
|
||||
lessonUiState: LessonUiState,
|
||||
directionUiState: DirectionUiState,
|
||||
directionsListUiState: DirectionsListUiState,
|
||||
daysUiState: DayOfWeekUiState,
|
||||
daysListUiState: DayOfWeeksListUiState,
|
||||
onClick: () -> Unit,
|
||||
onUpdate: (LessonDetails) -> Unit,
|
||||
onDirectionUpdate: (Direction) -> Unit,
|
||||
onDayUpdate: (DayOfWeek) -> Unit
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp)
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = lessonUiState.lessonDetails.time,
|
||||
onValueChange = { onUpdate(lessonUiState.lessonDetails.copy(time = it)) },
|
||||
label = { Text(stringResource(id = R.string.lesson_TimeDate)) },
|
||||
singleLine = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = lessonUiState.lessonDetails.teacher,
|
||||
onValueChange = { onUpdate(lessonUiState.lessonDetails.copy(teacher = it)) },
|
||||
label = { Text(stringResource(id = R.string.lesson_teacher)) },
|
||||
singleLine = true
|
||||
)
|
||||
DirectionDropDown(
|
||||
directionUiState = directionUiState,
|
||||
directionsListUiState = directionsListUiState,
|
||||
onDirectionUpdate = {
|
||||
onUpdate(lessonUiState.lessonDetails.copy(directionId = it.uid))
|
||||
onDirectionUpdate(it)
|
||||
}
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = lessonUiState.lessonDetails.classNumber.toString(),
|
||||
onValueChange = { onUpdate(lessonUiState.lessonDetails.copy(classNumber = it.toIntOrNull() ?: 0)) },
|
||||
label = { Text(stringResource(id = R.string.lesson_classNumber)) },
|
||||
singleLine = true
|
||||
)
|
||||
DayDropDown(
|
||||
daysUiState = daysUiState,
|
||||
daysListUiState = daysListUiState,
|
||||
onDayUpdate = {
|
||||
onUpdate(lessonUiState.lessonDetails.copy(dayOfWeekId = it.uid))
|
||||
onDayUpdate(it)
|
||||
}
|
||||
)
|
||||
Button(
|
||||
onClick = onClick,
|
||||
enabled = lessonUiState.isEntryValid,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = stringResource(R.string.lesson_save_button))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun LessonEditPreview() {
|
||||
PmudemoTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
LessonEdit(
|
||||
lessonUiState = Lesson.getLesson().toUiState(true),
|
||||
daysUiState = DayOfWeek.DEMO_DAY.toUiState(),
|
||||
directionUiState = Direction.DEMO_DIRECTION.toUiState(),
|
||||
directionsListUiState = DirectionsListUiState(listOf()),
|
||||
daysListUiState = DayOfWeeksListUiState(listOf()),
|
||||
onClick = {},
|
||||
onUpdate = {},
|
||||
onDirectionUpdate = {},
|
||||
onDayUpdate = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package com.example.myapplication.ui.edit
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import com.example.myapplication.dataBase.repository.LessonRepository
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LessonEditViewModel(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val lessonRepository: LessonRepository
|
||||
) : ViewModel() {
|
||||
|
||||
var lessonUiState by mutableStateOf(LessonUiState())
|
||||
private set
|
||||
|
||||
private val lessonUid: Int = checkNotNull(savedStateHandle["id"])
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
if (lessonUid > 0) {
|
||||
lessonUiState = lessonRepository.getLesson(lessonUid)
|
||||
.toUiState(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateUiState(lessonDetails: LessonDetails) {
|
||||
lessonUiState = LessonUiState(
|
||||
lessonDetails = lessonDetails,
|
||||
isEntryValid = validateInput(lessonDetails)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun saveLesson() {
|
||||
if (validateInput()) {
|
||||
if (lessonUid > 0) {
|
||||
lessonRepository.updateLesson(lessonUiState.lessonDetails.toLesson(lessonUid))
|
||||
} else {
|
||||
lessonRepository.insertLesson(lessonUiState.lessonDetails.toLesson())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateInput(uiState: LessonDetails = lessonUiState.lessonDetails): Boolean {
|
||||
return with(uiState) {
|
||||
teacher.isNotBlank()
|
||||
&& time.isNotBlank()
|
||||
&& classNumber > 0
|
||||
&& directionId > 0
|
||||
&& dayOfWeekId > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class LessonUiState(
|
||||
val lessonDetails: LessonDetails = LessonDetails(),
|
||||
val isEntryValid: Boolean = false
|
||||
)
|
||||
|
||||
data class LessonDetails(
|
||||
val teacher: String = "",
|
||||
val time: String = "",
|
||||
val classNumber: Int = 0,
|
||||
val directionId: Int = 0,
|
||||
val dayOfWeekId: Int = 0
|
||||
)
|
||||
|
||||
fun LessonDetails.toLesson(uid: Int = 0): Lesson = Lesson(
|
||||
uid = uid,
|
||||
teacher = teacher,
|
||||
time = time,
|
||||
classNumber = classNumber,
|
||||
directionId = directionId,
|
||||
dayOfWeekId = dayOfWeekId
|
||||
)
|
||||
|
||||
fun Lesson.toDetails(): LessonDetails = LessonDetails(
|
||||
teacher = teacher,
|
||||
time = time,
|
||||
classNumber = classNumber,
|
||||
directionId = directionId,
|
||||
dayOfWeekId = dayOfWeekId
|
||||
)
|
||||
|
||||
fun Lesson.toUiState(isEntryValid: Boolean = false): LessonUiState = LessonUiState(
|
||||
lessonDetails = this.toDetails(),
|
||||
isEntryValid = isEntryValid
|
||||
)
|
@ -0,0 +1,121 @@
|
||||
package com.example.myapplication.ui.edit
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.dataBase.model.DayOfWeek
|
||||
import com.example.myapplication.dataBase.model.Direction
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import com.example.myapplication.dataBase.model.RoleEnum
|
||||
import com.example.myapplication.ui.AppViewModelProvider
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun LessonRecord(
|
||||
navController: NavController,
|
||||
viewModel: LessonEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
directionViewModel: DirectionDropDownViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
directionViewModel.setCurrentDirection(viewModel.lessonUiState.lessonDetails.directionId)
|
||||
var getUser by remember { mutableStateOf(currentUserViewModel.user) }
|
||||
LessonEdit(
|
||||
lessonUiState = viewModel.lessonUiState,
|
||||
directionUiState = directionViewModel.directionUiState,
|
||||
onClick = {
|
||||
if (getUser?.role == RoleEnum.Admin) {
|
||||
coroutineScope.launch {
|
||||
viewModel.saveLesson()
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
},
|
||||
onUpdate = viewModel::updateUiState
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun LessonEdit(
|
||||
lessonUiState: LessonUiState,
|
||||
directionUiState: DirectionUiState,
|
||||
onClick: () -> Unit,
|
||||
onUpdate: (LessonDetails) -> Unit
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp)
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = lessonUiState.lessonDetails.time,
|
||||
onValueChange = { onUpdate(lessonUiState.lessonDetails.copy(time = it)) },
|
||||
label = { Text(stringResource(id = R.string.lesson_TimeDate)) },
|
||||
singleLine = true,
|
||||
readOnly = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = lessonUiState.lessonDetails.teacher,
|
||||
onValueChange = { onUpdate(lessonUiState.lessonDetails.copy(teacher = it)) },
|
||||
label = { Text(stringResource(id = R.string.lesson_teacher)) },
|
||||
singleLine = true,
|
||||
readOnly = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = directionUiState.direction?.directionName
|
||||
?: stringResource(id = R.string.lesson_direction),
|
||||
label = { Text(stringResource(id = R.string.lesson_direction)) },
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = lessonUiState.lessonDetails.classNumber.toString(),
|
||||
onValueChange = { onUpdate(lessonUiState.lessonDetails.copy(classNumber = it.toIntOrNull() ?: 0)) },
|
||||
label = { Text(stringResource(id = R.string.lesson_classNumber)) },
|
||||
singleLine = true,
|
||||
readOnly = true
|
||||
)
|
||||
Button(
|
||||
onClick = onClick,
|
||||
enabled = lessonUiState.isEntryValid,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = stringResource(R.string.lesson_record_button))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,563 @@
|
||||
package com.example.myapplication.ui.lesson
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.DismissDirection
|
||||
import androidx.compose.material3.DismissState
|
||||
import androidx.compose.material3.DismissValue
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.SwipeToDismiss
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberDismissState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import kotlinx.coroutines.launch
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import androidx.paging.compose.itemKey
|
||||
import com.example.myapplication.Enter
|
||||
import com.example.myapplication.Graph.BottomBarScreen
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import com.example.myapplication.dataBase.model.RoleEnum
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import com.example.myapplication.ui.AppViewModelProvider
|
||||
import com.example.myapplication.ui.navigation.Screen
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
import com.example.myapplication.ui.user.CurrentUserViewModel
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun LessonList(
|
||||
navController: NavController,
|
||||
viewModel: LessonListViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val lessonListUiState = viewModel.lessonListUiState.collectAsLazyPagingItems()
|
||||
var getUser by remember { mutableStateOf(currentUserViewModel.user) }
|
||||
Log.d("List", "getUser: $getUser")
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val state = rememberScrollState()
|
||||
LaunchedEffect(Unit) { state.animateScrollTo(500) }
|
||||
Scaffold(
|
||||
topBar = {},
|
||||
floatingActionButton = {
|
||||
if (getUser?.role == RoleEnum.Admin) {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
val route = Screen.LessonEdit.route.replace("{id}", 0.toString())
|
||||
navController.navigate(route)
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(bottom = 80.dp) // Добавляем отступ сверху и снизу
|
||||
) {
|
||||
Icon(Icons.Filled.Add, "Добавить")
|
||||
}
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
LessonList(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
lessonList = lessonListUiState,
|
||||
onClick = { uid: Int ->
|
||||
if (getUser?.role == RoleEnum.Admin) {
|
||||
val route = BottomBarScreen.LessonEdit.route.replace("{id}", uid.toString())
|
||||
navController.navigate(route)
|
||||
} else{
|
||||
val route = BottomBarScreen.LessonRecord.route.replace("{id}", uid.toString())
|
||||
navController.navigate(route)
|
||||
}
|
||||
}
|
||||
){ lesson: Lesson ->
|
||||
if (getUser?.role == RoleEnum.Admin) {
|
||||
coroutineScope.launch {
|
||||
viewModel.deleteLesson(lesson)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DismissBackground(dismissState: DismissState) {
|
||||
val color = when (dismissState.dismissDirection) {
|
||||
DismissDirection.StartToEnd -> Color.Transparent
|
||||
DismissDirection.EndToStart -> Color(0xFFFF1744)
|
||||
null -> Color.Transparent
|
||||
}
|
||||
val direction = dismissState.dismissDirection
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(color)
|
||||
.padding(12.dp, 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
if (direction == DismissDirection.EndToStart) {
|
||||
Icon(
|
||||
Icons.Default.Delete,
|
||||
contentDescription = "delete",
|
||||
tint = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun SwipeToDelete(
|
||||
dismissState: DismissState,
|
||||
lesson: Lesson,
|
||||
onClick: (uid: Int) -> Unit
|
||||
) {
|
||||
SwipeToDismiss(
|
||||
modifier = Modifier.zIndex(1f),
|
||||
state = dismissState,
|
||||
directions = setOf(
|
||||
DismissDirection.EndToStart
|
||||
),
|
||||
background = {
|
||||
DismissBackground(dismissState)
|
||||
},
|
||||
dismissContent = {
|
||||
LessonListItem(lesson = lesson,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 7.dp)
|
||||
.clickable { onClick(lesson.uid) })
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun LessonList(
|
||||
modifier: Modifier = Modifier,
|
||||
lessonList: LazyPagingItems<Lesson>,
|
||||
onClick: (uid: Int) -> Unit,
|
||||
onSwipe: (lesson: Lesson) -> Unit
|
||||
) {
|
||||
val refreshScope = rememberCoroutineScope()
|
||||
var refreshing by remember { mutableStateOf(false) }
|
||||
fun refresh() = refreshScope.launch {
|
||||
refreshing = true
|
||||
lessonList.refresh()
|
||||
refreshing = false
|
||||
}
|
||||
Column(
|
||||
modifier = modifier
|
||||
) {
|
||||
if (lessonList.itemSnapshotList.isEmpty()) {
|
||||
Text(
|
||||
text = stringResource(R.string.lesson_empty_description),
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
} else {
|
||||
val filteredLessons = lessonList.itemSnapshotList.filter { it?.dayOfWeekId == 1 }
|
||||
if (filteredLessons.isNotEmpty()) {
|
||||
Text(text = "Понедельник", style = TextStyle(fontSize = 24.sp), textAlign = TextAlign.Center)
|
||||
}
|
||||
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
|
||||
items(items = filteredLessons, key = { it?.uid ?: "" }) { lesson ->
|
||||
var show by remember { mutableStateOf(true) }
|
||||
val dismissState = rememberDismissState(
|
||||
confirmValueChange = {
|
||||
if (it == DismissValue.DismissedToStart ||
|
||||
it == DismissValue.DismissedToEnd
|
||||
) {
|
||||
show = false
|
||||
true
|
||||
} else false
|
||||
}, positionalThreshold = { 200.dp.toPx() }
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
show, exit = fadeOut(spring())
|
||||
) {
|
||||
if (lesson != null) {
|
||||
SwipeToDelete(
|
||||
dismissState = dismissState,
|
||||
lesson = lesson,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(show) {
|
||||
if (!show) {
|
||||
delay(800)
|
||||
if (lesson != null) {
|
||||
onSwipe(lesson)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val filteredLessons1 = lessonList.itemSnapshotList.filter { it?.dayOfWeekId == 2 }
|
||||
if (filteredLessons1.isNotEmpty()) {
|
||||
Text(text = "Вторник", style = TextStyle(fontSize = 24.sp))
|
||||
}
|
||||
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
|
||||
items(items = filteredLessons1, key = { it?.uid ?: "" }) { lesson ->
|
||||
var show by remember { mutableStateOf(true) }
|
||||
val dismissState = rememberDismissState(
|
||||
confirmValueChange = {
|
||||
if (it == DismissValue.DismissedToStart ||
|
||||
it == DismissValue.DismissedToEnd
|
||||
) {
|
||||
show = false
|
||||
true
|
||||
} else false
|
||||
}, positionalThreshold = { 200.dp.toPx() }
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
show, exit = fadeOut(spring())
|
||||
) {
|
||||
if (lesson != null) {
|
||||
SwipeToDelete(
|
||||
dismissState = dismissState,
|
||||
lesson = lesson,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(show) {
|
||||
if (!show) {
|
||||
delay(800)
|
||||
if (lesson != null) {
|
||||
onSwipe(lesson)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val filteredLessons2 = lessonList.itemSnapshotList.filter { it?.dayOfWeekId == 3 }
|
||||
if (filteredLessons2.isNotEmpty()) {
|
||||
Text(text = "Среда", style = TextStyle(fontSize = 24.sp))
|
||||
}
|
||||
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
|
||||
items(items = filteredLessons2, key = { it?.uid ?: "" }) { lesson ->
|
||||
var show by remember { mutableStateOf(true) }
|
||||
val dismissState = rememberDismissState(
|
||||
confirmValueChange = {
|
||||
if (it == DismissValue.DismissedToStart ||
|
||||
it == DismissValue.DismissedToEnd
|
||||
) {
|
||||
show = false
|
||||
true
|
||||
} else false
|
||||
}, positionalThreshold = { 200.dp.toPx() }
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
show, exit = fadeOut(spring())
|
||||
) {
|
||||
if (lesson != null) {
|
||||
SwipeToDelete(
|
||||
dismissState = dismissState,
|
||||
lesson = lesson,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(show) {
|
||||
if (!show) {
|
||||
delay(800)
|
||||
if (lesson != null) {
|
||||
onSwipe(lesson)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val filteredLessons3 = lessonList.itemSnapshotList.filter { it?.dayOfWeekId == 4 }
|
||||
if (filteredLessons3.isNotEmpty()) {
|
||||
Text(text = "Четверг", style = TextStyle(fontSize = 24.sp))
|
||||
}
|
||||
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
|
||||
items(items = filteredLessons3, key = { it?.uid ?: "" }) { lesson ->
|
||||
var show by remember { mutableStateOf(true) }
|
||||
val dismissState = rememberDismissState(
|
||||
confirmValueChange = {
|
||||
if (it == DismissValue.DismissedToStart ||
|
||||
it == DismissValue.DismissedToEnd
|
||||
) {
|
||||
show = false
|
||||
true
|
||||
} else false
|
||||
}, positionalThreshold = { 200.dp.toPx() }
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
show, exit = fadeOut(spring())
|
||||
) {
|
||||
if (lesson != null) {
|
||||
SwipeToDelete(
|
||||
dismissState = dismissState,
|
||||
lesson = lesson,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(show) {
|
||||
if (!show) {
|
||||
delay(800)
|
||||
if (lesson != null) {
|
||||
onSwipe(lesson)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val filteredLessons4 = lessonList.itemSnapshotList.filter { it?.dayOfWeekId == 5 }
|
||||
if (filteredLessons4.isNotEmpty()) {
|
||||
Text(text = "Пятница", style = TextStyle(fontSize = 24.sp))
|
||||
}
|
||||
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
|
||||
items(items = filteredLessons4, key = { it?.uid ?: "" }) { lesson ->
|
||||
var show by remember { mutableStateOf(true) }
|
||||
val dismissState = rememberDismissState(
|
||||
confirmValueChange = {
|
||||
if (it == DismissValue.DismissedToStart ||
|
||||
it == DismissValue.DismissedToEnd
|
||||
) {
|
||||
show = false
|
||||
true
|
||||
} else false
|
||||
}, positionalThreshold = { 200.dp.toPx() }
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
show, exit = fadeOut(spring())
|
||||
) {
|
||||
if (lesson != null) {
|
||||
SwipeToDelete(
|
||||
dismissState = dismissState,
|
||||
lesson = lesson,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(show) {
|
||||
if (!show) {
|
||||
delay(800)
|
||||
if (lesson != null) {
|
||||
onSwipe(lesson)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val filteredLessons5 = lessonList.itemSnapshotList.filter { it?.dayOfWeekId == 6 }
|
||||
if (filteredLessons5.isNotEmpty()) {
|
||||
Text(text = "Суббота", style = TextStyle(fontSize = 24.sp))
|
||||
}
|
||||
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
|
||||
items(items = filteredLessons5, key = { it?.uid ?: "" }) { lesson ->
|
||||
var show by remember { mutableStateOf(true) }
|
||||
val dismissState = rememberDismissState(
|
||||
confirmValueChange = {
|
||||
if (it == DismissValue.DismissedToStart ||
|
||||
it == DismissValue.DismissedToEnd
|
||||
) {
|
||||
show = false
|
||||
true
|
||||
} else false
|
||||
}, positionalThreshold = { 200.dp.toPx() }
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
show, exit = fadeOut(spring())
|
||||
) {
|
||||
if (lesson != null) {
|
||||
SwipeToDelete(
|
||||
dismissState = dismissState,
|
||||
lesson = lesson,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(show) {
|
||||
if (!show) {
|
||||
delay(800)
|
||||
if (lesson != null) {
|
||||
onSwipe(lesson)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val filteredLessons6 = lessonList.itemSnapshotList.filter { it?.dayOfWeekId == 7 }
|
||||
if (filteredLessons6.isNotEmpty()) {
|
||||
Text(text = "Воскресенье", style = TextStyle(fontSize = 24.sp))
|
||||
}
|
||||
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
|
||||
items(items = filteredLessons6, key = { it?.uid ?: "" }) { lesson ->
|
||||
var show by remember { mutableStateOf(true) }
|
||||
val dismissState = rememberDismissState(
|
||||
confirmValueChange = {
|
||||
if (it == DismissValue.DismissedToStart ||
|
||||
it == DismissValue.DismissedToEnd
|
||||
) {
|
||||
show = false
|
||||
true
|
||||
} else false
|
||||
}, positionalThreshold = { 200.dp.toPx() }
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
show, exit = fadeOut(spring())
|
||||
) {
|
||||
if (lesson != null) {
|
||||
SwipeToDelete(
|
||||
dismissState = dismissState,
|
||||
lesson = lesson,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(show) {
|
||||
if (!show) {
|
||||
delay(800)
|
||||
if (lesson != null) {
|
||||
onSwipe(lesson)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LessonListItem(
|
||||
lesson: Lesson, modifier: Modifier = Modifier
|
||||
) {
|
||||
var dir = ""
|
||||
if (lesson.directionId == 3) dir = "Contemporary"
|
||||
if (lesson.directionId == 1) dir = "K-pop"
|
||||
if (lesson.directionId == 2) dir = "House"
|
||||
if (lesson.directionId == 4) dir = "BreakDance"
|
||||
if (lesson.directionId == 6) dir = "Dancehall"
|
||||
if (lesson.directionId == 5) dir = "Jazz-funk"
|
||||
Card(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(0.dp),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier.align(CenterHorizontally)
|
||||
) {
|
||||
Text(
|
||||
text = String.format("%s %s %s", lesson.time, lesson.teacher, dir)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
//@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
//@Composable
|
||||
//fun LessonListPreview() {
|
||||
// PmudemoTheme {
|
||||
// Surface(
|
||||
// color = MaterialTheme.colorScheme.background
|
||||
// ) {
|
||||
// LessonList(
|
||||
// lessonList = (1..20).map { i -> Lesson.getLesson(i) },
|
||||
// onClick = {}
|
||||
// ) {}
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
//@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
//@Composable
|
||||
//fun LessonEmptyListPreview() {
|
||||
// PmudemoTheme {
|
||||
// Surface(
|
||||
// color = MaterialTheme.colorScheme.background
|
||||
// ) {
|
||||
// LessonList(
|
||||
// lessonList = listOf(),
|
||||
// onClick = {}
|
||||
// ) {}
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
@ -0,0 +1,60 @@
|
||||
package com.example.myapplication.ui.lesson
|
||||
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import com.example.myapplication.dataBase.AppDataContainer
|
||||
import com.example.myapplication.dataBase.model.Lesson
|
||||
import com.example.myapplication.dataBase.repository.LessonRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LessonListViewModel(
|
||||
private val lessonRepository: LessonRepository
|
||||
) : ViewModel() {
|
||||
|
||||
val lessonListUiState: Flow<PagingData<Lesson>> = lessonRepository.getAllLessons()
|
||||
|
||||
suspend fun deleteLesson(lesson: Lesson) {
|
||||
lessonRepository.deleteLesson(lesson)
|
||||
}
|
||||
}
|
||||
|
||||
//class LessonListViewModel(private val lessonRepository: LessonRepository): ViewModel() {
|
||||
// var teacher = mutableStateOf("")
|
||||
// val classNumber = mutableStateOf("")
|
||||
// val time = mutableStateOf("")
|
||||
// val directionId = mutableStateOf("")
|
||||
// val dayOfWeekId = mutableStateOf("")
|
||||
// val LessonList = lessonRepository.call().cachedIn(viewModelScope)
|
||||
// var lesson: Lesson? = null
|
||||
//
|
||||
// fun insert() = viewModelScope.launch {
|
||||
// val lesson = Lesson(
|
||||
// teacher = teacher.value,
|
||||
// classNumber = classNumber.value.toInt(),
|
||||
// time = time.value,
|
||||
// dayOfWeekId = dayOfWeekId.value.toInt(),
|
||||
// directionId = directionId.value.toInt()
|
||||
// )
|
||||
// lessonRepository.insertLesson(lesson)
|
||||
// }
|
||||
//
|
||||
// fun delete(lesson: Lesson) = viewModelScope.launch {
|
||||
// lessonRepository.deleteLesson(lesson)
|
||||
// }
|
||||
//
|
||||
// fun getLessonByUid(uid: Int) = viewModelScope.launch {
|
||||
// lessonRepository.getLessonByUid(uid)
|
||||
// }
|
||||
//
|
||||
// fun update(lesson: Lesson) = viewModelScope.launch {
|
||||
// lessonRepository.updateLesson(lesson)
|
||||
// }
|
||||
//}
|
@ -0,0 +1,170 @@
|
||||
package com.example.myapplication.ui.navigation
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.NavDestination.Companion.hierarchy
|
||||
import androidx.navigation.NavGraph.Companion.findStartDestination
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import com.example.myapplication.BrDance
|
||||
import com.example.myapplication.Contemp
|
||||
import com.example.myapplication.DirectionView
|
||||
import com.example.myapplication.Enter
|
||||
import com.example.myapplication.HomeView
|
||||
import com.example.myapplication.House
|
||||
import com.example.myapplication.Kpop
|
||||
import com.example.myapplication.Profile
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.Registration
|
||||
import com.example.myapplication.ui.About
|
||||
import com.example.myapplication.ui.edit.LessonEdit
|
||||
import com.example.myapplication.ui.lesson.LessonList
|
||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Topbar(
|
||||
navController: NavHostController,
|
||||
currentScreen: Screen?
|
||||
) {
|
||||
TopAppBar(
|
||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
titleContentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
),
|
||||
title = {
|
||||
Text(stringResource(currentScreen?.resourceId ?: R.string.app_name))
|
||||
},
|
||||
navigationIcon = {
|
||||
if (
|
||||
navController.previousBackStackEntry != null
|
||||
&& (currentScreen == null || !currentScreen.showInBottomBar)
|
||||
) {
|
||||
IconButton(onClick = { navController.navigateUp() }) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onPrimary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Navbar(
|
||||
navController: NavHostController,
|
||||
currentDestination: NavDestination?,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
NavigationBar(modifier) {
|
||||
Screen.bottomBarItems.forEach { screen ->
|
||||
NavigationBarItem(
|
||||
icon = { Icon(screen.icon, contentDescription = null) },
|
||||
label = { Text(stringResource(screen.resourceId)) },
|
||||
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
|
||||
onClick = {
|
||||
navController.navigate(screen.route) {
|
||||
popUpTo(navController.graph.findStartDestination().id) {
|
||||
saveState = true
|
||||
}
|
||||
launchSingleTop = true
|
||||
restoreState = true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Navhost(
|
||||
navController: NavHostController,
|
||||
innerPadding: PaddingValues, modifier:
|
||||
Modifier = Modifier
|
||||
) {
|
||||
NavHost(
|
||||
navController,
|
||||
startDestination = Screen.HomeView.route,
|
||||
modifier.padding(innerPadding)
|
||||
) {
|
||||
composable(Screen.LessonList.route) { LessonList(navController) }
|
||||
composable(Screen.About.route) { About() }
|
||||
composable(Screen.HomeView.route) { HomeView(navController) }
|
||||
composable(Screen.Registration.route) { Registration(navController) }
|
||||
composable(Screen.House.route) { House() }
|
||||
composable(Screen.Contemp.route) { Contemp() }
|
||||
composable(Screen.BrDance.route) { BrDance() }
|
||||
composable(Screen.Kpop.route) { Kpop() }
|
||||
composable(Screen.Enter.route) { Enter(navController) }
|
||||
composable(Screen.DirectionView.route) { DirectionView(navController) }
|
||||
composable(Screen.Profile.route) { Profile(navController) }
|
||||
composable(
|
||||
Screen.LessonEdit.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
) {
|
||||
LessonEdit(navController)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MainNavbar() {
|
||||
val navController = rememberNavController()
|
||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
val currentDestination = navBackStackEntry?.destination
|
||||
val currentScreen = currentDestination?.route?.let { Screen.getItem(it) }
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
Topbar(navController, currentScreen)
|
||||
},
|
||||
bottomBar = {
|
||||
if (currentScreen == null || currentScreen.showInBottomBar) {
|
||||
Navbar(navController, currentDestination)
|
||||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
Navhost(navController, innerPadding)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun MainNavbarPreview() {
|
||||
PmudemoTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
MainNavbar()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package com.example.myapplication.ui.navigation
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.DateRange
|
||||
import androidx.compose.material.icons.filled.Face
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material.icons.filled.List
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.example.myapplication.R
|
||||
|
||||
enum class Screen(
|
||||
val route: String,
|
||||
@StringRes val resourceId: Int,
|
||||
val icon: ImageVector = Icons.Filled.Favorite,
|
||||
val showInBottomBar: Boolean = true
|
||||
) {
|
||||
LessonList(
|
||||
"lesson-list", R.string.home_title, Icons.Filled.DateRange
|
||||
),
|
||||
About(
|
||||
"about", R.string.home_title, Icons.Filled.Info
|
||||
),
|
||||
Enter(
|
||||
"enter", R.string.home_title, Icons.Filled.Face
|
||||
),
|
||||
Registration(
|
||||
"registration", R.string.registration_header, showInBottomBar = false
|
||||
),
|
||||
DirectionView(
|
||||
"directionView", R.string.home_title, Icons.Filled.List
|
||||
),
|
||||
House(
|
||||
"house", R.string.house, showInBottomBar = false
|
||||
),
|
||||
Contemp(
|
||||
"contemp", R.string.contemp, showInBottomBar = false
|
||||
),
|
||||
BrDance(
|
||||
"brdance", R.string.brdance, showInBottomBar = false
|
||||
),
|
||||
Kpop(
|
||||
"kpop", R.string.kpop, showInBottomBar = false
|
||||
),
|
||||
HomeView(
|
||||
"homeView", R.string.home_title, Icons.Filled.Home
|
||||
),
|
||||
Profile(
|
||||
"profile", R.string.home_title, Icons.Filled.Person
|
||||
),
|
||||
LessonEdit(
|
||||
"lesson-edit/{id}", R.string.lesson_view_title, showInBottomBar = false
|
||||
);
|
||||
|
||||
companion object {
|
||||
val bottomBarItems = listOf(
|
||||
LessonList,
|
||||
DirectionView,
|
||||
HomeView,
|
||||
Enter,
|
||||
About
|
||||
)
|
||||
|
||||
fun getItem(route: String): Screen? {
|
||||
val findRoute = route.split("/").first()
|
||||
return values().find { value -> value.route.startsWith(findRoute) }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.example.myapplication.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val Purple80 = Color(0xFFD0BCFF)
|
||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||
val Pink80 = Color(0xFFEFB8C8)
|
||||
val Black = Color(0xFF000000)
|
||||
|
||||
val Purple40 = Color(0xFF6650a4)
|
||||
val PurpleGrey40 = Color(0xFF625b71)
|
||||
val Pink40 = Color(0xFF7D5260)
|
@ -0,0 +1,73 @@
|
||||
package com.example.myapplication.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.core.view.WindowCompat
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Black,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
|
||||
)
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Black,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
|
||||
/* Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.White,
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun PmudemoTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
val view = LocalView.current
|
||||
if (!view.isInEditMode) {
|
||||
SideEffect {
|
||||
val window = (view.context as Activity).window
|
||||
window.statusBarColor = colorScheme.primary.toArgb()
|
||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
|
||||
}
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
}
|
34
app/src/main/java/com/example/myapplication/ui/theme/Type.kt
Normal file
@ -0,0 +1,34 @@
|
||||
package com.example.myapplication.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
@ -0,0 +1,28 @@
|
||||
package com.example.myapplication.ui.user
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import com.example.myapplication.dataBase.repository.UserRepository
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CurrentUserViewModel(private val userRepository: UserRepository) : ViewModel(){
|
||||
val argument = mutableStateOf<String?>(null)
|
||||
private val userid = mutableStateOf<Int?>(null)
|
||||
var user by mutableStateOf<User?>(null)
|
||||
|
||||
fun setArgument(arg: String) {
|
||||
argument.value = arg
|
||||
userid.value = arg.toInt()
|
||||
viewModelScope.launch {
|
||||
user = userRepository.getUserById(userid.value)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateUser(user: User) {
|
||||
userRepository.updateUser(user)
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.example.myapplication.ui.user
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import com.example.myapplication.dataBase.repository.UserRepository
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class EntryViewModel(private val userRepository: UserRepository) : ViewModel() {
|
||||
|
||||
var userList by mutableStateOf<List<User>>(emptyList())
|
||||
fun setUserList() {
|
||||
viewModelScope.launch {
|
||||
userList=userRepository.getAllUsers()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.example.myapplication.ui.user
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.dataBase.model.User
|
||||
import com.example.myapplication.dataBase.repository.UserRepository
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class RegisterViewModel (private val userRepository: UserRepository) : ViewModel() {
|
||||
|
||||
private val _users = MutableLiveData<List<User>>()
|
||||
val users: LiveData<List<User>> get() = _users
|
||||
|
||||
fun setUserList() {
|
||||
viewModelScope.launch {
|
||||
_users.value = userRepository.getAllUsers()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun insertUser(user: User) {
|
||||
userRepository.createUser(user)
|
||||
}
|
||||
}
|
BIN
app/src/main/res/drawable/brdance.png
Normal file
After Width: | Height: | Size: 724 KiB |
BIN
app/src/main/res/drawable/brdance_button.png
Normal file
After Width: | Height: | Size: 114 KiB |
BIN
app/src/main/res/drawable/contemp.jpg
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
app/src/main/res/drawable/contemp_button.png
Normal file
After Width: | Height: | Size: 103 KiB |
BIN
app/src/main/res/drawable/dancehall_button.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
app/src/main/res/drawable/house.png
Normal file
After Width: | Height: | Size: 8.1 MiB |
BIN
app/src/main/res/drawable/house_button.png
Normal file
After Width: | Height: | Size: 108 KiB |
170
app/src/main/res/drawable/ic_launcher_background.xml
Normal 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>
|
30
app/src/main/res/drawable/ic_launcher_foreground.xml
Normal 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>
|
BIN
app/src/main/res/drawable/img_5.png
Normal file
After Width: | Height: | Size: 181 KiB |
BIN
app/src/main/res/drawable/img_7.png
Normal file
After Width: | Height: | Size: 281 KiB |
BIN
app/src/main/res/drawable/img_8.png
Normal file
After Width: | Height: | Size: 456 KiB |
BIN
app/src/main/res/drawable/jazz_button.png
Normal file
After Width: | Height: | Size: 97 KiB |
BIN
app/src/main/res/drawable/kpop.png
Normal file
After Width: | Height: | Size: 981 KiB |
BIN
app/src/main/res/drawable/kpop_button.png
Normal file
After Width: | Height: | Size: 89 KiB |
6
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal 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>
|
6
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal 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>
|
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
After Width: | Height: | Size: 2.8 KiB |