├── app
├── .gitignore
├── .DS_Store
├── src
│ ├── .DS_Store
│ ├── main
│ │ ├── .DS_Store
│ │ ├── res
│ │ │ ├── .DS_Store
│ │ │ ├── drawable
│ │ │ │ ├── man.png
│ │ │ │ ├── child.png
│ │ │ │ ├── login.png
│ │ │ │ ├── man2.png
│ │ │ │ ├── woman2.png
│ │ │ │ ├── ic_user_placeholder.png
│ │ │ │ ├── count_image_background.xml
│ │ │ │ ├── drawable_gender_tab_text_color_selector.xml
│ │ │ │ ├── ic_remove.xml
│ │ │ │ ├── ic_add.xml
│ │ │ │ ├── user_image_background.xml
│ │ │ │ ├── ic_arrow_back.xml
│ │ │ │ ├── item_grey_border_background.xml
│ │ │ │ ├── app_gradient_color_background.xml
│ │ │ │ ├── ic_person.xml
│ │ │ │ ├── ic_cancel.xml
│ │ │ │ ├── ic_full_fav.xml
│ │ │ │ ├── ic_add_photo.xml
│ │ │ │ ├── ic_favorite.xml
│ │ │ │ ├── ic_question_mark.xml
│ │ │ │ ├── ic_favorite_border.xml
│ │ │ │ ├── ic_share.xml
│ │ │ │ ├── ic_basket.xml
│ │ │ │ ├── ic_home.xml
│ │ │ │ ├── drawable_gender_tab_selector.xml
│ │ │ │ └── ic_profile.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.webp
│ │ │ │ └── ic_launcher_round.webp
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── anim
│ │ │ │ ├── enter_anim.xml
│ │ │ │ ├── exit_anim.xml
│ │ │ │ ├── popup_exit_anim.xml
│ │ │ │ ├── enter_anim_column.xml
│ │ │ │ ├── exit_anim_column.xml
│ │ │ │ ├── popup_enter_anim.xml
│ │ │ │ ├── popup_enter_anim_column.xml
│ │ │ │ └── popup_exit_anim_column.xml
│ │ │ ├── xml
│ │ │ │ ├── backup_rules.xml
│ │ │ │ └── data_extraction_rules.xml
│ │ │ ├── menu
│ │ │ │ └── bottom_menu.xml
│ │ │ ├── values-night
│ │ │ │ └── themes.xml
│ │ │ ├── layout
│ │ │ │ ├── item_category.xml
│ │ │ │ ├── fragment_splash.xml
│ │ │ │ ├── toolbar.xml
│ │ │ │ ├── dialog_progress.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── fragment_favorite.xml
│ │ │ │ ├── fragment_login_regiser.xml
│ │ │ │ ├── fragment_products.xml
│ │ │ │ ├── fragment_success.xml
│ │ │ │ ├── fragment_basket.xml
│ │ │ │ ├── fragment_password_forgot.xml
│ │ │ │ ├── item_fav.xml
│ │ │ │ ├── item_products.xml
│ │ │ │ ├── fragment_home.xml
│ │ │ │ ├── fragment_profile.xml
│ │ │ │ ├── term_condition_sheet.xml
│ │ │ │ ├── fragment_sign_in.xml
│ │ │ │ ├── item_basket.xml
│ │ │ │ └── fragment_product_detail.xml
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── themes.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── dimens.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── navigation
│ │ │ │ ├── auth_graph.xml
│ │ │ │ └── main_graph.xml
│ │ ├── assets
│ │ │ ├── Montserrat-Bold.ttf
│ │ │ └── Montserrat-Regular.ttf
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── sum
│ │ │ │ └── shop
│ │ │ │ ├── model
│ │ │ │ ├── CategoryModel.kt
│ │ │ │ ├── ProfileModel.kt
│ │ │ │ ├── ProductModel.kt
│ │ │ │ ├── FavModel.kt
│ │ │ │ └── BasketModel.kt
│ │ │ │ ├── di
│ │ │ │ ├── FirebaseApplication.kt
│ │ │ │ ├── FirebaseModule.kt
│ │ │ │ └── LocaleModule.kt
│ │ │ │ ├── utils
│ │ │ │ ├── resource
│ │ │ │ │ └── Resource.kt
│ │ │ │ ├── customs
│ │ │ │ │ ├── Button.kt
│ │ │ │ │ ├── EditText.kt
│ │ │ │ │ ├── BoldTextView.kt
│ │ │ │ │ ├── RadioButton.kt
│ │ │ │ │ └── NormalTextView.kt
│ │ │ │ ├── diffutil
│ │ │ │ │ └── DiffUtilCallback.kt
│ │ │ │ ├── constant
│ │ │ │ │ └── Constant.kt
│ │ │ │ └── extension
│ │ │ │ │ └── Extension.kt
│ │ │ │ ├── room
│ │ │ │ ├── FavProductDatabase.kt
│ │ │ │ ├── FavProductDao.kt
│ │ │ │ └── BasketProductDao.kt
│ │ │ │ ├── ui
│ │ │ │ ├── loginregister
│ │ │ │ │ ├── signin
│ │ │ │ │ │ ├── SignInViewModel.kt
│ │ │ │ │ │ └── SignInFragment.kt
│ │ │ │ │ ├── TabAdapter.kt
│ │ │ │ │ ├── LoginRegister.kt
│ │ │ │ │ └── signup
│ │ │ │ │ │ ├── SignUpTermConditionViewModel.kt
│ │ │ │ │ │ ├── TermConditionBottomSheet.kt
│ │ │ │ │ │ └── SignUpFragment.kt
│ │ │ │ ├── forgotpassword
│ │ │ │ │ ├── ForgotPasswordViewModel.kt
│ │ │ │ │ └── ForgotPasswordFragment.kt
│ │ │ │ ├── success
│ │ │ │ │ ├── SuccessViewModel.kt
│ │ │ │ │ └── SuccessFragment.kt
│ │ │ │ ├── profile
│ │ │ │ │ ├── ProfileViewModel.kt
│ │ │ │ │ └── ProfileFragment.kt
│ │ │ │ ├── products
│ │ │ │ │ ├── ProductsViewModel.kt
│ │ │ │ │ ├── ProductsFragment.kt
│ │ │ │ │ └── ProductsAdapter.kt
│ │ │ │ ├── productdetail
│ │ │ │ │ ├── ProductDetailViewModel.kt
│ │ │ │ │ └── ProductDetailFragment.kt
│ │ │ │ ├── addproduct
│ │ │ │ │ ├── AddProductViewModel.kt
│ │ │ │ │ └── AddProductFragment.kt
│ │ │ │ ├── favorite
│ │ │ │ │ ├── FavoriteViewModel.kt
│ │ │ │ │ ├── FavoriteFragment.kt
│ │ │ │ │ └── FavoriteAdapter.kt
│ │ │ │ ├── updateprofile
│ │ │ │ │ └── UpdateProfileViewModel.kt
│ │ │ │ ├── splash
│ │ │ │ │ └── SplashFragment.kt
│ │ │ │ ├── basket
│ │ │ │ │ ├── BasketViewModel.kt
│ │ │ │ │ ├── BasketFragment.kt
│ │ │ │ │ └── BasketAdapter.kt
│ │ │ │ ├── home
│ │ │ │ │ ├── CategoryAdapter.kt
│ │ │ │ │ └── HomeFragment.kt
│ │ │ │ └── payment
│ │ │ │ │ └── PaymentFragment.kt
│ │ │ │ ├── delegate
│ │ │ │ └── ViewBindingDelegate.kt
│ │ │ │ └── MainActivity.kt
│ │ └── AndroidManifest.xml
│ ├── debug
│ │ ├── ic_launcher-playstore.png
│ │ └── res
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_round.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── values
│ │ │ └── ic_launcher_background.xml
│ │ │ └── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── sum
│ │ │ └── shop
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── sum
│ │ └── shop
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
├── google-services.json
└── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── local.properties
├── settings.gradle
├── gradle.properties
├── gradlew.bat
└── README.md
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/.DS_Store
--------------------------------------------------------------------------------
/app/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/.DS_Store
--------------------------------------------------------------------------------
/app/src/main/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/.DS_Store
--------------------------------------------------------------------------------
/app/src/main/res/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/.DS_Store
--------------------------------------------------------------------------------
/app/src/main/res/drawable/man.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/drawable/man.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/child.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/drawable/child.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/drawable/login.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/man2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/drawable/man2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/woman2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/drawable/woman2.png
--------------------------------------------------------------------------------
/app/src/debug/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/assets/Montserrat-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/assets/Montserrat-Bold.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/Montserrat-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/assets/Montserrat-Regular.ttf
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_user_placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/drawable/ic_user_placeholder.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sumeyraozugur/Firebase-Shop-App/HEAD/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/model/CategoryModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.model
2 |
3 | data class CategoryModel(
4 | val categoryName: String,
5 | val categoryImage: Int
6 | )
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/di/FirebaseApplication.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.di
2 |
3 | import android.app.Application
4 | import dagger.hilt.android.HiltAndroidApp
5 |
6 | @HiltAndroidApp
7 | class FirebaseApplication : Application()
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/model/ProfileModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.model
2 |
3 | data class ProfileModel(
4 | val firstName: String?,
5 | val lastName: String?,
6 | val email: String?,
7 | val picture: String?
8 | )
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Sep 25 23:34:18 TRT 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/utils/resource/Resource.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.utils.resource
2 |
3 | sealed class Resource {
4 | object Loading : Resource()
5 | data class Success(val data: Boolean) : Resource()
6 | data class Error(val throwable: Throwable) : Resource()
7 | }
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/enter_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/exit_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/popup_exit_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/enter_anim_column.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/exit_anim_column.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/popup_enter_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/popup_enter_anim_column.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/popup_exit_anim_column.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/count_image_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/drawable_gender_tab_text_color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Mon Mar 13 00:51:48 TRT 2023
8 | sdk.dir=/Users/sumeyra/Library/Android/sdk
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_remove.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "Shop"
16 | include ':app'
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/user_image_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_back.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/test/java/com/sum/shop/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * See [testing documentation](http://d.android.com/tools/testing).
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/item_grey_border_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/utils/customs/Button.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.utils.customs
2 |
3 | import android.content.Context
4 | import android.graphics.Typeface
5 | import android.util.AttributeSet
6 | import androidx.appcompat.widget.AppCompatButton
7 |
8 | class Button(context: Context, attrs: AttributeSet) : AppCompatButton(context, attrs) {
9 |
10 | init {
11 | typeface = Typeface.createFromAsset(context.assets, "Montserrat-Bold.ttf")
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/app_gradient_color_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/utils/customs/EditText.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.utils.customs
2 |
3 | import android.content.Context
4 | import android.graphics.Typeface
5 | import android.util.AttributeSet
6 | import androidx.appcompat.widget.AppCompatEditText
7 |
8 | class EditText(context: Context, attrs: AttributeSet) : AppCompatEditText(context, attrs) {
9 |
10 |
11 | init {
12 | typeface = Typeface.createFromAsset(context.assets, "Montserrat-Regular.ttf")
13 | }
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/utils/customs/BoldTextView.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.utils.customs
2 |
3 | import android.content.Context
4 | import android.graphics.Typeface
5 | import android.util.AttributeSet
6 | import androidx.appcompat.widget.AppCompatTextView
7 |
8 | class BoldTextView(context: Context, attrs: AttributeSet) : AppCompatTextView(context, attrs) {
9 |
10 | init {
11 | typeface = Typeface.createFromAsset(context.assets, "Montserrat-Bold.ttf")
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/model/ProductModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.model
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class ProductModel(
8 | val id: String,
9 | val img: String,
10 | val productTitle: String,
11 | val productDescription: String,
12 | val productPrice: String,
13 | val productCount: String,
14 | var productFav: Boolean = false,
15 | var totalAmount: Double = 0.0
16 | ) : Parcelable
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/room/FavProductDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.room
2 |
3 | import androidx.room.Database
4 | import androidx.room.RoomDatabase
5 | import com.sum.shop.model.BasketModel
6 | import com.sum.shop.model.FavModel
7 |
8 | @Database(entities = [FavModel::class, BasketModel::class], version = 1, exportSchema = false)
9 | abstract class FavProductDatabase : RoomDatabase() {
10 | abstract fun favDao(): FavProductDao
11 | abstract fun basketDao(): BasketProductDao
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/utils/customs/RadioButton.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.utils.customs
2 |
3 | import android.content.Context
4 | import android.graphics.Typeface
5 | import android.util.AttributeSet
6 | import androidx.appcompat.widget.AppCompatRadioButton
7 |
8 | class RadioButton(context: Context, attrs: AttributeSet) :
9 | AppCompatRadioButton(context, attrs) {
10 |
11 |
12 | init {
13 | typeface = Typeface.createFromAsset(context.assets, "Montserrat-Bold.ttf")
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/utils/customs/NormalTextView.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.utils.customs
2 |
3 |
4 | import android.content.Context
5 | import android.graphics.Typeface
6 | import android.util.AttributeSet
7 | import androidx.appcompat.widget.AppCompatTextView
8 |
9 |
10 | class NormalTextView(context: Context, attrs: AttributeSet) : AppCompatTextView(context, attrs) {
11 |
12 | init {
13 | typeface = Typeface.createFromAsset(context.assets, "Montserrat-Regular.ttf")
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cancel.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_full_fav.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/room/FavProductDao.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.room
2 |
3 | import androidx.room.*
4 | import com.sum.shop.model.FavModel
5 |
6 | @Dao
7 | interface FavProductDao {
8 |
9 | @Insert(onConflict = OnConflictStrategy.REPLACE)
10 | suspend fun addToFav(fav: FavModel)
11 |
12 | @Query("SELECT * FROM fav_table ORDER BY fav_id ASC")
13 | suspend fun getAllFav(): List
14 |
15 | @Query("SELECT fav_title FROM fav_table")
16 | suspend fun getFavTitles(): List?
17 |
18 | @Delete
19 | suspend fun deleteFromFav(fav: FavModel)
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/model/FavModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.model
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 |
6 | @Entity(
7 | tableName = "fav_table",
8 | primaryKeys = ["fav_id", "uuid"]
9 | )
10 | data class FavModel(
11 |
12 | @ColumnInfo(name = "fav_id")
13 | val id: Int = 0,
14 |
15 | @ColumnInfo(name = "uuid")
16 | val uuid: String = "",
17 |
18 | @ColumnInfo(name = "fav_img")
19 | val img: String,
20 |
21 | @ColumnInfo(name = "fav_title")
22 | val productTitle: String,
23 |
24 | @ColumnInfo(name = "fav_price")
25 | val productPrice: String
26 | )
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/loginregister/signin/SignInViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.loginregister.signin
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.ViewModel
5 | import com.sum.shop.repository.FirebaseAuthRepository
6 | import dagger.hilt.android.lifecycle.HiltViewModel
7 | import javax.inject.Inject
8 |
9 | @HiltViewModel
10 | class SignInViewModel @Inject constructor(private val firebaseRepo: FirebaseAuthRepository) :
11 | ViewModel() {
12 |
13 | val isSingnIn: LiveData = firebaseRepo.isSignIn
14 |
15 | fun signIn(email: String, password: String) = firebaseRepo.signIn(email, password)
16 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_photo.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/utils/diffutil/DiffUtilCallback.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.utils.diffutil
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 |
5 | class DiffUtilCallback(
6 | private val itemsTheSame: (T, T) -> Boolean = { _, _ -> false },
7 | private val contentsTheSame: (T, T) -> Boolean = { _, _ -> false }
8 | ) : DiffUtil.ItemCallback() {
9 |
10 | override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
11 | return itemsTheSame(oldItem, newItem)
12 | }
13 |
14 | override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
15 | return contentsTheSame(oldItem, newItem)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/forgotpassword/ForgotPasswordViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.forgotpassword
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.ViewModel
5 | import com.sum.shop.repository.FirebaseAuthRepository
6 | import dagger.hilt.android.lifecycle.HiltViewModel
7 | import javax.inject.Inject
8 |
9 | @HiltViewModel
10 | class ForgotPasswordViewModel @Inject constructor(private val firebaseRepo: FirebaseAuthRepository) :
11 | ViewModel() {
12 |
13 | private val _isSuccess = firebaseRepo.isSuccess
14 | val isSuccess: LiveData = _isSuccess
15 |
16 | fun changePassword(email: String) = firebaseRepo.changePassword(email)
17 |
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/loginregister/TabAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.loginregister
2 |
3 | import androidx.fragment.app.Fragment
4 | import androidx.viewpager2.adapter.FragmentStateAdapter
5 | import com.sum.shop.ui.loginregister.signin.SignInFragment
6 | import com.sum.shop.ui.loginregister.signup.SignUpFragment
7 |
8 | class TabAdapter(fragment: Fragment) :
9 | FragmentStateAdapter(fragment) {
10 |
11 | override fun getItemCount(): Int = 2
12 |
13 | override fun createFragment(position: Int): Fragment {
14 | when (position) {
15 | 0 -> return SignInFragment()
16 | 1 -> return SignUpFragment()
17 | }
18 | return SignInFragment()
19 | }
20 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_question_mark.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite_border.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/sum/shop/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import androidx.test.platform.app.InstrumentationRegistry
5 | import org.junit.Assert.*
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * See [testing documentation](http://d.android.com/tools/testing).
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.sum.shop", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_share.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/model/BasketModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.model
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 |
6 | @Entity(tableName = "basket_table", primaryKeys = ["basket_id", "uuid"])
7 | data class BasketModel(
8 |
9 | @ColumnInfo(name = "basket_id")
10 | val id: Int = 0,
11 |
12 | @ColumnInfo(name = "uuid")
13 | val uuid: String = "",
14 |
15 | @ColumnInfo(name = "basket_img")
16 | val img: String,
17 |
18 | @ColumnInfo(name = "basket_title")
19 | val productTitle: String,
20 |
21 | @ColumnInfo(name = "basket_price")
22 | val productPrice: Int,
23 |
24 | @ColumnInfo(name = "basket_count")
25 | val productCount: String
26 | ) {
27 | var count = 1
28 | }
29 | //val abc = BasketModel().copy(productCount = "asasa") //keep in mind
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/room/BasketProductDao.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.room
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.room.*
5 | import com.sum.shop.model.BasketModel
6 |
7 | @Dao
8 | interface BasketProductDao {
9 |
10 | @Insert(onConflict = OnConflictStrategy.REPLACE)
11 | suspend fun addToBasket(basket: BasketModel)
12 |
13 | @Query("SELECT * FROM basket_table ORDER BY basket_id ASC")
14 | fun readAllBasket(): LiveData>
15 |
16 | @Query("DELETE FROM basket_table WHERE uuid = :idInput")
17 | suspend fun deleteFromBasket(idInput: String)
18 |
19 | @Query("SELECT SUM(count * basket_price) FROM basket_table")
20 | suspend fun getTotalPrice(): Double
21 |
22 | @Update
23 | suspend fun updateBasket(basket: BasketModel) // For count in adapter
24 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_basket.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/di/FirebaseModule.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.di
2 |
3 | import com.google.firebase.auth.FirebaseAuth
4 | import com.google.firebase.firestore.FirebaseFirestore
5 | import com.google.firebase.storage.FirebaseStorage
6 | import dagger.Module
7 | import dagger.Provides
8 | import dagger.hilt.InstallIn
9 |
10 | import dagger.hilt.components.SingletonComponent
11 | import javax.inject.Singleton
12 |
13 | @Module
14 | @InstallIn(SingletonComponent::class)
15 | object FirebaseModule {
16 |
17 | @Singleton
18 | @Provides
19 | fun provideFirebaseAuth(): FirebaseAuth = FirebaseAuth.getInstance()
20 |
21 | @Singleton
22 | @Provides
23 | fun provideFirebaseFirestore(): FirebaseFirestore = FirebaseFirestore.getInstance()
24 |
25 | @Singleton
26 | @Provides
27 | fun provideFirebaseStorage(): FirebaseStorage = FirebaseStorage.getInstance()
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/success/SuccessViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.success
2 |
3 |
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.sum.shop.model.BasketModel
8 | import com.sum.shop.repository.ProductRepository
9 | import dagger.hilt.android.lifecycle.HiltViewModel
10 | import kotlinx.coroutines.Dispatchers
11 | import kotlinx.coroutines.launch
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class SuccessViewModel @Inject constructor(private val repository: ProductRepository) :
16 | ViewModel() {
17 |
18 | val readAllBasket: LiveData> = repository.readAllBasket
19 |
20 | fun deleteFromBasket(basketId: String) {
21 | viewModelScope.launch(Dispatchers.IO) {
22 | repository.deleteFromBasket(basketId)
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_home.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/profile/ProfileViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.profile
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.ViewModel
5 | import com.sum.shop.model.ProfileModel
6 | import com.sum.shop.repository.FirebaseAuthRepository
7 | import dagger.hilt.android.lifecycle.HiltViewModel
8 | import javax.inject.Inject
9 |
10 | @HiltViewModel
11 | class ProfileViewModel @Inject constructor(val firebaseRepo: FirebaseAuthRepository) : ViewModel() {
12 |
13 | private var _profileInfo = firebaseRepo.profileInfo
14 | val profileInfo: LiveData = _profileInfo
15 |
16 | private var _isLoading = firebaseRepo.isLoading
17 | val isLoading: LiveData = _isLoading
18 |
19 | init {
20 | getProfileInfo()
21 | }
22 |
23 | private fun getProfileInfo() {
24 | firebaseRepo.getProfileInfo()
25 | _profileInfo = firebaseRepo.profileInfo
26 | }
27 |
28 | fun signOut() = firebaseRepo.signOut()
29 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/products/ProductsViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.products
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.sum.shop.model.ProductModel
8 | import com.sum.shop.repository.ProductRepository
9 | import dagger.hilt.android.lifecycle.HiltViewModel
10 | import kotlinx.coroutines.launch
11 | import javax.inject.Inject
12 |
13 | @HiltViewModel
14 | class ProductsViewModel @Inject constructor(private val firebaseRepo: ProductRepository) :
15 | ViewModel() {
16 |
17 | var categoryList = MutableLiveData>()
18 | var path = firebaseRepo.path
19 |
20 | private val _isLoading = firebaseRepo.isLoading
21 | val isLoading: LiveData = _isLoading
22 |
23 |
24 | fun getProduct(path: String) = viewModelScope.launch {
25 | categoryList.value = firebaseRepo.getProductRealtime(path)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/utils/constant/Constant.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.utils.constant
2 |
3 | object Constant {
4 | const val SIGN_IN = "SIGN IN"
5 | const val SIGN_UP = "SIGN UP"
6 | const val USERS_PATH = "users"
7 | const val SUCCESS = "Success"
8 | const val ID = "id"
9 | const val E_MAIL = "email"
10 | const val FIRST_NAME = "firstname"
11 | const val PROFILE_PICTURE = "picture"
12 | const val LAST_NAME = "lastname"
13 | const val PRODUCT_IMAGE = "image"
14 | const val PRODUCT_TITLE = "title"
15 | const val PRODUCT_PRICE = "price"
16 | const val PRODUCT_DESCRIPTION = "description"
17 | const val PRODUCT_QUANTILES = "quantiles"
18 | const val PRODUCT_TYPE = "type"
19 | const val PRODUCT_DATE = "date"
20 | const val PRODUCT_TIME = "time"
21 | const val PROFILE_PICTURE_LINK =
22 | "https://firebasestorage.googleapis.com/v0/b/mytimeline-3b8ed.appspot.com/o/8rSIYAZDvdgS6iyqO2wBIYbz2692?alt=media&token=25fda3bc-7307-4a7e-be69-8c87319496f5"
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/loginregister/LoginRegister.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.loginregister
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import com.google.android.material.tabs.TabLayoutMediator
7 | import com.sum.shop.R
8 | import com.sum.shop.databinding.FragmentLoginRegiserBinding
9 | import com.sum.shop.delegate.viewBinding
10 | import com.sum.shop.utils.constant.Constant
11 |
12 |
13 | class LoginRegister : Fragment(R.layout.fragment_login_regiser) {
14 | private val binding by viewBinding(FragmentLoginRegiserBinding::bind)
15 | private val titleList = arrayListOf(Constant.SIGN_IN, Constant.SIGN_UP)
16 |
17 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
18 | super.onViewCreated(view, savedInstanceState)
19 |
20 |
21 | binding.viewPager.adapter = TabAdapter(this)
22 |
23 | TabLayoutMediator(binding.loginRegisterTabLayout, binding.viewPager) { tab, position ->
24 | tab.text = titleList[position]
25 | }.attach()
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #5e35b1
4 | #2F127A
5 | #9162e4
6 | #916ECF
7 | #FFFFFF
8 |
9 | #222934
10 | #FFFFFFFF
11 | #000000
12 | #C3C3C3
13 | #989898
14 | #878787
15 | #E8E6E6
16 | #5956E9
17 | #BA2418
18 | #550D07
19 | #E1E1E1
20 | #fafafa
21 |
22 |
23 | #8BC34A
24 | #F72400
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/productdetail/ProductDetailViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.productdetail
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.sum.shop.model.BasketModel
6 | import com.sum.shop.model.FavModel
7 | import com.sum.shop.repository.ProductRepository
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.launch
11 | import javax.inject.Inject
12 |
13 | @HiltViewModel
14 | class ProductDetailViewModel @Inject constructor(private val repository: ProductRepository) :
15 | ViewModel() {
16 |
17 | fun addToFav(fav: FavModel) {
18 | viewModelScope.launch(Dispatchers.IO) {
19 | repository.addToFav(fav)
20 | }
21 | }
22 |
23 | fun addToBasket(basket: BasketModel) {
24 | viewModelScope.launch(Dispatchers.IO) {
25 | repository.addToBasket(basket)
26 | }
27 | }
28 |
29 | fun deleteFromFav(fav: FavModel) {
30 | viewModelScope.launch(Dispatchers.IO) {
31 | repository.deleteFromFav(fav)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/loginregister/signup/SignUpTermConditionViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.loginregister.signup
2 |
3 | import android.net.Uri
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.ViewModel
7 | import com.sum.shop.repository.FirebaseAuthRepository
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import javax.inject.Inject
10 |
11 | @HiltViewModel
12 | class SignUpTermConditionViewModel @Inject constructor(private val firebaseRepo: FirebaseAuthRepository) :
13 | ViewModel() {
14 |
15 | private var _isSuccess = firebaseRepo.isSuccess
16 | val isSuccess: LiveData = _isSuccess
17 |
18 | val resultOk = MutableLiveData()
19 |
20 |
21 | fun signUp(
22 | firstName: String,
23 | lastName: String,
24 | eMail: String,
25 | password: String,
26 | picture: Uri,
27 | isAccept: Boolean
28 | ) = firebaseRepo.signUp(firstName, lastName, eMail, password, picture)
29 |
30 | //check radio button clicked or not
31 | fun checkResult() {
32 | resultOk.value = true
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/addproduct/AddProductViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.addproduct
2 |
3 | import android.net.Uri
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.ViewModel
6 | import com.sum.shop.repository.ProductRepository
7 | import dagger.hilt.android.lifecycle.HiltViewModel
8 | import javax.inject.Inject
9 |
10 | @HiltViewModel
11 | class AddProductViewModel @Inject constructor(
12 | private val firebaseRepo: ProductRepository,
13 | ) : ViewModel() {
14 |
15 | private val _isSuccess = firebaseRepo.isSuccess
16 | val isSuccess: LiveData = _isSuccess
17 |
18 | private val _isLoading = firebaseRepo.isLoading
19 | val isLoading: LiveData = _isLoading
20 |
21 | fun addProduct(
22 | img: Uri,
23 | productTitle: String,
24 | productPrice: String,
25 | productDescription: String,
26 | productQuantiles: String,
27 | productType: String,
28 | ) = firebaseRepo.addProduct(
29 | img,
30 | productTitle,
31 | productPrice,
32 | productDescription,
33 | productQuantiles,
34 | productType
35 | )
36 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/drawable_gender_tab_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | -
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/favorite/FavoriteViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.favorite
2 |
3 | import androidx.lifecycle.MutableLiveData
4 | import androidx.lifecycle.ViewModel
5 | import androidx.lifecycle.viewModelScope
6 | import com.sum.shop.model.FavModel
7 | import com.sum.shop.repository.ProductRepository
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import kotlinx.coroutines.Dispatchers
10 | import kotlinx.coroutines.launch
11 | import javax.inject.Inject
12 |
13 | @HiltViewModel
14 | class FavoriteViewModel @Inject constructor(private val repository: ProductRepository) :
15 | ViewModel() {
16 |
17 | var favList = MutableLiveData>()
18 |
19 | init {
20 | getAllFav()
21 | favList = repository.returnFavList()
22 | }
23 |
24 |
25 | fun deleteFromFav(fav: FavModel) {
26 | viewModelScope.launch(Dispatchers.IO) {
27 | repository.deleteFromFav(fav)
28 | getAllFav() //to update the list as soon as it is deleted
29 | }
30 | }
31 |
32 | private fun getAllFav() {
33 | viewModelScope.launch(Dispatchers.IO) {
34 | repository.getAllFav()
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
16 |
17 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/di/LocaleModule.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.di
2 |
3 | import android.content.Context
4 | import androidx.room.Room
5 | import com.sum.shop.room.BasketProductDao
6 | import com.sum.shop.room.FavProductDao
7 | import com.sum.shop.room.FavProductDatabase
8 | import dagger.Module
9 | import dagger.Provides
10 | import dagger.hilt.InstallIn
11 | import dagger.hilt.android.qualifiers.ApplicationContext
12 | import dagger.hilt.components.SingletonComponent
13 | import javax.inject.Singleton
14 |
15 | @Module
16 | @InstallIn(SingletonComponent::class)
17 | object LocaleModule {
18 |
19 | @Provides
20 | @Singleton
21 | fun provideBasketProductDatabase(@ApplicationContext context: Context): FavProductDatabase =
22 | Room.databaseBuilder(context, FavProductDatabase::class.java, "product_database")
23 | .fallbackToDestructiveMigration().build()
24 |
25 | @Provides
26 | @Singleton
27 | fun provideBasketDao(basketProductDatabase: FavProductDatabase): BasketProductDao =
28 | basketProductDatabase.basketDao()
29 |
30 |
31 | @Provides
32 | @Singleton
33 | fun provideFavDao(favProductDatabase: FavProductDatabase): FavProductDao =
34 | favProductDatabase.favDao()
35 | }
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/favorite/FavoriteFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.favorite
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.viewModels
7 | import com.sum.shop.R
8 | import com.sum.shop.databinding.FragmentFavoriteBinding
9 | import com.sum.shop.delegate.viewBinding
10 | import com.sum.shop.utils.extension.visible
11 | import dagger.hilt.android.AndroidEntryPoint
12 |
13 | @AndroidEntryPoint
14 | class FavoriteFragment : Fragment(R.layout.fragment_favorite) {
15 | private val binding by viewBinding(FragmentFavoriteBinding::bind)
16 | private val viewModel: FavoriteViewModel by viewModels()
17 | private val adapter by lazy { FavoriteAdapter(viewModel::deleteFromFav) }
18 |
19 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
20 | super.onViewCreated(view, savedInstanceState)
21 |
22 | initializeObserver()
23 |
24 | binding.rvFav.adapter = adapter
25 | }
26 |
27 |
28 | private fun initializeObserver() {
29 | viewModel.favList.observe(viewLifecycleOwner) { favList ->
30 | adapter.submitList(favList)
31 | if (favList.isEmpty()) {
32 | binding.tvFavEmpty.visible()
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/updateprofile/UpdateProfileViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.updateprofile
2 |
3 | import android.net.Uri
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.ViewModel
6 | import com.sum.shop.model.ProfileModel
7 | import com.sum.shop.repository.FirebaseAuthRepository
8 | import dagger.hilt.android.lifecycle.HiltViewModel
9 | import javax.inject.Inject
10 |
11 | @HiltViewModel
12 | class UpdateProfileViewModel @Inject constructor(private val firebaseRepo: FirebaseAuthRepository) :
13 | ViewModel() {
14 |
15 | private var _profileInfo = firebaseRepo.profileInfo
16 | val profileInfo: LiveData = _profileInfo
17 |
18 | private var _isSuccess = firebaseRepo.isSuccess
19 | val isSuccess: LiveData = _isSuccess
20 |
21 | private var _isLoading = firebaseRepo.isLoading
22 | val isLoading: LiveData = _isLoading
23 |
24 |
25 | init {
26 | getProfileInfo()
27 | }
28 |
29 | private fun getProfileInfo() {
30 | firebaseRepo.getProfileInfo()
31 | _profileInfo = firebaseRepo.profileInfo
32 | }
33 |
34 | fun updateProfile(firstName: String, lastName: String, email: String, picture: Uri) {
35 | firebaseRepo.updateProfile(firstName, lastName, email, picture)
36 | _isSuccess = firebaseRepo.isSuccess
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/delegate/ViewBindingDelegate.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.delegate
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import androidx.appcompat.app.AppCompatActivity
6 | import androidx.fragment.app.Fragment
7 | import androidx.lifecycle.DefaultLifecycleObserver
8 | import androidx.lifecycle.Lifecycle
9 | import androidx.lifecycle.LifecycleOwner
10 | import androidx.viewbinding.ViewBinding
11 | import kotlin.properties.ReadOnlyProperty
12 | import kotlin.reflect.KProperty
13 |
14 | inline fun AppCompatActivity.viewBinding(crossinline factory: (LayoutInflater) -> T) =
15 | lazy(LazyThreadSafetyMode.NONE) {
16 | factory(layoutInflater)
17 | }
18 |
19 | fun Fragment.viewBinding(factory: (View) -> T): ReadOnlyProperty =
20 | object : ReadOnlyProperty, DefaultLifecycleObserver {
21 | private var binding: T? = null
22 |
23 | override fun getValue(thisRef: Fragment, property: KProperty<*>): T =
24 | binding ?: factory(requireView()).also {
25 | if (viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
26 | viewLifecycleOwner.lifecycle.addObserver(this)
27 | binding = it
28 | }
29 | }
30 |
31 | override fun onDestroy(owner: LifecycleOwner) {
32 | binding = null
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_profile.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
19 |
20 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "67584140812",
4 | "firebase_url": "https://mytimeline-3b8ed.firebaseio.com",
5 | "project_id": "mytimeline-3b8ed",
6 | "storage_bucket": "mytimeline-3b8ed.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:67584140812:android:9299065c57a45dcfa53029",
12 | "android_client_info": {
13 | "package_name": "com.sum.shop"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "67584140812-fpsa6mrt347jedbv48g21opk6tg7u8u2.apps.googleusercontent.com",
19 | "client_type": 1,
20 | "android_info": {
21 | "package_name": "com.sum.shop",
22 | "certificate_hash": "7783b95940deb38401a3e0118b134981908efc01"
23 | }
24 | },
25 | {
26 | "client_id": "67584140812-8km03oi96no4s5f9nd7jvh3ilogurvfb.apps.googleusercontent.com",
27 | "client_type": 3
28 | }
29 | ],
30 | "api_key": [
31 | {
32 | "current_key": "AIzaSyB-itWp5YdQqF6bVAvSvrR23zzf_PUwNj8"
33 | }
34 | ],
35 | "services": {
36 | "appinvite_service": {
37 | "other_platform_oauth_client": [
38 | {
39 | "client_id": "67584140812-8km03oi96no4s5f9nd7jvh3ilogurvfb.apps.googleusercontent.com",
40 | "client_type": 3
41 | }
42 | ]
43 | }
44 | }
45 | }
46 | ],
47 | "configuration_version": "1"
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.core.view.isVisible
6 | import androidx.navigation.NavController
7 | import androidx.navigation.fragment.NavHostFragment
8 | import androidx.navigation.ui.NavigationUI
9 | import com.sum.shop.databinding.ActivityMainBinding
10 | import dagger.hilt.android.AndroidEntryPoint
11 |
12 | @AndroidEntryPoint
13 | class MainActivity : AppCompatActivity() {
14 | private lateinit var binding: ActivityMainBinding
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 |
18 | binding = ActivityMainBinding.inflate(layoutInflater)
19 | setContentView(binding.root)
20 |
21 | val navHostFragment =
22 | supportFragmentManager.findFragmentById(R.id.fragment) as NavHostFragment
23 | val navController: NavController = navHostFragment.navController
24 |
25 | //bottom navigation is working correctly
26 | NavigationUI.setupWithNavController(binding.bottomNavigationView, navController)
27 |
28 | //put somewhere where you want to see bottom nav
29 | navController.addOnDestinationChangedListener { _, destination, _ ->
30 | binding.bottomNavigationView.isVisible = destination.id in listOf(
31 | R.id.homeFragment,
32 | R.id.profileFragment,
33 | R.id.favoriteFragment,
34 | R.id.basketFragment
35 | )
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/splash/SplashFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.splash
2 |
3 | import android.animation.Animator
4 | import android.animation.Animator.AnimatorListener
5 | import android.os.Bundle
6 | import android.view.View
7 | import androidx.fragment.app.Fragment
8 | import androidx.navigation.fragment.findNavController
9 | import com.google.firebase.auth.ktx.auth
10 | import com.google.firebase.ktx.Firebase
11 | import com.sum.shop.R
12 | import com.sum.shop.databinding.FragmentSplashBinding
13 | import com.sum.shop.delegate.viewBinding
14 |
15 |
16 | class SplashFragment : Fragment(R.layout.fragment_splash) {
17 |
18 | private val binding by viewBinding(FragmentSplashBinding::bind)
19 |
20 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
21 | super.onViewCreated(view, savedInstanceState)
22 |
23 | binding.lottieSplash.addAnimatorListener(object : AnimatorListener {
24 |
25 | override fun onAnimationEnd(animation: Animator) {
26 | if (Firebase.auth.currentUser != null) {
27 | findNavController().navigate(R.id.action_splashFragment_to_main_graph)
28 | } else {
29 | findNavController().navigate(R.id.action_splashFragment_to_loginRegister)
30 | }
31 | }
32 |
33 | override fun onAnimationStart(animation: Animator) = Unit
34 | override fun onAnimationCancel(animation: Animator) = Unit
35 | override fun onAnimationRepeat(animation: Animator) = Unit
36 |
37 | })
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/loginregister/signup/TermConditionBottomSheet.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.loginregister.signup
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.lifecycle.ViewModelProvider
8 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment
9 | import com.sum.shop.databinding.TermConditionSheetBinding
10 | import dagger.hilt.android.AndroidEntryPoint
11 |
12 | @AndroidEntryPoint
13 | class TermConditionBottomSheet : BottomSheetDialogFragment() {
14 |
15 | private var _binding: TermConditionSheetBinding? = null
16 | private val binding get() = _binding!!
17 |
18 | //private val viewModel:SignUpTermConditionViewModel by viewModels()
19 | private lateinit var viewModel: SignUpTermConditionViewModel
20 |
21 | override fun onCreateView(
22 | inflater: LayoutInflater,
23 | container: ViewGroup?,
24 | savedInstanceState: Bundle?
25 | ): View {
26 | _binding = TermConditionSheetBinding.inflate(inflater, container, false)
27 | return binding.root
28 | }
29 |
30 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
31 | super.onViewCreated(view, savedInstanceState)
32 |
33 | viewModel = ViewModelProvider(requireActivity())[SignUpTermConditionViewModel::class.java]
34 |
35 | binding.btnCancel.setOnClickListener {
36 | dismiss()
37 | }
38 |
39 | binding.btnTermAccept.setOnClickListener {
40 | viewModel.checkResult()
41 | dismiss()
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
23 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_favorite.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
20 |
21 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/success/SuccessFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.success
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.viewModels
7 | import androidx.navigation.Navigation
8 | import androidx.navigation.fragment.navArgs
9 | import com.sum.shop.R
10 | import com.sum.shop.databinding.FragmentSuccessBinding
11 | import com.sum.shop.delegate.viewBinding
12 | import com.sum.shop.utils.extension.sent
13 | import dagger.hilt.android.AndroidEntryPoint
14 |
15 | @AndroidEntryPoint
16 | class SuccessFragment : Fragment(R.layout.fragment_success) {
17 | private val binding by viewBinding(FragmentSuccessBinding::bind)
18 | private val viewModel: SuccessViewModel by viewModels()
19 | private val args: SuccessFragmentArgs by navArgs()
20 |
21 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
22 | super.onViewCreated(view, savedInstanceState)
23 |
24 | val totalAmount = args.objectTotalAmount
25 |
26 | initializeObserver()
27 |
28 | with(binding) {
29 | btnBackShop.setOnClickListener {
30 | Navigation.sent(it, R.id.action_successFragment_to_homeFragment)
31 | }
32 | tvSuccessInformation.text = getString(R.string.success_payment, totalAmount.toString())
33 | }
34 | // Proguard
35 | }
36 |
37 |
38 | private fun initializeObserver() {
39 | viewModel.readAllBasket.observe(viewLifecycleOwner) { basketList ->
40 | basketList.forEach { basketModel ->
41 | viewModel.deleteFromBasket(basketModel.uuid)
42 | }
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_login_regiser.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
25 |
26 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_products.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
25 |
26 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/basket/BasketViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.basket
2 |
3 |
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.ViewModel
7 | import androidx.lifecycle.viewModelScope
8 | import com.sum.shop.model.BasketModel
9 | import com.sum.shop.repository.ProductRepository
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.launch
13 | import javax.inject.Inject
14 |
15 | @HiltViewModel
16 | class BasketViewModel @Inject constructor(private val repository: ProductRepository) : ViewModel() {
17 | val readAllBasket: LiveData> = repository.readAllBasket
18 |
19 | private val _totalAmount = MutableLiveData(0.0)
20 | val totalAmount: LiveData = _totalAmount
21 |
22 | fun deleteFromBasket(basketId: String) {
23 | viewModelScope.launch(Dispatchers.IO) {
24 | repository.deleteFromBasket(basketId)
25 | }
26 | }
27 |
28 | private fun updateBasket(product: BasketModel) {
29 | viewModelScope.launch(Dispatchers.IO) {
30 | repository.updateBasket(product)
31 | }
32 | }
33 |
34 |
35 | fun increase(product: BasketModel) {
36 | _totalAmount.value = _totalAmount.value?.plus(product.productPrice)
37 | updateBasket(product)
38 | }
39 |
40 | fun decrease(product: BasketModel) {
41 | _totalAmount.value = _totalAmount.value?.minus(product.productPrice)
42 | updateBasket(product)
43 | }
44 |
45 | fun resetTotalAmount() {
46 | _totalAmount.value = 0.0
47 | }
48 |
49 | fun totalBasket() {
50 | viewModelScope.launch() {
51 | _totalAmount.value = repository.totalBasket()
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/home/CategoryAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.home
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.ListAdapter
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.sum.shop.databinding.ItemCategoryBinding
8 | import com.sum.shop.model.CategoryModel
9 | import com.sum.shop.utils.diffutil.DiffUtilCallback
10 | import com.sum.shop.utils.extension.loadImage
11 |
12 | class CategoryAdapter(private val onClickCategory: (CategoryModel) -> Unit) :
13 | ListAdapter(
14 | DiffUtilCallback(
15 | itemsTheSame = { oldItem, newItem ->
16 | oldItem == newItem
17 | },
18 | contentsTheSame = { oldItem, newItem ->
19 | oldItem == newItem
20 | }
21 | )
22 | ) {
23 |
24 | inner class CategoryViewHolder(private var itemCategoryBinding: ItemCategoryBinding) :
25 | RecyclerView.ViewHolder(itemCategoryBinding.root) {
26 |
27 | fun bind(categoryModel: CategoryModel) {
28 | with(itemCategoryBinding) {
29 | ivCategories.loadImage(categoryModel.categoryImage)
30 | root.setOnClickListener {
31 | onClickCategory(categoryModel)
32 | }
33 | }
34 | }
35 | }
36 |
37 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryViewHolder {
38 | val binding =
39 | ItemCategoryBinding.inflate(LayoutInflater.from(parent.context), parent, false)
40 | return CategoryViewHolder(binding)
41 | }
42 |
43 | override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) =
44 | holder.bind(currentList[position])
45 |
46 | override fun getItemCount() = currentList.size
47 |
48 |
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/home/HomeFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.home
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.navigation.Navigation
7 | import androidx.navigation.fragment.findNavController
8 | import com.sum.shop.R
9 | import com.sum.shop.databinding.FragmentHomeBinding
10 | import com.sum.shop.delegate.viewBinding
11 | import com.sum.shop.model.CategoryModel
12 | import com.sum.shop.utils.extension.sent
13 |
14 | class HomeFragment : Fragment(R.layout.fragment_home) {
15 | private val binding by viewBinding(FragmentHomeBinding::bind)
16 | private val categoryAdapter by lazy { CategoryAdapter(onClickCategory = ::onClickCategory) }
17 |
18 |
19 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
20 | super.onViewCreated(view, savedInstanceState)
21 |
22 | binding.tvAddStyle.setOnClickListener {
23 | Navigation.sent(it, R.id.action_homeFragment_to_addProductFragment)
24 | }
25 |
26 | val categoryList = arrayListOf()
27 | val woman = CategoryModel(
28 | getString(R.string.woman),
29 | R.drawable.woman2
30 | )
31 | val man = CategoryModel(
32 | getString(R.string.man),
33 | R.drawable.man
34 | )
35 | val child = CategoryModel(
36 | getString(R.string.child),
37 | R.drawable.child
38 | )
39 | categoryList.add(woman)
40 | categoryList.add(man)
41 | categoryList.add(child)
42 | categoryAdapter.submitList(categoryList)
43 | binding.rvCategory.adapter = categoryAdapter
44 | binding.rvCategory.set3DItem(true)
45 | binding.rvCategory.setAlpha(true)
46 | }
47 |
48 | private fun onClickCategory(categoryModel: CategoryModel) {
49 | val action =
50 | HomeFragmentDirections.actionHomeFragmentToProductsFragment(categoryModel.categoryName)
51 | findNavController().navigate(action)
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/favorite/FavoriteAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.favorite
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.ListAdapter
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.sum.shop.R
8 | import com.sum.shop.databinding.ItemFavBinding
9 | import com.sum.shop.model.FavModel
10 | import com.sum.shop.utils.diffutil.DiffUtilCallback
11 | import com.sum.shop.utils.extension.loadImage
12 |
13 | class FavoriteAdapter(private val onRemoveFavClick: (FavModel) -> Unit = {}) :
14 | ListAdapter(
15 | DiffUtilCallback(
16 | itemsTheSame = { oldItem, newItem ->
17 | oldItem == newItem
18 | },
19 | contentsTheSame = { oldItem, newItem ->
20 | oldItem == newItem
21 | }
22 | )
23 | ) {
24 |
25 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavoriteHolder {
26 | val binding = ItemFavBinding.inflate(LayoutInflater.from(parent.context), parent, false)
27 | return FavoriteHolder(binding)
28 | }
29 |
30 | override fun onBindViewHolder(holder: FavoriteHolder, position: Int) {
31 | holder.bind(currentList[position])
32 | }
33 |
34 | inner class FavoriteHolder(private var itemFavBinding: ItemFavBinding) :
35 | RecyclerView.ViewHolder(itemFavBinding.root) {
36 |
37 | fun bind(favModel: FavModel) {
38 | itemFavBinding.apply {
39 | tvFavName.text = favModel.productTitle
40 | val productPrice =
41 | itemView.context.getString(R.string.total_tl, favModel.productPrice)// 10Tl like
42 | tvFavPrice.text = productPrice
43 | ivFav.loadImage(favModel.img)
44 |
45 | ivFavBtn.setOnClickListener {
46 | onRemoveFavClick(favModel)
47 | }
48 | }
49 | }
50 | }
51 |
52 | override fun getItemCount() = currentList.size
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/profile/ProfileFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.profile
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.viewModels
7 | import androidx.navigation.Navigation
8 | import com.bumptech.glide.Glide
9 | import com.sum.shop.R
10 | import com.sum.shop.databinding.FragmentProfileBinding
11 | import com.sum.shop.delegate.viewBinding
12 | import com.sum.shop.utils.extension.*
13 | import dagger.hilt.android.AndroidEntryPoint
14 |
15 | @AndroidEntryPoint
16 | class ProfileFragment : Fragment(R.layout.fragment_profile) {
17 |
18 | private val binding by viewBinding(FragmentProfileBinding::bind)
19 | private val viewModel: ProfileViewModel by viewModels()
20 |
21 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
22 | super.onViewCreated(view, savedInstanceState)
23 | with(binding) {
24 |
25 | initializeObserver()
26 |
27 | tvEdit.setOnClickListener {
28 | Navigation.sent(it, R.id.action_profileFragment_to_updateProfileFragment)
29 | }
30 |
31 | btnLogout.setOnClickListener {
32 | viewModel.signOut()
33 | Navigation.sent(it, R.id.loginRegiser)
34 | }
35 | }
36 | }
37 |
38 | private fun initializeObserver() {
39 | with(binding) {
40 |
41 | viewModel.isLoading.observe(viewLifecycleOwner) {
42 | if (it) {
43 | setViewsGone(ivProfile, tvEdit, ivProfileBorder, tvProfileEmail, btnLogout)
44 | loadingLottie.visible()
45 | } else {
46 | setViewsVisible(ivProfile, tvEdit, ivProfileBorder, tvProfileEmail, btnLogout)
47 | loadingLottie.gone()
48 | }
49 | }
50 |
51 | viewModel.profileInfo.observe(viewLifecycleOwner) {
52 | tvProfileName.text = "${it.firstName} ${it.lastName}"
53 | tvProfileEmail.text = it.email
54 | Glide.with(binding.ivProfile).load(it.picture).into(binding.ivProfile)
55 | }
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/forgotpassword/ForgotPasswordFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.forgotpassword
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.viewModels
7 | import androidx.navigation.Navigation
8 | import androidx.navigation.fragment.findNavController
9 | import com.sum.shop.R
10 | import com.sum.shop.databinding.FragmentPasswordForgotBinding
11 | import com.sum.shop.delegate.viewBinding
12 | import com.sum.shop.utils.extension.back
13 | import com.sum.shop.utils.extension.isValidEmail
14 | import com.sum.shop.utils.extension.showErrorSnackBar
15 | import dagger.hilt.android.AndroidEntryPoint
16 |
17 | @AndroidEntryPoint
18 | class ForgotPasswordFragment : Fragment(R.layout.fragment_password_forgot) {
19 | private val binding by viewBinding(FragmentPasswordForgotBinding::bind)
20 | private val viewModel: ForgotPasswordViewModel by viewModels() // dont use with by lazy
21 |
22 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
23 | super.onViewCreated(view, savedInstanceState)
24 | observeChangePassword()
25 |
26 |
27 | with(binding) {
28 | profileToolbar.ibArrowBack.setOnClickListener {
29 | Navigation.back(it)
30 | }
31 | profileToolbar.tvProductTitle.text = getString(R.string.password)
32 |
33 |
34 | btnSubmit.setOnClickListener {
35 | val emailResult = etEmail.isValidEmail(getString(R.string.invalid_mail))
36 | if (emailResult) {
37 | val email = etEmail.text.toString()
38 | viewModel.changePassword(email)
39 | }
40 | }
41 | }
42 | }
43 |
44 | private fun observeChangePassword() {
45 | viewModel.isSuccess.observe(viewLifecycleOwner) {
46 | if (it) {
47 | requireView().showErrorSnackBar(getString(R.string.email_sent), false)
48 | findNavController().navigate(R.id.action_forgotPasswordFragment_to_loginFragment)
49 | } else {
50 | requireView().showErrorSnackBar(getString(R.string.fail), true)
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/loginregister/signin/SignInFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.loginregister.signin
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.viewModels
7 | import androidx.navigation.Navigation
8 | import androidx.navigation.fragment.findNavController
9 | import com.sum.shop.R
10 | import com.sum.shop.databinding.FragmentSignInBinding
11 | import com.sum.shop.delegate.viewBinding
12 | import com.sum.shop.utils.extension.isNullorEmpty
13 | import com.sum.shop.utils.extension.isValidEmail
14 | import com.sum.shop.utils.extension.sent
15 | import com.sum.shop.utils.extension.showErrorSnackBar
16 | import dagger.hilt.android.AndroidEntryPoint
17 |
18 | @AndroidEntryPoint
19 | class SignInFragment : Fragment(R.layout.fragment_sign_in) {
20 | private val binding by viewBinding(FragmentSignInBinding::bind)
21 | private val viewModel: SignInViewModel by viewModels()
22 |
23 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
24 | super.onViewCreated(view, savedInstanceState)
25 |
26 | initObservers()
27 |
28 | with(binding) {
29 |
30 | tvForgotPassword.setOnClickListener {
31 | Navigation.sent(it, R.id.action_loginRegiser2_to_forgotPasswordFragment)
32 | }
33 |
34 | btnLogin.setOnClickListener {
35 |
36 | val emailResult =
37 | etEmail.isValidEmail(getString(R.string.invalid_mail)) //validation
38 | val passwordResult = etPassword.isNullorEmpty(getString(R.string.invalid_password))
39 |
40 | if (emailResult && passwordResult) {
41 | val email = etEmail.text.toString()
42 | val password = etPassword.text.toString()
43 |
44 | viewModel.signIn(email, password)
45 | }
46 | }
47 | }
48 | }
49 |
50 |
51 | private fun initObservers() {
52 | viewModel.isSingnIn.observe(viewLifecycleOwner) {
53 | if (it) {
54 | findNavController().navigate(R.id.action_loginRegiser_to_main_graph)
55 | } else {
56 | requireView().showErrorSnackBar(getString(R.string.fail), true)
57 | }
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/products/ProductsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.products
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.viewModels
7 | import androidx.navigation.Navigation
8 | import androidx.navigation.fragment.findNavController
9 | import androidx.navigation.fragment.navArgs
10 | import com.sum.shop.R
11 | import com.sum.shop.databinding.FragmentProductsBinding
12 | import com.sum.shop.delegate.viewBinding
13 | import com.sum.shop.model.ProductModel
14 | import com.sum.shop.utils.extension.back
15 | import com.sum.shop.utils.extension.gone
16 | import com.sum.shop.utils.extension.visible
17 | import dagger.hilt.android.AndroidEntryPoint
18 |
19 | @AndroidEntryPoint
20 | class ProductsFragment : Fragment(R.layout.fragment_products) {
21 |
22 | private val binding by viewBinding(FragmentProductsBinding::bind)
23 | private val productAdapter by lazy { ProductsAdapter(onClickDetail = ::onClickDetail) }
24 | private val viewModel: ProductsViewModel by viewModels()
25 | private val args: ProductsFragmentArgs by navArgs()
26 |
27 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
28 | super.onViewCreated(view, savedInstanceState)
29 |
30 | val categoryType = args.category
31 | viewModel.getProduct(categoryType.lowercase())
32 | initObservers()
33 |
34 | with(binding) {
35 |
36 | productToolbar.apply {
37 | tvProductTitle.text = categoryType
38 | ibArrowBack.setOnClickListener {
39 | Navigation.back(it)
40 | }
41 | }
42 | rvProduct.adapter = productAdapter
43 | }
44 | }
45 |
46 | private fun onClickDetail(productModel: ProductModel) {
47 | val action =
48 | ProductsFragmentDirections.actionProductsFragmentToProductDetailFragment(
49 | productModel
50 | )
51 | findNavController().navigate(action)
52 |
53 | }
54 |
55 | private fun initObservers() {
56 | with(binding) {
57 | viewModel.categoryList.observe(viewLifecycleOwner) { productList ->
58 | productAdapter.submitList(productList)
59 | }
60 |
61 | viewModel.isLoading.observe(viewLifecycleOwner) { isLoading ->
62 | if (isLoading) {
63 | rvProduct.gone()
64 | loadingLottie.visible()
65 | } else {
66 | rvProduct.visible()
67 | loadingLottie.gone()
68 | }
69 | }
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/payment/PaymentFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.payment
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.navigation.Navigation
7 | import androidx.navigation.fragment.navArgs
8 | import com.sum.shop.R
9 | import com.sum.shop.databinding.FragmentPaymentBinding
10 | import com.sum.shop.delegate.viewBinding
11 | import com.sum.shop.utils.extension.back
12 | import com.sum.shop.utils.extension.showErrorSnackBar
13 | import com.sum.shop.utils.extension.trimmedText
14 |
15 | class PaymentFragment : Fragment(R.layout.fragment_payment) {
16 |
17 | private val binding by viewBinding(FragmentPaymentBinding::bind)
18 | private val args: PaymentFragmentArgs by navArgs()
19 |
20 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
21 | super.onViewCreated(view, savedInstanceState)
22 |
23 | val totalAmount = args.objectTotalAmount
24 |
25 | with(binding) {
26 | //Back
27 | productToolbar.ibArrowBack.setOnClickListener {
28 | Navigation.back(it)
29 | }
30 | productToolbar.tvProductTitle.text = getString(R.string.payment)
31 |
32 | btnPay.setOnClickListener {
33 | if (validatePaymentDetails()) {
34 | val action =
35 | PaymentFragmentDirections.actionPaymentFragmentToSuccessFragment(totalAmount)
36 | Navigation.findNavController(it).navigate(action)
37 | }
38 | }
39 | }
40 | }
41 |
42 | private fun validatePaymentDetails(): Boolean {
43 | with(binding) {
44 | val cardName = etCardName.trimmedText()
45 | val cardNumber = etCardNumber.trimmedText()
46 | val expiryDate = etExpiryDate.trimmedText()
47 | val cvv = etCvv.trimmedText()
48 | val address = etAddress.trimmedText()
49 |
50 |
51 | return when {
52 | cardName.isEmpty() -> showError(getString(R.string.required_card_name))
53 | cardNumber.isEmpty() -> showError(getString(R.string.required_card_number))
54 | expiryDate.isEmpty() -> showError(getString(R.string.required_expiry))
55 | cvv.isEmpty() -> showError(getString(R.string.required_cvv))
56 | address.isEmpty() -> showError(getString(R.string.required_address))
57 | else -> true
58 | }
59 | }
60 | }
61 |
62 | private fun showError(errorMsg: String): Boolean {
63 | requireView().showErrorSnackBar(errorMsg, true)
64 | return false
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/products/ProductsAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.products
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.ListAdapter
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.bumptech.glide.Glide
8 | import com.sum.shop.R
9 | import com.sum.shop.databinding.ItemProductsBinding
10 | import com.sum.shop.model.ProductModel
11 | import com.sum.shop.utils.diffutil.DiffUtilCallback
12 | import com.sum.shop.utils.extension.visible
13 |
14 | class ProductsAdapter(private val onClickDetail: (ProductModel) -> Unit) :
15 | ListAdapter(
16 | DiffUtilCallback(
17 | itemsTheSame = { oldItem, newItem ->
18 | oldItem == newItem
19 | },
20 | contentsTheSame = { oldItem, newItem ->
21 | oldItem == newItem
22 | }
23 | )
24 | ) {
25 |
26 |
27 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductsViewHolder {
28 | val binding =
29 | ItemProductsBinding.inflate(LayoutInflater.from(parent.context), parent, false)
30 | return ProductsViewHolder(binding)
31 | }
32 |
33 | override fun onBindViewHolder(holder: ProductsViewHolder, position: Int) {
34 | holder.bind(currentList[position])
35 | }
36 |
37 | inner class ProductsViewHolder(private var binding: ItemProductsBinding) :
38 | RecyclerView.ViewHolder(binding.root) {
39 |
40 | fun bind(productModel: ProductModel) {
41 | with(binding) {
42 | tvProductName.text = productModel.productTitle
43 | tvProductPrice.text =
44 | itemView.context.getString(R.string.total_tl, productModel.productPrice)
45 |
46 | Glide.with(binding.ivProduct).load(productModel.img).into(binding.ivProduct)
47 | if (productModel.productCount.toInt() <= 3) {
48 | tvProductCount.visible()
49 | tvProductCount.text = itemView.context.getString(
50 | R.string.left_in_stock, productModel.productCount
51 | )// order soon
52 | }
53 |
54 | root.setOnClickListener {
55 | onClickDetail(productModel)
56 | }
57 |
58 | if (productModel.productFav) ivProductFav.setBackgroundResource(R.drawable.ic_full_fav)
59 | else ivProductFav.setBackgroundResource(R.drawable.ic_favorite_border)
60 |
61 | }
62 | }
63 | }
64 |
65 | override fun getItemCount() = currentList.size
66 |
67 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_success.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
34 |
35 |
48 |
49 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/basket/BasketFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.basket
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.fragment.app.viewModels
7 | import androidx.navigation.Navigation
8 | import com.sum.shop.R
9 | import com.sum.shop.databinding.FragmentBasketBinding
10 | import com.sum.shop.delegate.viewBinding
11 | import com.sum.shop.utils.extension.showErrorSnackBar
12 | import com.sum.shop.utils.extension.visible
13 | import dagger.hilt.android.AndroidEntryPoint
14 |
15 | @AndroidEntryPoint
16 | class BasketFragment : Fragment(R.layout.fragment_basket) {
17 | private val binding by viewBinding(FragmentBasketBinding::bind)
18 | private val viewModel: BasketViewModel by viewModels()
19 | private val adapter by lazy {
20 | BasketAdapter(
21 | onRemoveBasketClick = ::onRemoveBasketClick,
22 | viewModel::increase,
23 | viewModel::decrease
24 | )
25 | }
26 |
27 |
28 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
29 | super.onViewCreated(view, savedInstanceState)
30 |
31 | binding.rvBasket.adapter = adapter
32 | initializeObserver()
33 | }
34 |
35 | private fun onRemoveBasketClick(s: String) {
36 | viewModel.deleteFromBasket(s)
37 | viewModel.resetTotalAmount()
38 | }
39 |
40 | private fun initializeObserver() {
41 | with(binding) {
42 | viewModel.apply {
43 |
44 | readAllBasket.observe(viewLifecycleOwner) { basketList ->
45 |
46 | totalBasket()
47 | adapter.submitList(basketList)
48 |
49 | if (basketList.isEmpty()) {
50 | tvBasketEmpty.visible()
51 | }
52 |
53 | btnCheckout.setOnClickListener {
54 | if (basketList.isNotEmpty()) {
55 | val action =
56 | totalAmount.value?.let { double ->
57 | BasketFragmentDirections.actionBasketFragmentToPaymentFragment(
58 | double.toFloat()
59 | )
60 | }
61 | if (action != null) {
62 | Navigation.findNavController(it).navigate(action)
63 | }
64 | } else {
65 | requireView().showErrorSnackBar(getString(R.string.empty_bag), true)
66 | }
67 | }
68 | }
69 |
70 | totalAmount.observe(viewLifecycleOwner) {
71 | if (it == null) tvAmount.text = getString(R.string._0_TL)
72 | else tvAmount.text = getString(R.string.total_tl, it.toString())
73 | }
74 | }
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/basket/BasketAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.basket
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.ListAdapter
6 | import androidx.recyclerview.widget.RecyclerView
7 | import com.sum.shop.R
8 | import com.sum.shop.databinding.ItemBasketBinding
9 | import com.sum.shop.model.BasketModel
10 | import com.sum.shop.utils.diffutil.DiffUtilCallback
11 | import com.sum.shop.utils.extension.loadImage
12 | import com.sum.shop.utils.extension.showErrorSnackBar
13 |
14 | class BasketAdapter(
15 | private val onRemoveBasketClick: (String) -> Unit = {},
16 | private val onIncreaseClick: (BasketModel) -> Unit = {},
17 | private val onDecreaseClick: (BasketModel) -> Unit = {}
18 | ) : ListAdapter(
19 | DiffUtilCallback(
20 | itemsTheSame = { oldItem, newItem ->
21 | oldItem == newItem
22 | },
23 | contentsTheSame = { oldItem, newItem ->
24 | oldItem == newItem
25 | }
26 | )
27 | ) {
28 |
29 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = BasketHolder(
30 | ItemBasketBinding.inflate(LayoutInflater.from(parent.context), parent, false)
31 | )
32 |
33 | override fun onBindViewHolder(holder: BasketHolder, position: Int) =
34 | holder.bind(currentList[position])
35 |
36 | inner class BasketHolder(private var itemBasketBinding: ItemBasketBinding) :
37 | RecyclerView.ViewHolder(itemBasketBinding.root) {
38 |
39 | fun bind(basketModel: BasketModel) = with(itemBasketBinding) {
40 |
41 | tvBasketName.text = basketModel.productTitle
42 | val productPrice = "${basketModel.productPrice} TL"
43 | tvBasketPrice.text = productPrice
44 | ivBasket.loadImage(basketModel.img)
45 |
46 | tvAmount.text = basketModel.count.toString()
47 |
48 | btnDelete.setOnClickListener {
49 | onRemoveBasketClick(basketModel.uuid)
50 | }
51 |
52 | btnMinus.setOnClickListener {
53 | if (basketModel.count != 1) {
54 | onDecreaseClick(basketModel)
55 | basketModel.count--
56 | tvAmount.text = basketModel.count.toString()
57 | } else {
58 | onRemoveBasketClick(basketModel.uuid)
59 | }
60 | }
61 |
62 | btnPlus.setOnClickListener {
63 | if (basketModel.productCount.toInt() > basketModel.count) {
64 | onIncreaseClick(basketModel)
65 | basketModel.count++
66 | tvAmount.text = basketModel.count.toString()
67 | } else {
68 | it.showErrorSnackBar(it.context.getString(R.string.products_in_stock), true)
69 | }
70 | }
71 | }
72 | }
73 |
74 | override fun getItemCount() = currentList.size
75 |
76 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_basket.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
20 |
21 |
34 |
35 |
36 |
47 |
48 |
56 |
57 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'com.google.gms.google-services'
5 | id 'androidx.navigation.safeargs'
6 | id 'com.google.dagger.hilt.android'
7 | id 'kotlin-kapt'
8 | id 'kotlin-parcelize'
9 | }
10 |
11 | android {
12 | compileSdk 33
13 |
14 | defaultConfig {
15 | applicationId "com.sum.shop"
16 | minSdk 21
17 | targetSdk 33
18 | versionCode 1
19 | versionName "1.0"
20 |
21 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 | kotlinOptions {
35 | jvmTarget = '1.8'
36 | }
37 | buildFeatures {
38 | viewBinding true
39 | }
40 | }
41 |
42 | dependencies {
43 |
44 | implementation 'androidx.core:core-ktx:1.9.0'
45 | implementation 'androidx.appcompat:appcompat:1.6.1'
46 | implementation 'com.google.android.material:material:1.8.0'
47 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
48 | implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
49 | implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
50 | implementation 'com.google.firebase:firebase-auth-ktx:21.1.0'
51 | implementation 'com.google.firebase:firebase-firestore-ktx'
52 | implementation 'com.google.firebase:firebase-storage-ktx:20.1.0'
53 | testImplementation 'junit:junit:4.13.2'
54 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
55 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
56 |
57 |
58 | // Import the BoM for the Firebase platform
59 | implementation platform('com.google.firebase:firebase-bom:30.5.0')
60 | //Firebase Perform
61 | implementation 'com.google.firebase:firebase-analytics-ktx'
62 | implementation 'com.google.firebase:firebase-perf-ktx'
63 |
64 |
65 | //glide
66 | implementation 'com.github.bumptech.glide:glide:4.15.1'
67 | annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'
68 |
69 | //Lottie
70 | implementation "com.airbnb.android:lottie:6.0.0"
71 |
72 | // Coroutines
73 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.2'
74 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
75 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4'
76 |
77 | // SSP-SDP library
78 | implementation 'com.intuit.ssp:ssp-android:1.1.0'
79 | implementation 'com.intuit.sdp:sdp-android:1.1.0'
80 |
81 | //carousel
82 | implementation 'com.mig35:carousellayoutmanager:1.4.6'
83 | implementation 'com.github.sparrow007:carouselrecyclerview:1.2.6'
84 | implementation 'com.github.bumptech.glide:glide:4.15.1'
85 |
86 | // Room
87 | implementation "androidx.room:room-runtime:2.5.0"
88 | implementation "androidx.room:room-ktx:2.5.0"
89 | kapt "androidx.room:room-compiler:2.5.0"
90 |
91 | // Hilt
92 | implementation 'com.google.dagger:hilt-android:2.45'
93 | kapt 'com.google.dagger:hilt-compiler:2.45'
94 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
26 |
27 |
34 |
35 |
42 |
43 |
49 |
50 |
56 |
57 |
67 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_password_forgot.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
23 |
24 |
38 |
39 |
52 |
53 |
61 |
62 |
63 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 250dp
6 | 200dp
7 | 110dp
8 | 56dp
9 | 130dp
10 | 28sp
11 | 16dp
12 | 34dp
13 | 16dp
14 | 16sp
15 | 30dp
16 | 16sp
17 |
18 | 20dp
19 | 30dp
20 | 36dp
21 | 20dp
22 | 25dp
23 | 10dp
24 | 14sp
25 | 16dp
26 | 30dp
27 | 8dp
28 | 18sp
29 | 5dp
30 | 160dp
31 | 18sp
32 | 50dp
33 | 8dp
34 | 14sp
35 |
36 | 10dp
37 | 5dp
38 | 50dp
39 | 10dp
40 | 16dp
41 | 16sp
42 | 4dp
43 | 8dp
44 | 30dp
45 | 22sp
46 | 4dp
47 | 18sp
48 | 1dp
49 | 2dp
50 | 14sp
51 | 207dp
52 | 196dp
53 | 216dp
54 | 193dp
55 | 50dp
56 | 12dp
57 | 262dp
58 | 226dp
59 | 44dp
60 | 254dp
61 | 224dp
62 | 8dp
63 | 64dp
64 | 20dp
65 | 52dp
66 | 40dp
67 | 5dp
68 | 1dp
69 | 5dp
70 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/loginregister/signup/SignUpFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.loginregister.signup
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.core.net.toUri
6 | import androidx.fragment.app.Fragment
7 | import androidx.lifecycle.ViewModelProvider
8 | import androidx.navigation.Navigation
9 | import com.sum.shop.R
10 | import com.sum.shop.databinding.FragmentSignUpBinding
11 | import com.sum.shop.delegate.viewBinding
12 | import com.sum.shop.utils.constant.Constant
13 | import com.sum.shop.utils.extension.sent
14 | import com.sum.shop.utils.extension.showErrorSnackBar
15 | import com.sum.shop.utils.extension.trimmedText
16 |
17 | class SignUpFragment : Fragment(R.layout.fragment_sign_up) {
18 | private val binding by viewBinding(FragmentSignUpBinding::bind)
19 | private lateinit var viewModel: SignUpTermConditionViewModel
20 |
21 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
22 | super.onViewCreated(view, savedInstanceState)
23 |
24 | viewModel =
25 | ViewModelProvider(requireActivity())[SignUpTermConditionViewModel::class.java] //live data for update
26 | initObservers()
27 |
28 | binding.tvTermsCondition.setOnClickListener {
29 | Navigation.sent(it, R.id.action_loginRegiser_to_termConditionBottomSheet)
30 | }
31 |
32 |
33 | with(binding) {
34 | btnRegister.setOnClickListener {
35 | val firstName = etFirstName.trimmedText()
36 | val lastName = etLastName.trimmedText()
37 | val email = etEmail.trimmedText()
38 | val password = etPassword.trimmedText()
39 | val isCheck = cbTermsAndCondition.isChecked
40 | val picture = Constant.PROFILE_PICTURE_LINK.toUri()
41 |
42 | if (validateSignUpDetails()) {
43 | viewModel.signUp(firstName, lastName, email, password, picture, isCheck)
44 | }
45 | }
46 | }
47 | }
48 |
49 |
50 | private fun validateSignUpDetails(): Boolean {
51 | with(binding) {
52 | val firstName = etFirstName.trimmedText()
53 | val lastName = etLastName.trimmedText()
54 | val email = etEmail.trimmedText()
55 | val password = etPassword.trimmedText()
56 | val confirmPassword = etConfirmPassword.trimmedText()
57 | val isCheck = cbTermsAndCondition.isChecked
58 |
59 | return when {
60 | firstName.isEmpty() -> showError(getString(R.string.required_name))
61 | lastName.isEmpty() -> showError(getString(R.string.required_lastname))
62 | email.isEmpty() -> showError(getString(R.string.required_email))
63 | password.isEmpty() -> showError(getString(R.string.required_password))
64 | confirmPassword.isEmpty() -> showError(getString(R.string.required_password))
65 | password != confirmPassword -> showError(getString(R.string.password_match))
66 | !isCheck -> showError(getString(R.string.accept_condition))
67 | else -> true
68 | }
69 | }
70 | }
71 |
72 | private fun showError(errorMsg: String): Boolean {
73 | requireView().showErrorSnackBar(errorMsg, true)
74 | return false
75 | }
76 |
77 | private fun initObservers() {
78 | viewModel.isSuccess.observe(viewLifecycleOwner) {
79 | if (it) requireView().showErrorSnackBar(getString(R.string.success), false)
80 | else requireView().showErrorSnackBar(getString(R.string.fail), true)
81 | }
82 |
83 | viewModel.resultOk.observe(viewLifecycleOwner) {
84 | binding.cbTermsAndCondition.isChecked = it
85 | }
86 | }
87 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_fav.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
14 |
26 |
27 |
37 |
38 |
47 |
48 |
49 |
59 |
60 |
71 |
72 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_products.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
25 |
26 |
36 |
37 |
46 |
47 |
48 |
58 |
59 |
70 |
71 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/productdetail/ProductDetailFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.productdetail
2 |
3 |
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import android.view.View
7 | import androidx.fragment.app.Fragment
8 | import androidx.fragment.app.viewModels
9 | import androidx.navigation.Navigation
10 | import androidx.navigation.fragment.navArgs
11 | import com.bumptech.glide.Glide
12 | import com.sum.shop.R
13 | import com.sum.shop.databinding.FragmentProductDetailBinding
14 | import com.sum.shop.delegate.viewBinding
15 | import com.sum.shop.model.BasketModel
16 | import com.sum.shop.model.FavModel
17 | import com.sum.shop.utils.extension.back
18 | import com.sum.shop.utils.extension.showErrorSnackBar
19 | import dagger.hilt.android.AndroidEntryPoint
20 |
21 | @AndroidEntryPoint
22 | class ProductDetailFragment() : Fragment(R.layout.fragment_product_detail) {
23 | private val binding by viewBinding(FragmentProductDetailBinding::bind)
24 | private val viewModel: ProductDetailViewModel by viewModels()
25 | private val args: ProductDetailFragmentArgs by navArgs()
26 |
27 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
28 | super.onViewCreated(view, savedInstanceState)
29 |
30 | val product = args.objectProduct
31 | val favModel = FavModel(
32 | uuid = product.id,
33 | img = product.img,
34 | productTitle = product.productTitle,
35 | productPrice = product.productPrice
36 | )
37 |
38 | shareLink()
39 |
40 | with(binding) {
41 | tvDetailName.text = product.productTitle
42 | tvDetailInfo.text = product.productDescription
43 | tvDetailPrice.text = getString(R.string.total_tl, product.productPrice)
44 |
45 |
46 | Glide.with(this@ProductDetailFragment).load(product.img)
47 | .into(binding.ivProductImage)
48 |
49 | //Back
50 | ibArrowBack.setOnClickListener {
51 | Navigation.back(it)
52 | }
53 |
54 | //Add fav products to room database
55 | btnDetailAddFav.setOnClickListener {
56 | if (product.productFav) {
57 | btnDetailAddFav.setBackgroundResource(R.drawable.ic_favorite)
58 | product.productFav = false
59 | viewModel.deleteFromFav(favModel)
60 | } else {
61 | btnDetailAddFav.setBackgroundResource(R.drawable.ic_full_fav)
62 | product.productFav = true
63 | viewModel.addToFav(favModel)
64 | }
65 | }
66 |
67 |
68 | if (product.productFav) {
69 | btnDetailAddFav.setBackgroundResource(R.drawable.ic_full_fav)
70 | } else {
71 | btnDetailAddFav.setBackgroundResource(R.drawable.ic_favorite)
72 | }
73 |
74 | btnAddToBasket.setOnClickListener {
75 | viewModel.addToBasket(
76 | product?.let { product ->
77 | BasketModel(
78 | id,
79 | product.id!!,
80 | product.img!!,
81 | product.productTitle!!,
82 | product.productPrice!!.toInt(),
83 | product.productCount!!
84 | )
85 |
86 | }
87 | )
88 | requireView().showErrorSnackBar(getString(R.string.product_add), false)
89 | }
90 | }
91 | }
92 |
93 | private fun shareLink() {
94 | binding.btnDetailShare.setOnClickListener {
95 | Intent(Intent.ACTION_SEND).apply {
96 | type = "text/plain"
97 | putExtra(Intent.EXTRA_TEXT, binding.webView.url)
98 | startActivity(Intent.createChooser(this, getString(R.string.share_link)))
99 | }
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Firebase-Shop-App🌈
2 |
3 | **Explanation:** It is a shop app where you can add and sell products.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | | Sign In |
12 | Sign Up |
13 | Forgot Password |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | |
22 |
23 |
24 | |
25 |
26 |
27 | |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | | Home Page |
39 | Add Product |
40 | Category Page |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | |
50 |
51 |
52 | |
53 |
54 |
55 | |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | | Detail Page |
67 | Favourite Page |
68 | Basket Page |
69 |
70 |
71 |
72 |
73 |
74 |
75 | |
76 |
77 |
78 | |
79 |
80 |
81 | |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | | Payment Page |
94 | Success Page |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | |
103 |
104 |
105 | |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | | Profile Page |
119 | Update Page |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | |
128 |
129 |
131 | |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | ## Video 💥
141 |
142 |
143 | https://user-images.githubusercontent.com/41166029/225932038-cc4cf7f9-c127-4030-95ef-88598dc9ff0b.mp4
144 |
145 |
146 |
147 |
148 |
149 |
150 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_home.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
17 |
18 |
30 |
31 |
44 |
45 |
56 |
57 |
58 |
70 |
71 |
82 |
83 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_profile.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
30 |
31 |
32 |
47 |
48 |
61 |
62 |
75 |
76 |
84 |
85 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/utils/extension/Extension.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.utils.extension
2 |
3 | import android.Manifest
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.pm.PackageManager
7 | import android.provider.MediaStore
8 | import android.util.Patterns
9 | import android.view.View
10 | import android.widget.ImageView
11 | import android.widget.Toast
12 | import androidx.activity.result.ActivityResultLauncher
13 | import androidx.core.app.ActivityCompat
14 | import androidx.core.content.ContextCompat
15 | import androidx.fragment.app.Fragment
16 | import androidx.navigation.Navigation
17 | import com.bumptech.glide.Glide
18 | import com.google.android.material.snackbar.Snackbar
19 | import com.google.android.material.textfield.TextInputLayout
20 | import com.sum.shop.R
21 | import com.sum.shop.utils.customs.EditText
22 |
23 | fun Navigation.sent(v: View, id: Int) = findNavController(v).navigate(id)
24 |
25 | fun Context.showToast(message: CharSequence) =
26 | Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
27 |
28 | fun View.visible() {
29 | visibility = View.VISIBLE
30 | }
31 |
32 | fun View.gone() {
33 | visibility = View.GONE
34 | }
35 |
36 | fun setViewsGone(vararg views: View) {
37 | views.forEach {
38 | it.gone()
39 | }
40 | }
41 |
42 | fun setViewsVisible(vararg views: View) {
43 | views.forEach {
44 | it.visible()
45 | }
46 |
47 | }
48 |
49 | fun checkEditTexts(vararg editTexts: EditText): Boolean {
50 | return editTexts.all {
51 | it.isNullorEmpty("required field")
52 | }
53 | }
54 |
55 | //fun View.visibleIf(bool: Boolean) {
56 | // if (bool) visible() else gone()
57 | //}
58 |
59 | fun Navigation.back(v: View) = findNavController(v).navigateUp()
60 |
61 | fun View.showErrorSnackBar(message: String, errorMessage: Boolean) {
62 | val snackBar = Snackbar.make(this, message, Snackbar.LENGTH_LONG)
63 | val snackBarView = snackBar.view
64 |
65 | if (errorMessage) {
66 | snackBarView.setBackgroundColor(
67 | ContextCompat.getColor(
68 | context,
69 | R.color.color_snack_bar_error
70 | )
71 | )
72 | } else {
73 | snackBarView.setBackgroundColor(
74 | ContextCompat.getColor(
75 | context,
76 | R.color.color_snack_bar_success
77 | )
78 | )
79 | }
80 | snackBar.show()
81 | }
82 |
83 | fun EditText.isValidEmail(errorString: String): Boolean {
84 | val textInputLayout = this.parent.parent as TextInputLayout
85 | return if (Patterns.EMAIL_ADDRESS.matcher(text.toString()).matches()) {
86 | textInputLayout.isErrorEnabled = false
87 | true
88 | } else {
89 | textInputLayout.error = errorString
90 | false
91 | }
92 | }
93 |
94 | fun EditText.trimmedText(): String {
95 | return this.text.toString().trim()
96 | }
97 |
98 | fun EditText.isNullorEmpty(errorString: String): Boolean {
99 | val textInputLayout = this.parent.parent as TextInputLayout
100 | return if (text.toString().trim().isNotEmpty()) {
101 | textInputLayout.isErrorEnabled = false
102 | true
103 | } else {
104 | textInputLayout.error = errorString
105 | false
106 | }
107 | }
108 |
109 | fun Fragment.pickImageFromGalleryWithPermission(
110 | activityResultLauncher: ActivityResultLauncher,
111 | permissionLauncher: ActivityResultLauncher
112 | ) {
113 | when {
114 | ContextCompat.checkSelfPermission(
115 | requireContext(),
116 | Manifest.permission.READ_EXTERNAL_STORAGE
117 | ) != PackageManager.PERMISSION_GRANTED -> {
118 | if (ActivityCompat.shouldShowRequestPermissionRationale(
119 | requireActivity(),
120 | Manifest.permission.READ_EXTERNAL_STORAGE
121 | )
122 | ) {
123 | Snackbar.make(
124 | requireView(),
125 | getString(R.string.permission_needed_gallery),
126 | Snackbar.LENGTH_INDEFINITE
127 | )
128 | .setAction(getString(R.string.give_permission)) {
129 | permissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
130 | }.show()
131 | } else {
132 | permissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
133 | }
134 | }
135 | else -> {
136 | activityResultLauncher.launch(
137 | Intent(
138 | Intent.ACTION_PICK,
139 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI
140 | )
141 | )
142 | }
143 | }
144 | }
145 |
146 | fun ImageView.loadImage(url: Any) { //url can be string or int
147 | Glide.with(this)
148 | .load(url)
149 | .into(this)
150 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/term_condition_sheet.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
20 |
21 |
22 |
30 |
31 |
35 |
36 |
45 |
46 |
57 |
58 |
59 |
69 |
70 |
79 |
80 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/auth_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
13 |
16 |
19 |
20 |
21 |
26 |
29 |
32 |
35 |
36 |
37 |
42 |
45 |
46 |
47 |
48 |
49 |
60 |
65 |
68 |
75 |
78 |
81 |
84 |
87 |
88 |
93 |
98 |
103 |
104 |
105 |
110 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_sign_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
23 |
36 |
37 |
50 |
51 |
60 |
61 |
62 |
75 |
76 |
85 |
86 |
87 |
88 |
97 |
98 |
112 |
113 |
--------------------------------------------------------------------------------
/app/src/main/java/com/sum/shop/ui/addproduct/AddProductFragment.kt:
--------------------------------------------------------------------------------
1 | package com.sum.shop.ui.addproduct
2 |
3 | import android.app.Activity
4 | import android.content.Intent
5 | import android.net.Uri
6 | import android.os.Bundle
7 | import android.provider.MediaStore
8 | import android.view.View
9 | import androidx.activity.result.ActivityResultLauncher
10 | import androidx.activity.result.contract.ActivityResultContracts
11 | import androidx.fragment.app.Fragment
12 | import androidx.fragment.app.viewModels
13 | import androidx.navigation.Navigation
14 | import com.sum.shop.R
15 | import com.sum.shop.databinding.FragmentAddProductBinding
16 | import com.sum.shop.delegate.viewBinding
17 | import com.sum.shop.utils.extension.*
18 | import dagger.hilt.android.AndroidEntryPoint
19 |
20 | @AndroidEntryPoint
21 | class AddProductFragment : Fragment(R.layout.fragment_add_product) {
22 |
23 | private val binding by viewBinding(FragmentAddProductBinding::bind)
24 | private val viewModel: AddProductViewModel by viewModels()
25 |
26 | private lateinit var activityResultLauncher: ActivityResultLauncher
27 | private lateinit var permissionLauncher: ActivityResultLauncher
28 |
29 | private var selectedPicture: Uri? = null
30 |
31 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
32 | super.onViewCreated(view, savedInstanceState)
33 |
34 | initObservers()
35 | registerLauncher()
36 |
37 | with(binding) {
38 | ivAddUpdateProduct.setOnClickListener {
39 | pickImageFromGallery()
40 | }
41 | //Back
42 | ibArrowBack.setOnClickListener {
43 | Navigation.back(it)
44 | }
45 |
46 | btnAdd.setOnClickListener {
47 |
48 | val productType = when (binding.rgType.checkedRadioButtonId) {
49 | R.id.rb_woman -> getString(R.string.woman)
50 | R.id.rb_man -> getString(R.string.man)
51 | else -> getString(R.string.child)
52 | }
53 |
54 | val productTitle = etProductTitle.trimmedText()
55 | val productPrice = etProductPrice.trimmedText()
56 | val productDescription = etProductDescription.trimmedText()
57 | val productQuantity = etProductQuantity.trimmedText()
58 |
59 | if (validAddProduct() && selectedPicture != null) {
60 | viewModel.addProduct(
61 | selectedPicture!!,
62 | productTitle,
63 | productPrice,
64 | productDescription,
65 | productQuantity,
66 | productType
67 | )
68 | }
69 | }
70 | }
71 | }
72 |
73 | //Permision
74 | private fun pickImageFromGallery() {
75 | this.pickImageFromGalleryWithPermission(activityResultLauncher, permissionLauncher)
76 | }
77 |
78 | private fun registerLauncher() {
79 | activityResultLauncher =
80 | registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
81 | if (result.resultCode == Activity.RESULT_OK) {
82 | selectedPicture = result.data?.data
83 | selectedPicture?.let { binding.ivProductImage.setImageURI(it) }
84 | } else {
85 | requireContext().showToast(getString(R.string.image_not_selected))
86 | }
87 | }
88 |
89 | permissionLauncher =
90 | registerForActivityResult(ActivityResultContracts.RequestPermission()) { result ->
91 | if (result) {
92 | activityResultLauncher.launch(
93 | Intent(
94 | Intent.ACTION_PICK,
95 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI
96 | )
97 | )
98 | } else {
99 | requireContext().showToast(getString(R.string.permission_needed))
100 | }
101 | }
102 | }
103 |
104 |
105 | private fun validAddProduct(): Boolean {
106 | with(binding) {
107 | return checkEditTexts(
108 | etProductTitle,
109 | etProductPrice,
110 | etProductDescription,
111 | etProductQuantity
112 | )
113 | }
114 | }
115 |
116 |
117 | private fun initObservers() {
118 | viewModel.isSuccess.observe(viewLifecycleOwner) {
119 | if (it.equals(true)) requireView().showErrorSnackBar(
120 | getString(R.string.success),
121 | false
122 | )
123 | else requireView().showErrorSnackBar(getString(R.string.fail), true)
124 |
125 | }
126 |
127 | viewModel.isLoading.observe(viewLifecycleOwner) {
128 | with(binding) {
129 | if (it) {
130 | setViewsGone(
131 | tilProductDescription, tilProductPrice, tilProductTitle, tilProductQuantity,
132 | ivProductImage, ivAddUpdateProduct, rgType, btnAdd
133 | )
134 | loadingLottie.visible()
135 | } else {
136 | setViewsVisible(
137 | tilProductDescription, tilProductPrice, tilProductTitle, tilProductQuantity,
138 | ivProductImage, ivAddUpdateProduct, rgType, btnAdd
139 | )
140 | loadingLottie.gone()
141 | }
142 | }
143 |
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/app/src/main/res/navigation/main_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
20 |
27 |
28 |
33 |
38 |
45 |
46 |
51 |
54 |
55 |
60 |
67 |
68 |
73 |
78 |
81 |
82 |
86 |
89 |
96 |
97 |
102 |
109 |
112 |
113 |
118 |
121 |
124 |
125 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_basket.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
16 |
22 |
23 |
33 |
34 |
45 |
46 |
54 |
55 |
65 |
66 |
77 |
78 |
92 |
93 |
102 |
103 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_product_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
16 |
17 |
22 |
23 |
33 |
34 |
35 |
42 |
43 |
44 |
54 |
55 |
56 |
66 |
67 |
80 |
81 |
96 |
97 |
110 |
111 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------