v1
This commit is contained in:
+15
@@ -0,0 +1,15 @@
|
|||||||
|
*.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
|
||||||
Generated
+3
@@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
Generated
+1
@@ -0,0 +1 @@
|
|||||||
|
SweetShopViki
|
||||||
Generated
+126
@@ -0,0 +1,126 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<JetCodeStyleSettings>
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
</JetCodeStyleSettings>
|
||||||
|
<ScalaCodeStyleSettings>
|
||||||
|
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
|
||||||
|
</ScalaCodeStyleSettings>
|
||||||
|
<codeStyleSettings language="XML">
|
||||||
|
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
|
</indentOptions>
|
||||||
|
<arrangement>
|
||||||
|
<rules>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>xmlns:android</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>xmlns:.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*:id</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*:name</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>name</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>style</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<rule>
|
||||||
|
<match>
|
||||||
|
<AND>
|
||||||
|
<NAME>.*</NAME>
|
||||||
|
<XML_ATTRIBUTE />
|
||||||
|
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||||
|
</AND>
|
||||||
|
</match>
|
||||||
|
<order>BY_NAME</order>
|
||||||
|
</rule>
|
||||||
|
</section>
|
||||||
|
</rules>
|
||||||
|
</arrangement>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="kotlin">
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
||||||
Generated
+5
@@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<bytecodeTargetLevel target="17" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+20
@@ -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>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="KotlinJpsPluginSettings">
|
||||||
|
<option name="version" value="1.9.10" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+9
@@ -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>
|
||||||
Generated
+6
@@ -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>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,115 @@
|
|||||||
|
plugins {
|
||||||
|
id("com.android.application")
|
||||||
|
id("org.jetbrains.kotlin.android")
|
||||||
|
id("com.google.gms.google-services")
|
||||||
|
id("com.google.devtools.ksp") version "1.9.10-1.0.13"
|
||||||
|
id("kotlin-kapt")
|
||||||
|
id("androidx.navigation.safeargs.kotlin")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.yaros.sweetshopviki"
|
||||||
|
compileSdk = 34
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId = "com.yaros.sweetshopviki"
|
||||||
|
minSdk = 26
|
||||||
|
targetSdk = 34
|
||||||
|
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_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(8)
|
||||||
|
}
|
||||||
|
buildFeatures {
|
||||||
|
compose = true
|
||||||
|
viewBinding = true
|
||||||
|
}
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion = "1.5.3"
|
||||||
|
}
|
||||||
|
packaging {
|
||||||
|
resources {
|
||||||
|
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(17))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
implementation("androidx.core:core-ktx:1.12.0")
|
||||||
|
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
|
||||||
|
implementation("androidx.activity:activity-compose:1.8.0")
|
||||||
|
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||||
|
implementation("androidx.compose.ui:ui")
|
||||||
|
implementation("androidx.compose.ui:ui-graphics")
|
||||||
|
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||||
|
implementation("androidx.compose.material3:material3")
|
||||||
|
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")
|
||||||
|
implementation("com.google.devtools.ksp:symbol-processing-api:1.9.10-1.0.13")
|
||||||
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
|
implementation("androidx.legacy:legacy-support-v4:1.0.0")
|
||||||
|
|
||||||
|
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2")
|
||||||
|
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
|
||||||
|
implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
|
||||||
|
implementation("androidx.navigation:navigation-ui-ktx:2.7.4")
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
|
||||||
|
|
||||||
|
implementation(platform("com.google.firebase:firebase-bom:32.5.0"))
|
||||||
|
implementation("com.google.firebase:firebase-auth-ktx")
|
||||||
|
implementation("com.firebaseui:firebase-ui-auth:7.2.0")
|
||||||
|
implementation("com.google.firebase:firebase-firestore-ktx")
|
||||||
|
implementation("com.google.firebase:firebase-analytics")
|
||||||
|
|
||||||
|
implementation("com.facebook.shimmer:shimmer:0.5.0")
|
||||||
|
implementation("com.squareup.picasso:picasso:2.71828")
|
||||||
|
implementation("com.github.Zhuinden:fragmentviewbindingdelegate-kt:1.0.2")
|
||||||
|
implementation("nl.joery.animatedbottombar:library:1.1.0")
|
||||||
|
implementation("com.github.Spikeysanju:MotionToast:1.4")
|
||||||
|
implementation("com.github.ibrahimsn98:SmoothBottomBar:1.7.9")
|
||||||
|
implementation("com.apachat:loadingbutton-android:1.0.11")
|
||||||
|
implementation("com.google.android.material:material:1.10.0")
|
||||||
|
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||||
|
|
||||||
|
implementation("com.google.code.gson:gson:2.9.1")
|
||||||
|
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||||
|
implementation("androidx.room:room-runtime:2.6.0")
|
||||||
|
implementation("androidx.room:room-ktx:2.6.0")
|
||||||
|
ksp("androidx.room:room-compiler:2.6.0")
|
||||||
|
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "196968989683",
|
||||||
|
"firebase_url": "https://sweetshopviki-default-rtdb.europe-west1.firebasedatabase.app",
|
||||||
|
"project_id": "sweetshopviki",
|
||||||
|
"storage_bucket": "sweetshopviki.appspot.com"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:196968989683:android:40a8cee7ccf184d17e0886",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.yaros.sweetshopviki"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyBO4bIOLwDFly-tUmI9mbPtW37RDmf3FEQ"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
Vendored
+21
@@ -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.yaros.sweetshopviki
|
||||||
|
|
||||||
|
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.yaros.sweetshopviki", appContext.packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
package="com.yaros.sweetshopviki">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
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.MaterialComponents"
|
||||||
|
tools:targetApi="31">
|
||||||
|
<activity
|
||||||
|
android:name=".ui.SplashActivity"
|
||||||
|
android:theme="@style/Theme.AppCompat"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.login.LoginActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
<activity
|
||||||
|
android:name=".ui.MainActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.yaros.sweetshopviki.common
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.squareup.picasso.Picasso
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
|
||||||
|
fun Double.formatPrice(): String {
|
||||||
|
return String.format("%.2f", this) + " ₽"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Float.formatPrice(): String {
|
||||||
|
return String.format("%.2f", this) + " ₽"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ImageView.loadImage(url: String?) {
|
||||||
|
Picasso.get()
|
||||||
|
.load("https://liwapos.com/samba.mobil/Content/$url")
|
||||||
|
.placeholder(R.drawable.loading)
|
||||||
|
.error(R.drawable.error)
|
||||||
|
.into(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPaymentImages(): ArrayList<Int> {
|
||||||
|
return arrayListOf(R.drawable.ic_cash, R.drawable.ic_bank_cards)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.getPaymentNames(): ArrayList<String> {
|
||||||
|
return arrayListOf(this.getString(R.string.cash), this.getString(R.string.credit_card))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.visible() {
|
||||||
|
this.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun View.gone() {
|
||||||
|
this.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Toast.showCustomToast(toastText: String, activity: Activity) {
|
||||||
|
|
||||||
|
val layout = activity.layoutInflater.inflate(
|
||||||
|
R.layout.custom_toast,
|
||||||
|
activity.findViewById(R.id.toast_layout_root)
|
||||||
|
)
|
||||||
|
|
||||||
|
val text =
|
||||||
|
layout.findViewById<View>(R.id.text) as TextView
|
||||||
|
text.text = toastText
|
||||||
|
|
||||||
|
this.apply {
|
||||||
|
setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL, 0, 0)
|
||||||
|
duration = Toast.LENGTH_SHORT
|
||||||
|
view = layout
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.yaros.sweetshopviki.common.utils
|
||||||
|
|
||||||
|
import com.yaros.sweetshopviki.data.retrofit.DAOInterface
|
||||||
|
import com.yaros.sweetshopviki.data.retrofit.RetrofitClient
|
||||||
|
|
||||||
|
class ApiUtils {
|
||||||
|
companion object {
|
||||||
|
private const val BASE_URL = "https://my-json-server.typicode.com/YarikHumster/SweetShopViki/"
|
||||||
|
|
||||||
|
|
||||||
|
fun getInterfaceDAO(): DAOInterface {
|
||||||
|
return RetrofitClient.getClient(BASE_URL).create(DAOInterface::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.yaros.sweetshopviki.data.models
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
data class Categories (
|
||||||
|
@SerializedName("id") @Expose var id: Int,
|
||||||
|
@SerializedName("name") @Expose var name: String,
|
||||||
|
@SerializedName("imagePath") @Expose var imagePath: String
|
||||||
|
): Serializable
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.yaros.sweetshopviki.data.models
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
data class Product (
|
||||||
|
@SerializedName("Name") @Expose var name: String?,
|
||||||
|
@SerializedName("ImagePath") @Expose var imagePath: String?,
|
||||||
|
@SerializedName("Price") @Expose var price: Double?,
|
||||||
|
@SerializedName("MenuItemId") @Expose var menuItemId: Int?,
|
||||||
|
@SerializedName("GroupName") @Expose var groupName: String?,
|
||||||
|
@SerializedName("CustomTags") @Expose var customTags: String?,
|
||||||
|
@SerializedName("Expr1") @Expose var portion: String?
|
||||||
|
): Serializable
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.yaros.sweetshopviki.data.models
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
|
@Entity(tableName = "productsbasketdatabase")
|
||||||
|
data class ProductsBasketRoomModel(
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = false)
|
||||||
|
@ColumnInfo(name = "id")
|
||||||
|
var productId: Int = 0,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "productName")
|
||||||
|
var productName: String?,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "productCount")
|
||||||
|
var productCount: Int = 1,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "productPrice")
|
||||||
|
var productPrice: Double?,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "productImage")
|
||||||
|
var productImage: String?
|
||||||
|
|
||||||
|
)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.yaros.sweetshopviki.data.models
|
||||||
|
|
||||||
|
data class UserModel (
|
||||||
|
val email: String?,
|
||||||
|
val phoneNumber: String?,
|
||||||
|
val userName: String?,
|
||||||
|
)
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
package com.yaros.sweetshopviki.data.repo
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.yaros.sweetshopviki.common.utils.ApiUtils
|
||||||
|
import com.yaros.sweetshopviki.data.models.Categories
|
||||||
|
import com.yaros.sweetshopviki.data.models.Product
|
||||||
|
import com.yaros.sweetshopviki.data.models.ProductsBasketRoomModel
|
||||||
|
import com.yaros.sweetshopviki.data.retrofit.DAOInterface
|
||||||
|
import com.yaros.sweetshopviki.data.room.ProductsBasketDAOInterface
|
||||||
|
import com.yaros.sweetshopviki.data.room.ProductsBasketRoomDatabase
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
|
class Repository(context: Context) {
|
||||||
|
enum class LOADING {
|
||||||
|
LOADING, DONE, ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
val categoriesList = MutableLiveData<List<Categories>>()
|
||||||
|
val productList = MutableLiveData<List<Product>>()
|
||||||
|
val searchList = MutableLiveData<List<Product>>()
|
||||||
|
val basketList = MutableLiveData<List<ProductsBasketRoomModel>>()
|
||||||
|
val isLoading = MutableLiveData<LOADING>()
|
||||||
|
val basketTotalAmount = MutableLiveData<Double>()
|
||||||
|
|
||||||
|
private val dif: DAOInterface = ApiUtils.getInterfaceDAO()
|
||||||
|
private val basketDif: ProductsBasketDAOInterface? =
|
||||||
|
ProductsBasketRoomDatabase.productsBasketRoomDatabase(context)?.productsBasketDAOInterface()
|
||||||
|
|
||||||
|
suspend fun getCategories() {
|
||||||
|
try {
|
||||||
|
isLoading.value = LOADING.LOADING
|
||||||
|
val response = dif.getCategories()
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
val tempList = response.body()
|
||||||
|
categoriesList.value = tempList!!
|
||||||
|
isLoading.value = LOADING.DONE
|
||||||
|
} else {
|
||||||
|
isLoading.value = LOADING.ERROR
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
t.localizedMessage?.toString()?.let { Log.e("getCategories", it) }
|
||||||
|
isLoading.value = LOADING.ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getProducts(categoryId: Int) {
|
||||||
|
try {
|
||||||
|
isLoading.value = LOADING.LOADING
|
||||||
|
val response = dif.getProducts(categoryId)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
val tempList = response.body()
|
||||||
|
productList.value = tempList!!
|
||||||
|
isLoading.value = LOADING.DONE
|
||||||
|
} else {
|
||||||
|
isLoading.value = LOADING.ERROR
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
t.localizedMessage?.toString()?.let { Log.e("getCategories", it) }
|
||||||
|
isLoading.value = LOADING.ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getSearch() {
|
||||||
|
try {
|
||||||
|
isLoading.value = LOADING.LOADING
|
||||||
|
val response = dif.getSearch()
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
val tempList = response.body()
|
||||||
|
searchList.value = tempList!!
|
||||||
|
isLoading.value = LOADING.DONE
|
||||||
|
} else {
|
||||||
|
isLoading.value = LOADING.ERROR
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
t.localizedMessage?.toString()?.let { Log.e("getCategories", it) }
|
||||||
|
isLoading.value = LOADING.ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBasket() = runBlocking {
|
||||||
|
isLoading.value = LOADING.LOADING
|
||||||
|
|
||||||
|
basketDif?.getProductsBasket()?.let {
|
||||||
|
basketList.value = it
|
||||||
|
isLoading.value = LOADING.DONE
|
||||||
|
} ?: run {
|
||||||
|
isLoading.value = LOADING.DONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBasketTotalAmount() = runBlocking {
|
||||||
|
|
||||||
|
if (basketDif?.getProductsBasketTotalAmount() != null) {
|
||||||
|
basketTotalAmount.value = basketDif.getProductsBasketTotalAmount()
|
||||||
|
} else {
|
||||||
|
basketTotalAmount.value = 0.00
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun addBookToBasket(productModel: ProductsBasketRoomModel) {
|
||||||
|
|
||||||
|
val productFromDatabase = basketDif?.getProductById(productModel.productId)
|
||||||
|
|
||||||
|
if (productFromDatabase != null) {
|
||||||
|
val productCount = productFromDatabase.productCount + productModel.productCount
|
||||||
|
val productPrice =
|
||||||
|
(productFromDatabase.productPrice?.div(productFromDatabase.productCount))?.times(
|
||||||
|
productCount
|
||||||
|
)
|
||||||
|
|
||||||
|
basketDif?.updateProductBasket(productModel.productId, productCount, productPrice)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
basketDif?.addProductBasket(productModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun deleteBookFromBasket(productId: Int) {
|
||||||
|
basketDif?.deleteProductWithId(productId)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun clearBasket() {
|
||||||
|
basketDif?.clearBasket()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package com.yaros.sweetshopviki.data.repo
|
||||||
|
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.google.firebase.auth.ktx.auth
|
||||||
|
import com.google.firebase.firestore.ktx.firestore
|
||||||
|
import com.google.firebase.ktx.Firebase
|
||||||
|
import com.yaros.sweetshopviki.data.models.UserModel
|
||||||
|
|
||||||
|
class UserRepository {
|
||||||
|
enum class LOADING {
|
||||||
|
LOADING, DONE, ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
var isSignIn = MutableLiveData<Boolean>()
|
||||||
|
var isSignUp = MutableLiveData<Boolean>()
|
||||||
|
var userInfo = MutableLiveData<UserModel>()
|
||||||
|
var isLoading = MutableLiveData<LOADING>()
|
||||||
|
|
||||||
|
private var auth = Firebase.auth
|
||||||
|
private val db = Firebase.firestore
|
||||||
|
|
||||||
|
fun signIn(eMail: String, password: String) {
|
||||||
|
isLoading.value = LOADING.LOADING
|
||||||
|
auth.signInWithEmailAndPassword(eMail, password).addOnCompleteListener { task ->
|
||||||
|
|
||||||
|
if (task.isSuccessful) {
|
||||||
|
isLoading.value = LOADING.DONE
|
||||||
|
isSignIn.value = true
|
||||||
|
Log.d("SIGN_IN", "SUCCESS")
|
||||||
|
} else {
|
||||||
|
isLoading.value = LOADING.ERROR
|
||||||
|
isSignIn.value = false
|
||||||
|
Log.w("SIGN_IN", "FAILURE", task.exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun signUp(eMail: String, password: String, phoneNumber: String, userName: String) {
|
||||||
|
isLoading.value = LOADING.LOADING
|
||||||
|
auth.createUserWithEmailAndPassword(eMail, password).addOnCompleteListener { task ->
|
||||||
|
|
||||||
|
if (task.isSuccessful) {
|
||||||
|
|
||||||
|
val currentUser = auth.currentUser
|
||||||
|
currentUser?.let { fbUser ->
|
||||||
|
val user = hashMapOf(
|
||||||
|
"id" to fbUser.uid,
|
||||||
|
"email" to eMail,
|
||||||
|
"phonenumber" to phoneNumber,
|
||||||
|
"username" to userName
|
||||||
|
)
|
||||||
|
|
||||||
|
db.collection("users").document(fbUser.uid)
|
||||||
|
.set(user)
|
||||||
|
.addOnSuccessListener {
|
||||||
|
isSignUp.value = true
|
||||||
|
isLoading.value = LOADING.DONE
|
||||||
|
Log.d("SIGN_UP", "SUCCESS")
|
||||||
|
}
|
||||||
|
.addOnFailureListener { e ->
|
||||||
|
isSignUp.value = false
|
||||||
|
isLoading.value = LOADING.ERROR
|
||||||
|
Log.w("SIGN_UP", "FAILURE", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isLoading.value = LOADING.DONE
|
||||||
|
} else {
|
||||||
|
isSignUp.value = false
|
||||||
|
isLoading.value = LOADING.ERROR
|
||||||
|
Log.w("SIGN_UP", "FAILURE", task.exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUserInfo() {
|
||||||
|
isLoading.value = LOADING.LOADING
|
||||||
|
auth.currentUser?.let { user ->
|
||||||
|
|
||||||
|
val docRef = db.collection("users").document(user.uid)
|
||||||
|
docRef.get()
|
||||||
|
.addOnSuccessListener { document ->
|
||||||
|
document?.let {
|
||||||
|
userInfo.value = UserModel(
|
||||||
|
user.email,
|
||||||
|
document.get("phonenumber") as String,
|
||||||
|
document.get("username") as String
|
||||||
|
)
|
||||||
|
isLoading.value = LOADING.DONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.addOnFailureListener { exception ->
|
||||||
|
Log.d(ContentValues.TAG, "get failed with ", exception)
|
||||||
|
isLoading.value = LOADING.ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun signOut() {
|
||||||
|
isLoading.value = LOADING.LOADING
|
||||||
|
auth.signOut()
|
||||||
|
isLoading.value = LOADING.DONE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.yaros.sweetshopviki.data.retrofit
|
||||||
|
|
||||||
|
import com.yaros.sweetshopviki.data.models.Categories
|
||||||
|
import com.yaros.sweetshopviki.data.models.Product
|
||||||
|
import retrofit2.Response
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Path
|
||||||
|
|
||||||
|
interface DAOInterface {
|
||||||
|
@GET("JsonCategories")
|
||||||
|
suspend fun getCategories(): Response<List<Categories>>
|
||||||
|
|
||||||
|
@GET("JsonItems/{id}")
|
||||||
|
suspend fun getProducts(@Path("id") id: Int): Response<List<Product>>
|
||||||
|
|
||||||
|
@GET("JsonSearch")
|
||||||
|
suspend fun getSearch(): Response<List<Product>>
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.yaros.sweetshopviki.data.retrofit
|
||||||
|
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
|
class RetrofitClient {
|
||||||
|
companion object {
|
||||||
|
fun getClient(baseUrl: String): Retrofit {
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.baseUrl(baseUrl)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.yaros.sweetshopviki.data.room
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.Query
|
||||||
|
import com.yaros.sweetshopviki.data.models.ProductsBasketRoomModel
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface ProductsBasketDAOInterface {
|
||||||
|
@Insert
|
||||||
|
suspend fun addProductBasket(productsBasketRoomModel: ProductsBasketRoomModel)
|
||||||
|
|
||||||
|
@Query("SELECT * FROM productsbasketdatabase")
|
||||||
|
suspend fun getProductsBasket(): List<ProductsBasketRoomModel>?
|
||||||
|
|
||||||
|
@Query("SELECT Sum(ProductPrice) FROM productsbasketdatabase")
|
||||||
|
suspend fun getProductsBasketTotalAmount(): Double?
|
||||||
|
|
||||||
|
@Query("SELECT * FROM productsbasketdatabase WHERE id = :productId LIMIT 1")
|
||||||
|
suspend fun getProductById(productId: Int): ProductsBasketRoomModel?
|
||||||
|
|
||||||
|
@Query("DELETE FROM productsbasketdatabase WHERE id = :idInput")
|
||||||
|
suspend fun deleteProductWithId(idInput: Int)
|
||||||
|
|
||||||
|
@Query("DELETE FROM productsbasketdatabase")
|
||||||
|
suspend fun clearBasket()
|
||||||
|
|
||||||
|
@Query("UPDATE productsbasketdatabase SET productCount=:productCount, productPrice=:productPrice WHERE id = :productId")
|
||||||
|
suspend fun updateProductBasket(productId: Int, productCount: Int, productPrice: Double?)
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.yaros.sweetshopviki.data.room
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Database
|
||||||
|
import androidx.room.Room
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
|
import com.yaros.sweetshopviki.data.models.ProductsBasketRoomModel
|
||||||
|
|
||||||
|
@Database(entities = [ProductsBasketRoomModel::class], version = 1, exportSchema = false)
|
||||||
|
abstract class ProductsBasketRoomDatabase : RoomDatabase() {
|
||||||
|
abstract fun productsBasketDAOInterface(): ProductsBasketDAOInterface
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private var instance: ProductsBasketRoomDatabase? = null
|
||||||
|
|
||||||
|
fun productsBasketRoomDatabase(context: Context): ProductsBasketRoomDatabase? {
|
||||||
|
|
||||||
|
if (instance == null) {
|
||||||
|
|
||||||
|
synchronized(ProductsBasketRoomDatabase::class) {
|
||||||
|
instance = Room.databaseBuilder(
|
||||||
|
context,
|
||||||
|
ProductsBasketRoomDatabase::class.java,
|
||||||
|
"productsbasketdatabase.db"
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.PopupMenu
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.databinding.ActivityMainBinding
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
lateinit var binding: ActivityMainBinding
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
|
||||||
|
setupSmoothBottomMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupSmoothBottomMenu() {
|
||||||
|
val navHostFragment =
|
||||||
|
supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
|
||||||
|
|
||||||
|
val popupMenu = PopupMenu(this, null)
|
||||||
|
popupMenu.inflate(R.menu.menu)
|
||||||
|
val menu = popupMenu.menu
|
||||||
|
binding.navigationView.setupWithNavController(menu, navHostFragment.navController)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.yaros.sweetshopviki.databinding.ActivitySplashBinding
|
||||||
|
import com.yaros.sweetshopviki.ui.login.LoginActivity
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@SuppressLint("CustomSplashScreen")
|
||||||
|
class SplashActivity : AppCompatActivity() {
|
||||||
|
private lateinit var binding: ActivitySplashBinding
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivitySplashBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
val intent = Intent(this@SplashActivity, LoginActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.basket
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.common.formatPrice
|
||||||
|
import com.yaros.sweetshopviki.data.models.ProductsBasketRoomModel
|
||||||
|
import com.yaros.sweetshopviki.databinding.BasketItemBinding
|
||||||
|
|
||||||
|
class BasketAdapter (private var basketList: ArrayList<ProductsBasketRoomModel>) :
|
||||||
|
RecyclerView.Adapter<BasketAdapter.ProductsViewHolder>() {
|
||||||
|
|
||||||
|
class ProductsViewHolder(val productCardBinding: BasketItemBinding) :
|
||||||
|
RecyclerView.ViewHolder(productCardBinding.root)
|
||||||
|
|
||||||
|
var onDeleteClick: (Int) -> Unit = {}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(
|
||||||
|
parent: ViewGroup,
|
||||||
|
viewType: Int
|
||||||
|
): ProductsViewHolder {
|
||||||
|
val layoutInflater = LayoutInflater.from(parent.context)
|
||||||
|
val basketItemBinding = BasketItemBinding.inflate(layoutInflater, parent, false)
|
||||||
|
return ProductsViewHolder(basketItemBinding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ProductsViewHolder, position: Int) {
|
||||||
|
val product = basketList[position]
|
||||||
|
|
||||||
|
holder.productCardBinding.apply {
|
||||||
|
productText.text = product.productName
|
||||||
|
productCount.text = product.productCount.toString() + " X"
|
||||||
|
productPrice.text = product.productPrice?.formatPrice()
|
||||||
|
|
||||||
|
deleteBasketProduct.setOnClickListener {
|
||||||
|
onDeleteClick(product.productId)
|
||||||
|
basketList.removeAt(position)
|
||||||
|
notifyItemRemoved(position)
|
||||||
|
notifyItemRangeChanged(
|
||||||
|
position,
|
||||||
|
itemCount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
holder.productCardBinding.root.animation =
|
||||||
|
AnimationUtils.loadAnimation(holder.itemView.context, R.anim.recyclerview_anim)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return basketList.size
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.basket
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.MenuHost
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.common.formatPrice
|
||||||
|
import com.yaros.sweetshopviki.common.gone
|
||||||
|
import com.yaros.sweetshopviki.common.visible
|
||||||
|
import com.yaros.sweetshopviki.data.models.ProductsBasketRoomModel
|
||||||
|
import com.yaros.sweetshopviki.data.repo.Repository
|
||||||
|
import com.yaros.sweetshopviki.databinding.FragmentBasketBinding
|
||||||
|
import com.zhuinden.fragmentviewbindingdelegatekt.viewBinding
|
||||||
|
|
||||||
|
class BasketFragment : Fragment(R.layout.fragment_basket) {
|
||||||
|
|
||||||
|
private val binding by viewBinding(FragmentBasketBinding::bind)
|
||||||
|
private val viewModel by lazy { BasketViewModel(requireContext()) }
|
||||||
|
private var basketAmount: Double = 0.0
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
(activity as AppCompatActivity?)!!.supportActionBar!!.title =
|
||||||
|
resources.getString(R.string.basket)
|
||||||
|
(activity as AppCompatActivity?)!!.supportActionBar!!.setDisplayHomeAsUpEnabled(false)
|
||||||
|
|
||||||
|
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
getBasket()
|
||||||
|
initObservers()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
initToolbarMenu()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initToolbarMenu() {
|
||||||
|
val menuHost: MenuHost = requireActivity()
|
||||||
|
menuHost.addMenuProvider(object : MenuProvider {
|
||||||
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
|
menuInflater.inflate(R.menu.search, menu)
|
||||||
|
val item = menu.findItem(R.id.action_search)
|
||||||
|
item.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initObservers() {
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
isLoading.observe(viewLifecycleOwner) {
|
||||||
|
when (it!!) {
|
||||||
|
Repository.LOADING.LOADING -> {
|
||||||
|
shimmerLayout.startShimmer()
|
||||||
|
}
|
||||||
|
Repository.LOADING.DONE -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
|
||||||
|
gone()
|
||||||
|
stopShimmer()
|
||||||
|
}
|
||||||
|
basketRecyclerView.visible()
|
||||||
|
}
|
||||||
|
|
||||||
|
Repository.LOADING.ERROR -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
stopShimmer()
|
||||||
|
gone()
|
||||||
|
}
|
||||||
|
basketRecyclerView.visible()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
basketTotalAmount.observe(viewLifecycleOwner) { basketTotalAmount ->
|
||||||
|
if (basketTotalAmount > 0.00) {
|
||||||
|
totalAmount.text =
|
||||||
|
basketTotalAmount.formatPrice()
|
||||||
|
approveLayout.visible()
|
||||||
|
basketRecyclerView.visible()
|
||||||
|
emptyLayout.gone()
|
||||||
|
} else {
|
||||||
|
approveLayout.gone()
|
||||||
|
basketRecyclerView.gone()
|
||||||
|
emptyLayout.visible()
|
||||||
|
}
|
||||||
|
|
||||||
|
basketAmount = basketTotalAmount
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
basketList.observe(viewLifecycleOwner) { basketList ->
|
||||||
|
val basketAdapter =
|
||||||
|
BasketAdapter(basketList as ArrayList<ProductsBasketRoomModel>)
|
||||||
|
basketRecyclerView.adapter = basketAdapter
|
||||||
|
basketAdapter.onDeleteClick = ::onDeleteClick
|
||||||
|
|
||||||
|
|
||||||
|
if (basketList.isNotEmpty()) {
|
||||||
|
approveLayout.visible()
|
||||||
|
} else {
|
||||||
|
approveLayout.gone()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
basketRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||||
|
basketRecyclerView.setHasFixedSize(true)
|
||||||
|
|
||||||
|
addOrder.setOnClickListener { findNavController().navigate(BasketFragmentDirections.actionBasketFragmentToCategoriesFragment()) }
|
||||||
|
approveBasket.setOnClickListener {
|
||||||
|
findNavController().navigate(
|
||||||
|
BasketFragmentDirections.actionBasketFragmentToPaymentFragment(basketAmount.toFloat())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onDeleteClick(productId: Int) {
|
||||||
|
viewModel.deleteProductFromBasket(productId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.basket
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.yaros.sweetshopviki.data.models.ProductsBasketRoomModel
|
||||||
|
import com.yaros.sweetshopviki.data.repo.Repository
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class BasketViewModel(context: Context) : ViewModel() {
|
||||||
|
|
||||||
|
private val repository = Repository(context)
|
||||||
|
var basketList: LiveData<List<ProductsBasketRoomModel>> = repository.basketList
|
||||||
|
var basketTotalAmount: LiveData<Double> = repository.basketTotalAmount
|
||||||
|
var isLoading: LiveData<Repository.LOADING> = repository.isLoading
|
||||||
|
|
||||||
|
fun getBasket() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
// Bottom Navigation Bar is lagging if don't add delay
|
||||||
|
delay(500)
|
||||||
|
repository.getBasket()
|
||||||
|
getBasketTotalAmount()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteProductFromBasket(productId: Int) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
repository.deleteBookFromBasket(productId)
|
||||||
|
getBasketTotalAmount()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBasketTotalAmount() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
repository.getBasketTotalAmount()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.category
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.common.loadImage
|
||||||
|
import com.yaros.sweetshopviki.data.models.Categories
|
||||||
|
import com.yaros.sweetshopviki.databinding.CategoryCardBinding
|
||||||
|
|
||||||
|
class CategoriesAdapter (private var categoriesList: ArrayList<Categories>) :
|
||||||
|
RecyclerView.Adapter<CategoriesAdapter.CategoryCardDesign>() {
|
||||||
|
|
||||||
|
var onClick: (Categories) -> Unit = {}
|
||||||
|
|
||||||
|
class CategoryCardDesign(val categoryCardBinding: CategoryCardBinding) :
|
||||||
|
RecyclerView.ViewHolder(categoryCardBinding.root)
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryCardDesign {
|
||||||
|
val layoutInflater = LayoutInflater.from(parent.context)
|
||||||
|
val categoryCardBinding = CategoryCardBinding.inflate(layoutInflater, parent, false)
|
||||||
|
return CategoryCardDesign(categoryCardBinding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: CategoryCardDesign, position: Int) {
|
||||||
|
val category = categoriesList[position]
|
||||||
|
|
||||||
|
holder.categoryCardBinding.apply {
|
||||||
|
categoryText.text = category.name
|
||||||
|
categoryImageView.loadImage(category.imagePath)
|
||||||
|
|
||||||
|
root.setOnClickListener {
|
||||||
|
onClick(category)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
holder.categoryCardBinding.root.animation =
|
||||||
|
AnimationUtils.loadAnimation(holder.itemView.context, R.anim.recyclerview_anim)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return categoriesList.size
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.category
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.common.gone
|
||||||
|
import com.yaros.sweetshopviki.common.visible
|
||||||
|
import com.yaros.sweetshopviki.data.models.Categories
|
||||||
|
import com.yaros.sweetshopviki.data.repo.Repository
|
||||||
|
import com.yaros.sweetshopviki.databinding.FragmentCategoriesBinding
|
||||||
|
import com.zhuinden.fragmentviewbindingdelegatekt.viewBinding
|
||||||
|
|
||||||
|
class CategoriesFragment : Fragment(R.layout.fragment_categories) {
|
||||||
|
|
||||||
|
|
||||||
|
private val binding by viewBinding(FragmentCategoriesBinding::bind)
|
||||||
|
private val viewModel by lazy { CategoriesViewModel(requireContext()) }
|
||||||
|
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
val tryAgain: Button = requireView().findViewById<View>(R.id.tryAgain) as Button
|
||||||
|
|
||||||
|
(activity as AppCompatActivity?)!!.supportActionBar!!.title =
|
||||||
|
resources.getString(R.string.categories)
|
||||||
|
(activity as AppCompatActivity?)!!.supportActionBar!!.setDisplayHomeAsUpEnabled(false)
|
||||||
|
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
getCategories()
|
||||||
|
initObservers()
|
||||||
|
tryAgain.setOnClickListener {
|
||||||
|
getCategories()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initObservers() {
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
val errorLayout: LinearLayout =
|
||||||
|
requireView().findViewById<View>(R.id.errorLayout) as LinearLayout
|
||||||
|
isLoading.observe(viewLifecycleOwner) {
|
||||||
|
when (it!!) {
|
||||||
|
Repository.LOADING.LOADING -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
startShimmer()
|
||||||
|
visible()
|
||||||
|
}
|
||||||
|
categoriesRecyclerView.gone()
|
||||||
|
errorLayout.gone()
|
||||||
|
}
|
||||||
|
Repository.LOADING.DONE -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
stopShimmer()
|
||||||
|
gone()
|
||||||
|
}
|
||||||
|
categoriesRecyclerView.visible()
|
||||||
|
errorLayout.gone()
|
||||||
|
}
|
||||||
|
|
||||||
|
Repository.LOADING.ERROR -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
stopShimmer()
|
||||||
|
gone()
|
||||||
|
}
|
||||||
|
categoriesRecyclerView.gone()
|
||||||
|
errorLayout.visible()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
categoryList.observe(viewLifecycleOwner) { categories ->
|
||||||
|
val productAdapter = CategoriesAdapter(categories as ArrayList<Categories>)
|
||||||
|
categoriesRecyclerView.adapter = productAdapter
|
||||||
|
productAdapter.onClick = ::clickCategory
|
||||||
|
|
||||||
|
}
|
||||||
|
categoriesRecyclerView.layoutManager = GridLayoutManager(context, 2)
|
||||||
|
categoriesRecyclerView.setHasFixedSize(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clickCategory(category: Categories) {
|
||||||
|
val categoryNavigation =
|
||||||
|
CategoriesFragmentDirections.actionCategoriesFragmentToProductsFragment(
|
||||||
|
category
|
||||||
|
)
|
||||||
|
|
||||||
|
findNavController().navigate(categoryNavigation)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.category
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.yaros.sweetshopviki.data.models.Categories
|
||||||
|
import com.yaros.sweetshopviki.data.repo.Repository
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class CategoriesViewModel (context: Context) : ViewModel() {
|
||||||
|
|
||||||
|
private val repository = Repository(context)
|
||||||
|
|
||||||
|
var categoryList: LiveData<List<Categories>> = repository.categoriesList
|
||||||
|
var isLoading: LiveData<Repository.LOADING> = repository.isLoading
|
||||||
|
|
||||||
|
|
||||||
|
fun getCategories() {
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
repository.getCategories()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.login
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.google.firebase.auth.ktx.auth
|
||||||
|
import com.google.firebase.ktx.Firebase
|
||||||
|
import com.yaros.sweetshopviki.databinding.ActivityLoginBinding
|
||||||
|
import com.yaros.sweetshopviki.ui.MainActivity
|
||||||
|
|
||||||
|
class LoginActivity : AppCompatActivity() {
|
||||||
|
private lateinit var binding: ActivityLoginBinding
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = ActivityLoginBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
|
||||||
|
supportActionBar?.hide()
|
||||||
|
|
||||||
|
Firebase.auth.currentUser?.let {
|
||||||
|
val intent = Intent(this, MainActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.viewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle)
|
||||||
|
|
||||||
|
binding.tabBar.setupWithViewPager2(binding.viewPager)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.login
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
|
import com.yaros.sweetshopviki.ui.login.signin.SignInFragment
|
||||||
|
import com.yaros.sweetshopviki.ui.login.signup.SignUpFragment
|
||||||
|
|
||||||
|
class ViewPagerAdapter (fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
||||||
|
FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createFragment(position: Int): Fragment {
|
||||||
|
when (position) {
|
||||||
|
0 -> return SignInFragment()
|
||||||
|
1 -> return SignUpFragment()
|
||||||
|
}
|
||||||
|
return SignInFragment()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.login.signin
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.data.repo.UserRepository
|
||||||
|
import com.yaros.sweetshopviki.databinding.FragmentSignInBinding
|
||||||
|
import com.yaros.sweetshopviki.ui.MainActivity
|
||||||
|
import com.zhuinden.fragmentviewbindingdelegatekt.viewBinding
|
||||||
|
import www.sanju.motiontoast.MotionToast
|
||||||
|
import www.sanju.motiontoast.MotionToastStyle
|
||||||
|
|
||||||
|
class SignInFragment : Fragment(R.layout.fragment_sign_in) {
|
||||||
|
|
||||||
|
private val binding by viewBinding(FragmentSignInBinding::bind)
|
||||||
|
private val viewModel by lazy { SignInViewModel() }
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
|
||||||
|
initObservers()
|
||||||
|
btnSignIn.setOnClickListener {
|
||||||
|
signIn(
|
||||||
|
emailEditText.text.toString(),
|
||||||
|
passwordEditText.text.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initObservers() {
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
isLoading.observe(viewLifecycleOwner) {
|
||||||
|
when (it!!) {
|
||||||
|
UserRepository.LOADING.LOADING -> {
|
||||||
|
btnSignIn.startAnimation()
|
||||||
|
}
|
||||||
|
UserRepository.LOADING.DONE -> {
|
||||||
|
|
||||||
|
btnSignIn.revertAnimation {
|
||||||
|
btnSignIn.setBackgroundResource(R.drawable.rounded_bg3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserRepository.LOADING.ERROR -> {
|
||||||
|
btnSignIn.revertAnimation {
|
||||||
|
btnSignIn.setBackgroundResource(R.drawable.rounded_bg3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isSignIn.observe(viewLifecycleOwner) {
|
||||||
|
if (it) {
|
||||||
|
MotionToast.createColorToast(
|
||||||
|
requireActivity(),
|
||||||
|
getString(R.string.success),
|
||||||
|
getString(R.string.login_success),
|
||||||
|
MotionToastStyle.SUCCESS,
|
||||||
|
MotionToast.GRAVITY_TOP or MotionToast.GRAVITY_CENTER,
|
||||||
|
MotionToast.LONG_DURATION,
|
||||||
|
ResourcesCompat.getFont(requireContext(), R.font.circular)
|
||||||
|
)
|
||||||
|
|
||||||
|
val intent = Intent(context, MainActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
requireActivity().finish()
|
||||||
|
} else {
|
||||||
|
MotionToast.createColorToast(
|
||||||
|
requireActivity(),
|
||||||
|
getString(R.string.error),
|
||||||
|
getString(R.string.wrong_email_password),
|
||||||
|
MotionToastStyle.ERROR,
|
||||||
|
MotionToast.GRAVITY_TOP or MotionToast.GRAVITY_CENTER,
|
||||||
|
MotionToast.LONG_DURATION,
|
||||||
|
ResourcesCompat.getFont(requireContext(), R.font.circular)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidMail.observe(viewLifecycleOwner) {
|
||||||
|
if (it.not()) {
|
||||||
|
emailEditText.error = getString(R.string.invalid_mail)
|
||||||
|
} else {
|
||||||
|
emailEditText.error = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isInfosValid.observe(viewLifecycleOwner) {
|
||||||
|
if (it.not())
|
||||||
|
|
||||||
|
MotionToast.createColorToast(
|
||||||
|
requireActivity(),
|
||||||
|
getString(R.string.error),
|
||||||
|
getString(R.string.complete_not_entered_info),
|
||||||
|
MotionToastStyle.ERROR,
|
||||||
|
MotionToast.GRAVITY_TOP or MotionToast.GRAVITY_CENTER,
|
||||||
|
MotionToast.LONG_DURATION,
|
||||||
|
ResourcesCompat.getFont(requireContext(), R.font.circular)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.login.signin
|
||||||
|
|
||||||
|
import android.util.Patterns
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.yaros.sweetshopviki.data.repo.UserRepository
|
||||||
|
|
||||||
|
class SignInViewModel : ViewModel() {
|
||||||
|
|
||||||
|
private var usersRepo = UserRepository()
|
||||||
|
val isSignIn: LiveData<Boolean> = usersRepo.isSignIn
|
||||||
|
val isLoading: LiveData<UserRepository.LOADING> = usersRepo.isLoading
|
||||||
|
|
||||||
|
|
||||||
|
private var _isValidMail = MutableLiveData<Boolean>()
|
||||||
|
val isValidMail: LiveData<Boolean> = _isValidMail
|
||||||
|
|
||||||
|
private var _isInfosValid = MutableLiveData<Boolean>()
|
||||||
|
val isInfosValid: LiveData<Boolean> = _isInfosValid
|
||||||
|
|
||||||
|
fun signIn(eMail: String, password: String) {
|
||||||
|
|
||||||
|
|
||||||
|
if (eMail.isEmpty() || password.isEmpty()) {
|
||||||
|
_isInfosValid.value = false
|
||||||
|
} else {
|
||||||
|
_isInfosValid.value = true
|
||||||
|
if (Patterns.EMAIL_ADDRESS.matcher(eMail).matches().not()) {
|
||||||
|
_isValidMail.value = false
|
||||||
|
} else {
|
||||||
|
_isValidMail.value = true
|
||||||
|
|
||||||
|
usersRepo.signIn(eMail, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.login.signup
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.data.repo.UserRepository
|
||||||
|
import com.yaros.sweetshopviki.databinding.FragmentSignUpBinding
|
||||||
|
import com.yaros.sweetshopviki.ui.MainActivity
|
||||||
|
import com.zhuinden.fragmentviewbindingdelegatekt.viewBinding
|
||||||
|
import www.sanju.motiontoast.MotionToast
|
||||||
|
import www.sanju.motiontoast.MotionToastStyle
|
||||||
|
|
||||||
|
class SignUpFragment : Fragment(R.layout.fragment_sign_up) {
|
||||||
|
|
||||||
|
private val binding by viewBinding(FragmentSignUpBinding::bind)
|
||||||
|
private val viewModel by lazy { SignUpViewModel() }
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
signUpButton.setOnClickListener {
|
||||||
|
signUp(
|
||||||
|
emailEditText.text.toString(),
|
||||||
|
passwordEditText.text.toString(),
|
||||||
|
confirmPasswordEditText.text.toString(),
|
||||||
|
phoneNumberEditText.text.toString(),
|
||||||
|
userNameEditText.text.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
initObservers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
private fun initObservers() {
|
||||||
|
|
||||||
|
with(binding) {
|
||||||
|
|
||||||
|
with(viewModel) {
|
||||||
|
|
||||||
|
|
||||||
|
isLoading.observe(viewLifecycleOwner) {
|
||||||
|
when (it!!) {
|
||||||
|
UserRepository.LOADING.LOADING -> {
|
||||||
|
signUpButton.startAnimation()
|
||||||
|
}
|
||||||
|
UserRepository.LOADING.DONE -> {
|
||||||
|
|
||||||
|
signUpButton.revertAnimation {
|
||||||
|
signUpButton.setBackgroundResource(R.drawable.rounded_bg3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserRepository.LOADING.ERROR -> {
|
||||||
|
signUpButton.revertAnimation {
|
||||||
|
signUpButton.setBackgroundResource(R.drawable.rounded_bg3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isPasswordSixChar.observe(viewLifecycleOwner) {
|
||||||
|
if (it.not()) {
|
||||||
|
passwordInputLayout.error = getString(R.string.six_char_error)
|
||||||
|
} else {
|
||||||
|
passwordInputLayout.error = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isInfoValid.observe(viewLifecycleOwner) {
|
||||||
|
if (it.not()) MotionToast.createColorToast(
|
||||||
|
requireActivity(),
|
||||||
|
getString(R.string.error),
|
||||||
|
getString(R.string.complete_not_entered_info),
|
||||||
|
MotionToastStyle.ERROR,
|
||||||
|
MotionToast.GRAVITY_TOP or MotionToast.GRAVITY_CENTER,
|
||||||
|
MotionToast.LONG_DURATION,
|
||||||
|
ResourcesCompat.getFont(requireContext(), R.font.circular)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidMail.observe(viewLifecycleOwner) {
|
||||||
|
if (it.not()) {
|
||||||
|
emailInputLayout.error = getString(R.string.invalid_mail)
|
||||||
|
} else {
|
||||||
|
emailInputLayout.error = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isPasswordMatch.observe(viewLifecycleOwner) {
|
||||||
|
if (it.not()) {
|
||||||
|
passwordInputLayout.error = getString(R.string.password_match_error)
|
||||||
|
confirmPasswordInputLayout.error = getString(R.string.password_match_error)
|
||||||
|
} else {
|
||||||
|
passwordInputLayout.error = ""
|
||||||
|
confirmPasswordInputLayout.error = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isSignUp.observe(viewLifecycleOwner) {
|
||||||
|
if (it) {
|
||||||
|
|
||||||
|
MotionToast.createColorToast(
|
||||||
|
requireActivity(),
|
||||||
|
getString(R.string.success),
|
||||||
|
getString(R.string.sign_up_success),
|
||||||
|
MotionToastStyle.SUCCESS,
|
||||||
|
MotionToast.GRAVITY_TOP or MotionToast.GRAVITY_CENTER,
|
||||||
|
MotionToast.LONG_DURATION,
|
||||||
|
ResourcesCompat.getFont(requireContext(), R.font.circular)
|
||||||
|
)
|
||||||
|
|
||||||
|
clearFields()
|
||||||
|
|
||||||
|
val intent = Intent(context, MainActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
requireActivity().finish()
|
||||||
|
} else {
|
||||||
|
emailInputLayout.error = getString(R.string.registered_mail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun clearFields() {
|
||||||
|
with(binding) {
|
||||||
|
emailEditText.setText("")
|
||||||
|
emailInputLayout.error = ""
|
||||||
|
passwordEditText.setText("")
|
||||||
|
passwordInputLayout.error = ""
|
||||||
|
confirmPasswordEditText.setText("")
|
||||||
|
confirmPasswordInputLayout.error = ""
|
||||||
|
phoneNumberEditText.setText("")
|
||||||
|
phoneNumberInputLayout.error = ""
|
||||||
|
userNameEditText.setText("")
|
||||||
|
userNameInputLayout.error = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.login.signup
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import android.util.Patterns
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.yaros.sweetshopviki.data.repo.UserRepository
|
||||||
|
|
||||||
|
class SignUpViewModel : ViewModel() {
|
||||||
|
|
||||||
|
private var usersRepo = UserRepository()
|
||||||
|
|
||||||
|
|
||||||
|
private var _isInfoValid = MutableLiveData<Boolean>()
|
||||||
|
val isInfoValid: LiveData<Boolean> = _isInfoValid
|
||||||
|
|
||||||
|
private var _isValidMail = MutableLiveData<Boolean>()
|
||||||
|
val isValidMail: LiveData<Boolean> = _isValidMail
|
||||||
|
|
||||||
|
private var _isPasswordMatch = MutableLiveData<Boolean>()
|
||||||
|
val isPasswordMatch: LiveData<Boolean> = _isPasswordMatch
|
||||||
|
|
||||||
|
private var _isPasswordSixChar = MutableLiveData<Boolean>()
|
||||||
|
val isPasswordSixChar: LiveData<Boolean> = _isPasswordSixChar
|
||||||
|
|
||||||
|
val isSignUp: LiveData<Boolean> = usersRepo.isSignUp
|
||||||
|
|
||||||
|
|
||||||
|
val isLoading: LiveData<UserRepository.LOADING> = usersRepo.isLoading
|
||||||
|
|
||||||
|
fun signUp(
|
||||||
|
eMail: String,
|
||||||
|
password: String,
|
||||||
|
confirmPassword: String,
|
||||||
|
phoneNumber: String,
|
||||||
|
userName: String
|
||||||
|
) {
|
||||||
|
|
||||||
|
if (eMail.isEmpty() || password.isEmpty() || confirmPassword.isEmpty() || phoneNumber.isEmpty() || userName.isEmpty()) {
|
||||||
|
_isInfoValid.value = false
|
||||||
|
Log.d("SIGN_UP", "SUCCESS")
|
||||||
|
} else {
|
||||||
|
_isInfoValid.value = true
|
||||||
|
if (Patterns.EMAIL_ADDRESS.matcher(eMail).matches().not()) {
|
||||||
|
_isValidMail.value = false
|
||||||
|
} else {
|
||||||
|
_isValidMail.value = true
|
||||||
|
if (password != confirmPassword) {
|
||||||
|
_isPasswordMatch.value = false
|
||||||
|
} else {
|
||||||
|
if (password.length >= 6) {
|
||||||
|
_isPasswordSixChar.value = true
|
||||||
|
_isPasswordMatch.value = true
|
||||||
|
usersRepo.signUp(eMail, password, phoneNumber, userName)
|
||||||
|
} else {
|
||||||
|
_isPasswordSixChar.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.payment
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.WindowManager
|
||||||
|
import android.widget.Button
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.common.formatPrice
|
||||||
|
import com.yaros.sweetshopviki.common.getPaymentImages
|
||||||
|
import com.yaros.sweetshopviki.common.getPaymentNames
|
||||||
|
import com.yaros.sweetshopviki.databinding.FragmentPaymentBinding
|
||||||
|
|
||||||
|
class PaymentFragment : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private var _binding: FragmentPaymentBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
private val viewModel by lazy { PaymentViewModel(requireContext()) }
|
||||||
|
|
||||||
|
private val args: PaymentFragmentArgs by navArgs()
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
|
||||||
|
_binding = FragmentPaymentBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
|
||||||
|
val dialog = BottomSheetDialog(requireContext(), theme)
|
||||||
|
dialog.setOnShowListener {
|
||||||
|
|
||||||
|
val bottomSheetDialog = it as BottomSheetDialog
|
||||||
|
val parentLayout =
|
||||||
|
bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
|
||||||
|
parentLayout?.let { layout ->
|
||||||
|
val behaviour = BottomSheetBehavior.from(layout)
|
||||||
|
setupFullHeight(layout)
|
||||||
|
behaviour.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
behaviour.skipCollapsed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupFullHeight(bottomSheet: View) {
|
||||||
|
val layoutParams = bottomSheet.layoutParams
|
||||||
|
layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT
|
||||||
|
bottomSheet.layoutParams = layoutParams
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
binding.apply {
|
||||||
|
closePaymentScreen.setOnClickListener { findNavController().popBackStack() }
|
||||||
|
orderNow.setOnClickListener {
|
||||||
|
if (orderAddress.text.isEmpty().not()) {
|
||||||
|
showOrderSuccessDialog()
|
||||||
|
viewModel.clearBasket()
|
||||||
|
} else {
|
||||||
|
orderAddress.error = getString(R.string.address_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
cancel.setOnClickListener { findNavController().popBackStack() }
|
||||||
|
|
||||||
|
|
||||||
|
val customAdapter =
|
||||||
|
SpinnerAdapter(
|
||||||
|
requireContext(),
|
||||||
|
getPaymentImages(),
|
||||||
|
requireContext().getPaymentNames()
|
||||||
|
)
|
||||||
|
paymentTypes.adapter = customAdapter
|
||||||
|
|
||||||
|
orderAmountPrice.text = args.totalPrice.formatPrice()
|
||||||
|
discountAmount.text = (args.totalPrice * 0.20).formatPrice()
|
||||||
|
orderPaymentTotalPrice.text =
|
||||||
|
((args.totalPrice) - (args.totalPrice * 0.20)).formatPrice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showOrderSuccessDialog() {
|
||||||
|
|
||||||
|
val alertDialog = AlertDialog.Builder(requireContext())
|
||||||
|
val factory = LayoutInflater.from(requireContext())
|
||||||
|
val view = factory.inflate(R.layout.dialog_order_approved, null)
|
||||||
|
alertDialog.setView(view)
|
||||||
|
|
||||||
|
val dialog = alertDialog.create()
|
||||||
|
dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||||
|
dialog.show()
|
||||||
|
dialog.setCancelable(false)
|
||||||
|
|
||||||
|
val button = view.findViewById<View>(R.id.okay) as Button
|
||||||
|
button.setOnClickListener {
|
||||||
|
dialog.dismiss()
|
||||||
|
dialog.cancel()
|
||||||
|
findNavController().navigate(PaymentFragmentDirections.actionPaymentFragmentToCategoriesFragment())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.payment
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.yaros.sweetshopviki.data.repo.Repository
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class PaymentViewModel (context: Context) : ViewModel() {
|
||||||
|
|
||||||
|
private val repository = Repository(context)
|
||||||
|
|
||||||
|
fun clearBasket() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
repository.clearBasket()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.payment
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.BaseAdapter
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
|
||||||
|
class SpinnerAdapter(
|
||||||
|
var context: Context,
|
||||||
|
var imagesList: ArrayList<Int>,
|
||||||
|
var namesList: ArrayList<String>
|
||||||
|
) :
|
||||||
|
BaseAdapter() {
|
||||||
|
var inflter: LayoutInflater = LayoutInflater.from(context)
|
||||||
|
override fun getCount(): Int {
|
||||||
|
return imagesList.size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItem(i: Int): Any? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemId(i: Int): Long {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
val view: View? = inflter.inflate(R.layout.custom_spinner_items, null)
|
||||||
|
val icon = view?.findViewById<View>(R.id.imageView) as ImageView
|
||||||
|
val names = view.findViewById<View>(R.id.textView) as TextView
|
||||||
|
|
||||||
|
icon.setImageResource(imagesList[position])
|
||||||
|
names.text = namesList[position]
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.product
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.common.formatPrice
|
||||||
|
import com.yaros.sweetshopviki.common.loadImage
|
||||||
|
import com.yaros.sweetshopviki.data.models.Product
|
||||||
|
import com.yaros.sweetshopviki.databinding.ProductCardBinding
|
||||||
|
|
||||||
|
class ProductsAdapter (private var productList: ArrayList<Product>) :
|
||||||
|
RecyclerView.Adapter<ProductsAdapter.ProductsViewHolder>() {
|
||||||
|
|
||||||
|
class ProductsViewHolder(val productCardBinding: ProductCardBinding) :
|
||||||
|
RecyclerView.ViewHolder(productCardBinding.root)
|
||||||
|
|
||||||
|
var onClick: (Product) -> Unit = {}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(
|
||||||
|
parent: ViewGroup,
|
||||||
|
viewType: Int
|
||||||
|
): ProductsViewHolder {
|
||||||
|
val layoutInflater = LayoutInflater.from(parent.context)
|
||||||
|
val productCardBinding = ProductCardBinding.inflate(layoutInflater, parent, false)
|
||||||
|
return ProductsViewHolder(productCardBinding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ProductsViewHolder, position: Int) {
|
||||||
|
val product = productList[position]
|
||||||
|
|
||||||
|
holder.productCardBinding.apply {
|
||||||
|
productText.text = product.name
|
||||||
|
productPrice.text = product.price?.formatPrice()
|
||||||
|
productImageView.loadImage(product.imagePath.toString())
|
||||||
|
|
||||||
|
root.setOnClickListener { onClick(product) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
holder.productCardBinding.root.animation =
|
||||||
|
AnimationUtils.loadAnimation(holder.itemView.context, R.anim.recyclerview_anim)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return productList.size
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.product
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.MenuHost
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.common.gone
|
||||||
|
import com.yaros.sweetshopviki.common.visible
|
||||||
|
import com.yaros.sweetshopviki.data.models.Product
|
||||||
|
import com.yaros.sweetshopviki.data.repo.Repository
|
||||||
|
import com.yaros.sweetshopviki.databinding.FragmentProductsBinding
|
||||||
|
import com.zhuinden.fragmentviewbindingdelegatekt.viewBinding
|
||||||
|
|
||||||
|
class ProductsFragment : Fragment(R.layout.fragment_products) {
|
||||||
|
|
||||||
|
|
||||||
|
private val binding by viewBinding(FragmentProductsBinding::bind)
|
||||||
|
private val viewModel by lazy { ProductsViewModel(requireContext()) }
|
||||||
|
|
||||||
|
|
||||||
|
private val args: ProductsFragmentArgs by navArgs()
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val category = args.category
|
||||||
|
|
||||||
|
val tryAgain: Button = requireView().findViewById<View>(R.id.tryAgain) as Button
|
||||||
|
|
||||||
|
|
||||||
|
(activity as AppCompatActivity?)!!.supportActionBar!!.title = category.name
|
||||||
|
(activity as AppCompatActivity?)!!.supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||||
|
|
||||||
|
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
|
||||||
|
getProducts(category.id)
|
||||||
|
initObservers()
|
||||||
|
tryAgain.setOnClickListener {
|
||||||
|
getProducts(category.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initToolbarMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initToolbarMenu() {
|
||||||
|
val menuHost: MenuHost = requireActivity()
|
||||||
|
menuHost.addMenuProvider(object : MenuProvider {
|
||||||
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
|
menuInflater.inflate(R.menu.search, menu)
|
||||||
|
val item = menu.findItem(R.id.action_search)
|
||||||
|
item.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||||
|
return when (menuItem.itemId) {
|
||||||
|
android.R.id.home -> {
|
||||||
|
findNavController().popBackStack()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initObservers() {
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
val errorLayout: LinearLayout =
|
||||||
|
requireView().findViewById<View>(R.id.errorLayout) as LinearLayout
|
||||||
|
isLoading.observe(viewLifecycleOwner) {
|
||||||
|
when (it!!) {
|
||||||
|
Repository.LOADING.LOADING -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
startShimmer()
|
||||||
|
visible()
|
||||||
|
}
|
||||||
|
productsRecyclerView.gone()
|
||||||
|
errorLayout.gone()
|
||||||
|
}
|
||||||
|
Repository.LOADING.DONE -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
stopShimmer()
|
||||||
|
gone()
|
||||||
|
}
|
||||||
|
productsRecyclerView.visible()
|
||||||
|
errorLayout.gone()
|
||||||
|
}
|
||||||
|
|
||||||
|
Repository.LOADING.ERROR -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
stopShimmer()
|
||||||
|
gone()
|
||||||
|
}
|
||||||
|
productsRecyclerView.gone()
|
||||||
|
errorLayout.visible()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
productList.observe(viewLifecycleOwner) { products ->
|
||||||
|
val productsAdapter = ProductsAdapter(products as ArrayList<Product>)
|
||||||
|
productsRecyclerView.adapter = productsAdapter
|
||||||
|
productsAdapter.onClick = ::clickProduct
|
||||||
|
|
||||||
|
}
|
||||||
|
productsRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||||
|
productsRecyclerView.setHasFixedSize(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clickProduct(product: Product) {
|
||||||
|
val productNavigation =
|
||||||
|
ProductsFragmentDirections.actionProductsFragmentToProductDetailFragment(product)
|
||||||
|
|
||||||
|
findNavController().navigate(productNavigation)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.product
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.yaros.sweetshopviki.data.models.Product
|
||||||
|
import com.yaros.sweetshopviki.data.repo.Repository
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class ProductsViewModel (context: Context) : ViewModel() {
|
||||||
|
|
||||||
|
private val repository = Repository(context)
|
||||||
|
var productList: LiveData<List<Product>> = repository.productList
|
||||||
|
var isLoading: LiveData<Repository.LOADING> = repository.isLoading
|
||||||
|
|
||||||
|
|
||||||
|
fun getProducts(categoryId: Int) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
repository.getProducts(categoryId)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.productdetail
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.common.formatPrice
|
||||||
|
import com.yaros.sweetshopviki.common.loadImage
|
||||||
|
import com.yaros.sweetshopviki.common.showCustomToast
|
||||||
|
import com.yaros.sweetshopviki.data.models.ProductsBasketRoomModel
|
||||||
|
import com.yaros.sweetshopviki.databinding.FragmentProductDetailBinding
|
||||||
|
|
||||||
|
class ProductDetailFragment : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private val viewModel by lazy { ProductDetailViewModel(requireContext()) }
|
||||||
|
private var _binding: FragmentProductDetailBinding? = null
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
private val args: ProductDetailFragmentArgs by navArgs()
|
||||||
|
private var count: Int = 1
|
||||||
|
private var totalPrice: Double? = null
|
||||||
|
private var price: Double? = null
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
|
||||||
|
_binding = FragmentProductDetailBinding.inflate(inflater, container, false)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
|
||||||
|
return BottomSheetDialog(requireContext(), R.style.AppBottomSheetDialogTheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val product = args.product
|
||||||
|
|
||||||
|
binding.apply {
|
||||||
|
productImage.loadImage(product.imagePath?.substring(39).toString())
|
||||||
|
totalPrice = product.price
|
||||||
|
price = product.price
|
||||||
|
productName.text = product.name
|
||||||
|
updatePrice()
|
||||||
|
productCount.text = count.toString()
|
||||||
|
increase.setOnClickListener { increaseCount() }
|
||||||
|
decrease.setOnClickListener { decreaseCount() }
|
||||||
|
cancel.setOnClickListener { findNavController().popBackStack() }
|
||||||
|
addToBasket.setOnClickListener {
|
||||||
|
viewModel.addBookToBasket(
|
||||||
|
ProductsBasketRoomModel(
|
||||||
|
productId = product.menuItemId!!,
|
||||||
|
productName = product.name,
|
||||||
|
productCount = count,
|
||||||
|
productPrice = totalPrice,
|
||||||
|
productImage = product.imagePath
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Toast(requireContext()).showCustomToast(
|
||||||
|
getString(R.string.success_add_basket),
|
||||||
|
requireActivity()
|
||||||
|
)
|
||||||
|
findNavController().popBackStack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updatePrice() {
|
||||||
|
totalPrice = count * price!!
|
||||||
|
binding.productPrice.text = totalPrice!!.formatPrice()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun increaseCount() {
|
||||||
|
count += 1
|
||||||
|
binding.productCount.text = count.toString()
|
||||||
|
updatePrice()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun decreaseCount() {
|
||||||
|
if (count >= 2) {
|
||||||
|
count -= 1
|
||||||
|
binding.productCount.text = count.toString()
|
||||||
|
updatePrice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.productdetail
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.yaros.sweetshopviki.data.models.ProductsBasketRoomModel
|
||||||
|
import com.yaros.sweetshopviki.data.repo.Repository
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class ProductDetailViewModel (context: Context) : ViewModel() {
|
||||||
|
|
||||||
|
private val repository = Repository(context)
|
||||||
|
|
||||||
|
fun addBookToBasket(productModel: ProductsBasketRoomModel) {
|
||||||
|
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
repository.addBookToBasket(productModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.profile
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.MenuHost
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.data.repo.UserRepository
|
||||||
|
import com.yaros.sweetshopviki.databinding.FragmentProfileBinding
|
||||||
|
import com.yaros.sweetshopviki.ui.login.LoginActivity
|
||||||
|
import com.zhuinden.fragmentviewbindingdelegatekt.viewBinding
|
||||||
|
|
||||||
|
class ProfileFragment : Fragment(R.layout.fragment_profile) {
|
||||||
|
|
||||||
|
private val binding by viewBinding(FragmentProfileBinding::bind)
|
||||||
|
private val viewModel by lazy { ProfileViewModel() }
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
(activity as AppCompatActivity?)!!.supportActionBar!!.title =
|
||||||
|
resources.getString(R.string.profile)
|
||||||
|
(activity as AppCompatActivity?)!!.supportActionBar!!.setDisplayHomeAsUpEnabled(false)
|
||||||
|
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
|
||||||
|
initObservers()
|
||||||
|
|
||||||
|
logOut.setOnClickListener {
|
||||||
|
signOut().also {
|
||||||
|
val intent = Intent(requireActivity(), LoginActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initToolbarMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initObservers() {
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
|
||||||
|
userInfo.observe(viewLifecycleOwner) {
|
||||||
|
username.text = it.userName
|
||||||
|
email.text = it.email
|
||||||
|
phone.text = it.phoneNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading.observe(viewLifecycleOwner) {
|
||||||
|
when (it!!) {
|
||||||
|
UserRepository.LOADING.LOADING -> {
|
||||||
|
logOut.startAnimation()
|
||||||
|
}
|
||||||
|
UserRepository.LOADING.DONE -> {
|
||||||
|
|
||||||
|
logOut.revertAnimation {
|
||||||
|
logOut.setBackgroundResource(R.drawable.rounded_bg3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserRepository.LOADING.ERROR -> {
|
||||||
|
logOut.revertAnimation {
|
||||||
|
logOut.setBackgroundResource(R.drawable.rounded_bg3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initToolbarMenu() {
|
||||||
|
val menuHost: MenuHost = requireActivity()
|
||||||
|
menuHost.addMenuProvider(object : MenuProvider {
|
||||||
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
|
menuInflater.inflate(R.menu.search, menu)
|
||||||
|
val item = menu.findItem(R.id.action_search)
|
||||||
|
item.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.profile
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.yaros.sweetshopviki.data.models.UserModel
|
||||||
|
import com.yaros.sweetshopviki.data.repo.UserRepository
|
||||||
|
|
||||||
|
class ProfileViewModel : ViewModel() {
|
||||||
|
|
||||||
|
private val usersRepo = UserRepository()
|
||||||
|
|
||||||
|
val userInfo: LiveData<UserModel>
|
||||||
|
get() = usersRepo.userInfo
|
||||||
|
|
||||||
|
val isLoading: LiveData<UserRepository.LOADING> = usersRepo.isLoading
|
||||||
|
|
||||||
|
init {
|
||||||
|
getUserInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getUserInfo() {
|
||||||
|
usersRepo.getUserInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun signOut() {
|
||||||
|
usersRepo.signOut()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.search
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
|
import android.widget.Filter
|
||||||
|
import android.widget.Filterable
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.common.formatPrice
|
||||||
|
import com.yaros.sweetshopviki.common.loadImage
|
||||||
|
import com.yaros.sweetshopviki.data.models.Product
|
||||||
|
import com.yaros.sweetshopviki.databinding.ProductCardBinding
|
||||||
|
|
||||||
|
class SearchAdapter :
|
||||||
|
RecyclerView.Adapter<SearchAdapter.ProductsViewHolder>(), Filterable {
|
||||||
|
|
||||||
|
var onClick: (Product) -> Unit = {}
|
||||||
|
private var productList = ArrayList<Product>()
|
||||||
|
var productFilterList = ArrayList<Product>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
productFilterList = productList
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProductsViewHolder(val productCardBinding: ProductCardBinding) :
|
||||||
|
RecyclerView.ViewHolder(productCardBinding.root)
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(
|
||||||
|
parent: ViewGroup,
|
||||||
|
viewType: Int
|
||||||
|
): ProductsViewHolder {
|
||||||
|
val layoutInflater = LayoutInflater.from(parent.context)
|
||||||
|
val productCardBinding = ProductCardBinding.inflate(layoutInflater, parent, false)
|
||||||
|
return ProductsViewHolder(productCardBinding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ProductsViewHolder, position: Int) {
|
||||||
|
val product = productFilterList[position]
|
||||||
|
|
||||||
|
holder.productCardBinding.apply {
|
||||||
|
productText.text = product.name
|
||||||
|
productPrice.text = product.price?.formatPrice()
|
||||||
|
productImageView.loadImage(product.imagePath.toString())
|
||||||
|
|
||||||
|
root.setOnClickListener { onClick(product) }
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.productCardBinding.root.animation =
|
||||||
|
AnimationUtils.loadAnimation(holder.itemView.context, R.anim.recyclerview_anim)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateList(list: List<Product>) {
|
||||||
|
productList.clear()
|
||||||
|
productList.addAll(list)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isListSame(): Boolean {
|
||||||
|
return productList == productFilterList
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return productFilterList.size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFilter(): Filter {
|
||||||
|
|
||||||
|
return object : Filter() {
|
||||||
|
override fun performFiltering(constraint: CharSequence?): FilterResults {
|
||||||
|
|
||||||
|
val searchText = constraint.toString().lowercase()
|
||||||
|
productFilterList = if (searchText.isEmpty()) {
|
||||||
|
productList
|
||||||
|
} else {
|
||||||
|
val resultList = ArrayList<Product>()
|
||||||
|
for (row in productList) {
|
||||||
|
row.name.let { productName ->
|
||||||
|
|
||||||
|
if (productName!!.lowercase().contains(searchText)) {
|
||||||
|
resultList.add(row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
resultList
|
||||||
|
}
|
||||||
|
|
||||||
|
val filterResults = FilterResults()
|
||||||
|
filterResults.values = productFilterList
|
||||||
|
|
||||||
|
return filterResults
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
|
||||||
|
productFilterList = results?.values as ArrayList<Product>
|
||||||
|
if (isListSame().not()) {
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.search
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.inputmethod.EditorInfo
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.core.view.MenuHost
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.yaros.sweetshopviki.R
|
||||||
|
import com.yaros.sweetshopviki.common.gone
|
||||||
|
import com.yaros.sweetshopviki.common.visible
|
||||||
|
import com.yaros.sweetshopviki.data.models.Product
|
||||||
|
import com.yaros.sweetshopviki.data.repo.Repository
|
||||||
|
import com.yaros.sweetshopviki.databinding.FragmentSearchBinding
|
||||||
|
import com.zhuinden.fragmentviewbindingdelegatekt.viewBinding
|
||||||
|
|
||||||
|
class SearchFragment : Fragment(R.layout.fragment_search) {
|
||||||
|
|
||||||
|
|
||||||
|
private val binding by viewBinding(FragmentSearchBinding::bind)
|
||||||
|
private val viewModel by lazy { SearchViewModel(requireContext()) }
|
||||||
|
private val productsAdapter by lazy { SearchAdapter() }
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
(activity as AppCompatActivity?)!!.supportActionBar!!.title =
|
||||||
|
resources.getString(R.string.search_product)
|
||||||
|
(activity as AppCompatActivity?)!!.supportActionBar!!.setDisplayHomeAsUpEnabled(false)
|
||||||
|
|
||||||
|
val tryAgain: Button = requireView().findViewById<View>(R.id.tryAgain) as Button
|
||||||
|
|
||||||
|
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
getSearch()
|
||||||
|
initObservers()
|
||||||
|
tryAgain.setOnClickListener {
|
||||||
|
getSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initToolbarMenu()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initToolbarMenu() {
|
||||||
|
val menuHost: MenuHost = requireActivity()
|
||||||
|
menuHost.addMenuProvider(object : MenuProvider {
|
||||||
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
|
menuInflater.inflate(R.menu.search, menu)
|
||||||
|
val item = menu.findItem(R.id.action_search)
|
||||||
|
item.isVisible = true
|
||||||
|
|
||||||
|
val searchItem = menu.findItem(R.id.action_search)
|
||||||
|
val searchView = searchItem.actionView as SearchView
|
||||||
|
searchView.imeOptions = EditorInfo.IME_ACTION_DONE
|
||||||
|
searchView.queryHint = activity!!.getString(R.string.search) + "..."
|
||||||
|
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||||
|
override fun onQueryTextSubmit(query: String): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQueryTextChange(newText: String): Boolean {
|
||||||
|
|
||||||
|
productsAdapter.filter.filter(newText)
|
||||||
|
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initObservers() {
|
||||||
|
binding.apply {
|
||||||
|
viewModel.apply {
|
||||||
|
val errorLayout: LinearLayout =
|
||||||
|
requireView().findViewById(R.id.errorLayout)
|
||||||
|
isLoading.observe(viewLifecycleOwner) {
|
||||||
|
when (it!!) {
|
||||||
|
Repository.LOADING.LOADING -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
startShimmer()
|
||||||
|
visible()
|
||||||
|
}
|
||||||
|
productsRecyclerView.gone()
|
||||||
|
errorLayout.gone()
|
||||||
|
}
|
||||||
|
Repository.LOADING.DONE -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
stopShimmer()
|
||||||
|
gone()
|
||||||
|
}
|
||||||
|
productsRecyclerView.visible()
|
||||||
|
errorLayout.gone()
|
||||||
|
}
|
||||||
|
|
||||||
|
Repository.LOADING.ERROR -> {
|
||||||
|
shimmerLayout.apply {
|
||||||
|
stopShimmer()
|
||||||
|
gone()
|
||||||
|
}
|
||||||
|
productsRecyclerView.gone()
|
||||||
|
errorLayout.visible()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
productList.observe(viewLifecycleOwner) { products ->
|
||||||
|
productsRecyclerView.adapter = productsAdapter.also { adapter ->
|
||||||
|
adapter.updateList(products)
|
||||||
|
|
||||||
|
adapter.onClick = ::clickProduct
|
||||||
|
}
|
||||||
|
}
|
||||||
|
productsRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||||
|
productsRecyclerView.setHasFixedSize(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clickProduct(product: Product) {
|
||||||
|
val productNavigation =
|
||||||
|
SearchFragmentDirections.actionSearchFragmentToProductDetailFragment(product)
|
||||||
|
|
||||||
|
findNavController().navigate(productNavigation)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.yaros.sweetshopviki.ui.search
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.yaros.sweetshopviki.data.models.Product
|
||||||
|
import com.yaros.sweetshopviki.data.repo.Repository
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class SearchViewModel (context: Context) : ViewModel() {
|
||||||
|
|
||||||
|
private val repository = Repository(context)
|
||||||
|
var productList: LiveData<List<Product>> = repository.searchList
|
||||||
|
var isLoading: LiveData<Repository.LOADING> = repository.isLoading
|
||||||
|
|
||||||
|
|
||||||
|
fun getSearch() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
repository.getSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<scale xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:duration="500"
|
||||||
|
android:fromXScale="0.5"
|
||||||
|
android:fromYScale="0.5"
|
||||||
|
android:toXScale="1"
|
||||||
|
android:toYScale="1"
|
||||||
|
android:pivotY="50%"
|
||||||
|
android:pivotX="50%">
|
||||||
|
</scale>
|
||||||
|
|
||||||
|
<!--<translate-->
|
||||||
|
<!-- android:fromYDelta="100%"-->
|
||||||
|
<!-- android:fromXDelta="100%"-->
|
||||||
|
<!-- android:toYDelta="0%"-->
|
||||||
|
<!-- android:toXDelta="0%"-->
|
||||||
|
<!-- android:duration="500"-->
|
||||||
|
<!-- xmlns:android="http://schemas.android.com/apk/res/android" />-->
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<solid android:color="@color/background" />
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="25dp"
|
||||||
|
android:topRightRadius="25dp" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<solid android:color="#FFFFFF" />
|
||||||
|
|
||||||
|
<stroke
|
||||||
|
android:width="0.8dp"
|
||||||
|
android:color="@color/primary" />
|
||||||
|
<corners
|
||||||
|
android:radius="5dp"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||||
|
<solid android:color="@color/black"/>
|
||||||
|
<corners android:radius="20dp"/>
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid
|
||||||
|
android:color="@color/white"/>
|
||||||
|
<corners
|
||||||
|
android:radius="20dp" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="50dp"
|
||||||
|
android:height="50dp"
|
||||||
|
android:viewportWidth="50"
|
||||||
|
android:viewportHeight="50">
|
||||||
|
<path
|
||||||
|
android:pathData="M6,5C3.793,5 2,6.793 2,9L2,12L44,12L44,9C44,6.793 42.207,5 40,5ZM2,17L2,31C2,33.207 3.793,35 6,35L40,35C42.207,35 44,33.207 44,31L44,17ZM9,20L25,20L25,22L9,22ZM46,24.0625L46,31C46,34.3086 43.3086,37 40,37L6,37C5.8789,37 5.7461,36.9766 5.625,36.9688L6.5938,42.3125C6.7813,43.3672 7.3438,44.2969 8.2188,44.9063C8.8984,45.3828 9.6875,45.625 10.5,45.625C10.7344,45.625 10.9844,45.6055 11.2188,45.5625L44.6875,39.5938C45.7383,39.4063 46.6719,38.8125 47.2813,37.9375C47.8906,37.0625 48.125,36.0195 47.9375,34.9688Z"
|
||||||
|
android:fillColor="@color/black"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8,9h8v10L8,19L8,9zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M18.06,22.99h1.66c0.84,0 1.53,-0.64 1.63,-1.46L23,5.05h-5L18,1h-1.97v4.05h-4.97l0.3,2.34c1.71,0.47 3.31,1.32 4.27,2.26 1.44,1.42 2.43,2.89 2.43,5.29v8.05zM1,21.99L1,21h15.03v0.99c0,0.55 -0.45,1 -1.01,1L2.01,22.99c-0.56,0 -1.01,-0.45 -1.01,-1zM16.03,14.99c0,-8 -15.03,-8 -15.03,0h15.03zM1.02,17h15v2h-15z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:tint="#000000" android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M11,7L9.6,8.4l2.6,2.6H2v2h10.2l-2.6,2.6L11,17l5,-5L11,7zM20,19h-8v2h8c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2h-8v2h8V19z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:tint="#000000" android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M17,7l-1.41,1.41L18.17,11H8v2h10.17l-2.58,2.58L17,17l5,-5zM4,5h8V3H4c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h8v-2H4V5z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M13,8c0,-2.21 -1.79,-4 -4,-4S5,5.79 5,8s1.79,4 4,4S13,10.21 13,8zM15,10v2h3v3h2v-3h3v-2h-3V7h-2v3H15zM1,18v2h16v-2c0,-2.66 -5.33,-4 -8,-4S1,15.34 1,18z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M6.62,10.79c1.44,2.83 3.76,5.14 6.59,6.59l2.2,-2.2c0.27,-0.27 0.67,-0.36 1.02,-0.24 1.12,0.37 2.33,0.57 3.57,0.57 0.55,0 1,0.45 1,1V20c0,0.55 -0.45,1 -1,1 -9.39,0 -17,-7.61 -17,-17 0,-0.55 0.45,-1 1,-1h3.5c0.55,0 1,0.45 1,1 0,1.25 0.2,2.45 0.57,3.57 0.11,0.35 0.03,0.74 -0.25,1.02l-2.2,2.2z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#fff"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M17.21,9l-4.38,-6.56c-0.19,-0.28 -0.51,-0.42 -0.83,-0.42 -0.32,0 -0.64,0.14 -0.83,0.43L6.79,9L2,9c-0.55,0 -1,0.45 -1,1 0,0.09 0.01,0.18 0.04,0.27l2.54,9.27c0.23,0.84 1,1.46 1.92,1.46h13c0.92,0 1.69,-0.62 1.93,-1.46l2.54,-9.27L23,10c0,-0.55 -0.45,-1 -1,-1h-4.79zM9,9l3,-4.4L15,9L9,9zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="30dp"
|
||||||
|
android:height="30dp"
|
||||||
|
android:viewportWidth="30"
|
||||||
|
android:viewportHeight="30">
|
||||||
|
<path
|
||||||
|
android:pathData="M22,2C18.686,2 16,4.686 16,8C16,11.314 18.686,14 22,14C25.314,14 28,11.314 28,8C28,4.686 25.314,2 22,2zM20.0566,5L23.9434,5L23.9434,6.1582L21.2031,6.1582L21.0938,7.5137L21.1719,7.5137C21.3989,7.1497 21.8112,6.9141 22.4102,6.9141C23.5192,6.9141 24.3125,7.737 24.3125,8.875C24.3115,10.138 23.3817,11 21.9727,11C20.6167,11 19.7085,10.2036 19.6875,9.1426L21.0352,9.1426C21.1042,9.5716 21.4934,9.8555 21.9824,9.8555C22.5244,9.8555 22.9102,9.4821 22.9102,8.9121C22.9102,8.3291 22.5205,7.9414 21.9785,7.9414C21.5655,7.9414 21.2758,8.1278 21.0898,8.4238L19.7813,8.4238L20.0566,5zM4,10A2,2 0,0 0,3.6152 10.0391C3.6019,10.0417 3.5894,10.046 3.5762,10.0488A2,2 0,0 0,3.2363 10.1543C3.2257,10.1587 3.2156,10.1634 3.2051,10.168A2,2 0,0 0,2.8887 10.3379C2.8867,10.3392 2.8847,10.3405 2.8828,10.3418A2,2 0,0 0,2.873 10.3496A2,2 0,0 0,2.5918 10.5801C2.5859,10.5859 2.582,10.5937 2.5762,10.5996A2,2 0,0 0,2.3438 10.8809C2.3419,10.8835 2.3397,10.886 2.3379,10.8887A2,2 0,0 0,2.1582 11.2207C2.158,11.2212 2.1584,11.2221 2.1582,11.2227A2,2 0,0 0,2.041 11.5977A2,2 0,0 0,2 12L2,24A2,2 0,0 0,2.0391 24.3848C2.0417,24.3981 2.046,24.4106 2.0488,24.4238A2,2 0,0 0,2.1543 24.7637C2.1587,24.7743 2.1634,24.7844 2.168,24.7949A2,2 0,0 0,2.3379 25.1113C2.3415,25.1167 2.3459,25.1216 2.3496,25.127A2,2 0,0 0,2.5801 25.4082C2.5859,25.4141 2.5937,25.418 2.5996,25.4238A2,2 0,0 0,2.8809 25.6563C2.8835,25.6581 2.886,25.6603 2.8887,25.6621A2,2 0,0 0,3.2207 25.8418C3.2212,25.842 3.2221,25.8416 3.2227,25.8418A2,2 0,0 0,3.5977 25.959A2,2 0,0 0,4 26L26,26A2,2 0,0 0,26.3848 25.9609C26.3981,25.9583 26.4106,25.954 26.4238,25.9512A2,2 0,0 0,26.7637 25.8457C26.7743,25.8413 26.7844,25.8366 26.7949,25.832A2,2 0,0 0,27.1113 25.6621A2,2 0,0 0,27.1172 25.6582C27.1206,25.6559 27.1235,25.6528 27.127,25.6504A2,2 0,0 0,27.4082 25.4199A2,2 0,0 0,27.4141 25.4141C27.418,25.4101 27.4199,25.4044 27.4238,25.4004A2,2 0,0 0,27.6563 25.1191A2,2 0,0 0,27.6582 25.1172C27.6595,25.1153 27.6608,25.1133 27.6621,25.1113A2,2 0,0 0,27.8418 24.7793A2,2 0,0 0,27.8418 24.7773A2,2 0,0 0,27.959 24.4023A2,2 0,0 0,28 24L28,13.2793C27.428,13.9293 26.754,14.4849 26,14.9219L25.998,22A2,2 0,0 0,24 24L6,24A2,2 0,0 0,4 22L4,14A2,2 0,0 0,6 12L15.0781,12C14.7191,11.381 14.4447,10.71 14.2617,10L4,10zM15,14C12.791,14 11,16.015 11,18.5C11,19.922 11.5977,21.175 12.5137,22L17.4863,22C18.4023,21.175 19,19.922 19,18.5C19,16.015 17.209,14 15,14zM7,17A1,1 0,0 0,6 18A1,1 0,0 0,7 19A1,1 0,0 0,8 18A1,1 0,0 0,7 17zM23,17A1,1 0,0 0,22 18A1,1 0,0 0,23 19A1,1 0,0 0,24 18A1,1 0,0 0,23 17z"
|
||||||
|
android:fillColor="#F9AA33"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="30dp"
|
||||||
|
android:height="30dp"
|
||||||
|
android:viewportWidth="30"
|
||||||
|
android:viewportHeight="30">
|
||||||
|
<path
|
||||||
|
android:pathData="M4,4C4,4 2,8 2,12C2,15.595 3.757,18.551 8,18.949L8,23.242L4.738,24.031L4.738,24.033A1,1 0,0 0,5 26L8.832,26A1,1 0,0 0,9.158 26L13,26A1,1 0,0 0,13.262 24.031L10,23.242L10,18.949C14.243,18.551 16,15.595 16,12C16,8 14,4 14,4L9,4L4,4zM19,4C18.448,4 18,4.448 18,5L18,10.785C18,13.127 19.541,15.232 21.734,15.822L21,23.826L21.008,23.826A2,2 0,0 0,21 24A2,2 0,0 0,23 26A2,2 0,0 0,25 24A2,2 0,0 0,24.99 23.826L24.992,23.826L24.26,15.834C26.41,15.275 28,13.325 28,11L28,5C28,4.448 27.552,4 27,4C26.448,4 26,4.448 26,5L26,10C26,10.553 25.552,11 25,11C24.448,11 24,10.553 24,10L24,5C24,4.448 23.552,4 23,4C22.448,4 22,4.448 22,5L22,10C22,10.553 21.552,11 21,11C20.448,11 20,10.553 20,10L20,5C20,4.448 19.552,4 19,4zM22.992,15.996C22.995,15.996 22.997,15.998 23,15.998L23,22A2,2 0,0 0,22.992 22L22.992,15.996z"
|
||||||
|
android:fillColor="#FAAB1A"/>
|
||||||
|
</vector>
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M19,13H5v-2h14v2z"/>
|
||||||
|
</vector>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="#C2C2C2" />
|
||||||
|
|
||||||
|
<corners android:radius="50dp" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="#C2C2C2" />
|
||||||
|
|
||||||
|
<corners android:radius="10dp" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/black" />
|
||||||
|
<corners android:radius="20dp" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||||
|
<solid android:color="#A3ADB3"/>
|
||||||
|
<corners android:radius="20dp"/>
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape android:shape="oval"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<solid android:color="@color/white"></solid>
|
||||||
|
|
||||||
|
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
<corners android:radius="5dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="0.8dp"
|
||||||
|
android:color="@color/primary" />
|
||||||
|
</shape>
|
||||||
Binary file not shown.
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".ui.login.LoginActivity">
|
||||||
|
|
||||||
|
|
||||||
|
<nl.joery.animatedbottombar.AnimatedBottomBar
|
||||||
|
android:id="@+id/tabBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/primary"
|
||||||
|
app:abb_animationInterpolator="@android:anim/overshoot_interpolator"
|
||||||
|
app:abb_badgeBackgroundColor="@color/white"
|
||||||
|
app:abb_badgeTextColor="@color/white"
|
||||||
|
app:abb_iconSize="30dp"
|
||||||
|
app:abb_indicatorAppearance="round"
|
||||||
|
app:abb_indicatorColor="@color/black"
|
||||||
|
app:abb_indicatorHeight="5dp"
|
||||||
|
app:abb_indicatorLocation="bottom"
|
||||||
|
app:abb_indicatorMargin="16dp"
|
||||||
|
app:abb_selectedIndex="0"
|
||||||
|
app:abb_selectedTabType="icon"
|
||||||
|
app:abb_tabColor="@color/white"
|
||||||
|
app:abb_tabColorSelected="@color/white"
|
||||||
|
app:abb_tabs="@menu/tabs"
|
||||||
|
app:abb_textAppearance="@style/CustomText"
|
||||||
|
app:abb_textSize="16sp"
|
||||||
|
app:abb_textStyle="bold"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
|
android:id="@+id/viewPager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/tabBar" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".ui.MainActivity">
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.fragment.app.FragmentContainerView
|
||||||
|
android:id="@+id/fragmentContainerView"
|
||||||
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:defaultNavHost="true"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/navigation_view"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:navGraph="@navigation/nav_graph" />
|
||||||
|
|
||||||
|
<me.ibrahimsn.lib.SmoothBottomBar
|
||||||
|
android:id="@+id/navigation_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
app:backgroundColor="@color/primary"
|
||||||
|
app:cornerRadius="0dp"
|
||||||
|
app:corners="all"
|
||||||
|
app:iconSize="22dp"
|
||||||
|
app:iconTint="@color/black"
|
||||||
|
app:iconTintActive="@color/black"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:menu="@menu/menu"
|
||||||
|
app:textColor="@color/black"
|
||||||
|
app:textSize="15sp" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background"
|
||||||
|
tools:context=".ui.SplashActivity">
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_margin="@dimen/margin_small"
|
||||||
|
app:cardCornerRadius="50dp"
|
||||||
|
app:cardElevation="@dimen/card_elevation_small"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:strokeColor="@color/primary"
|
||||||
|
app:strokeWidth="2dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/materialCardView2"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
app:cardCornerRadius="50dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:strokeColor="@color/primary"
|
||||||
|
app:strokeWidth="2dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/productCount"
|
||||||
|
android:layout_width="60dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/primary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:translationZ="90dp"
|
||||||
|
tools:text="3X" />
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/productText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start|center"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="start"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/primary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:translationZ="90dp"
|
||||||
|
tools:text="textView" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/productPrice"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start|center"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="0.00 ₽"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/green"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:translationZ="90dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/deleteBasketProduct"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginVertical="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
app:cardBackgroundColor="@color/red100"
|
||||||
|
app:cardCornerRadius="50dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="35dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:contentDescription="@string/delete"
|
||||||
|
android:padding="@dimen/padding_small"
|
||||||
|
app:srcCompat="@drawable/ic_baseline_delete_outline_24"
|
||||||
|
app:tint="@color/red800" />
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/cardView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/margin_small"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
app:cardCornerRadius="20dp"
|
||||||
|
app:cardElevation="@dimen/card_elevation_small"
|
||||||
|
app:strokeColor="@color/primary"
|
||||||
|
app:strokeWidth="2dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/categoryImageView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:srcCompat="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/categoryText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_margin="@dimen/margin_small"
|
||||||
|
android:gravity="start"
|
||||||
|
android:text="textView"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="@color/primary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:translationZ="90dp" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:src="@drawable/ic_cash" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:text="Demo"
|
||||||
|
android:textColor="@color/primary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user