├── 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 | 3 | 4 | 8 | 9 | 13 | 14 | 18 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /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 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 25 | 28 | 29 | 30 |
Sign InSign UpForgot Password
20 | signIn 21 | 23 | SignUp 24 | 26 | ForgotPassword 27 |
31 | 32 |
33 | 34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 50 | 53 | 56 | 57 | 58 |
Home Page Add ProductCategory Page
48 | Ekran Resmi 2023-03-17 15 28 27 49 | 51 | add_product 52 | 54 | Ekran Resmi 2023-03-17 16 42 42 55 |
59 | 60 |
61 | 62 | 63 |
64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 76 | 79 | 82 | 83 | 84 |
Detail PageFavourite PageBasket Page
74 | Ekran Resmi 2023-03-17 16 43 05 75 | 77 | Ekran Resmi 2023-03-17 15 29 21 78 | 80 | Ekran Resmi 2023-03-17 15 30 13 81 |
85 | 86 |
87 | 88 | 89 | 90 |
91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 103 | 106 | 107 | 108 | 109 |
Payment PageSuccess Page
101 | Ekran Resmi 2023-03-17 15 31 57 102 | 104 | Ekran Resmi 2023-03-17 15 32 36 105 |
110 | 111 |
112 | 113 | 114 | 115 |
116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 128 | 132 | 133 | 134 | 135 |
Profile PageUpdate Page
126 | Ekran Resmi 2023-03-17 15 34 00 127 | 129 | Ekran Resmi 2023-03-17 15 33 30 131 |
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 | 53 | 56 | 59 | 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 | --------------------------------------------------------------------------------