├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── gradle.xml
├── kotlinc.xml
├── misc.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── google-services.json
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── adilegungor
│ │ └── gungorecommerce
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── cartt-playstore.png
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── com
│ │ │ └── adilegungor
│ │ │ ├── MainApplication.kt
│ │ │ └── gungorecommerce
│ │ │ ├── MainActivity.kt
│ │ │ ├── common
│ │ │ ├── Constants.kt
│ │ │ ├── Extensions.kt
│ │ │ ├── Resource.kt
│ │ │ └── ViewBindingExtensions.kt
│ │ │ ├── data
│ │ │ ├── model
│ │ │ │ ├── AddToCartRequest.kt
│ │ │ │ ├── CRUDResponse.kt
│ │ │ │ ├── ClearCartRequest.kt
│ │ │ │ ├── DeleteFromCartRequest.kt
│ │ │ │ ├── GetProductDetailResponse.kt
│ │ │ │ ├── GetProductsResponse.kt
│ │ │ │ ├── Product.kt
│ │ │ │ ├── ProductEntity.kt
│ │ │ │ └── ProductUI.kt
│ │ │ ├── repository
│ │ │ │ └── ProductRepository.kt
│ │ │ └── source
│ │ │ │ ├── local
│ │ │ │ ├── ProductDao.kt
│ │ │ │ └── ProductRoomDB.kt
│ │ │ │ └── remote
│ │ │ │ └── ProductService.kt
│ │ │ ├── di
│ │ │ ├── NetworkModule.kt
│ │ │ ├── RepositoryModule.kt
│ │ │ └── RoomDBModule.kt
│ │ │ └── ui
│ │ │ ├── anasayfa
│ │ │ ├── HomeFragment.kt
│ │ │ ├── HomeViewModel.kt
│ │ │ ├── ProductAdapter.kt
│ │ │ └── SalesProductAdapter.kt
│ │ │ ├── arama
│ │ │ ├── SearchAdapter.kt
│ │ │ ├── SearchFragment.kt
│ │ │ └── SearchViewModel.kt
│ │ │ ├── detay
│ │ │ ├── ProductDetailFragment.kt
│ │ │ └── ProductDetailViewModel.kt
│ │ │ ├── favori
│ │ │ ├── FavoriteAdapter.kt
│ │ │ ├── FavoriteFragment.kt
│ │ │ └── FavoriteViewModel.kt
│ │ │ ├── giris
│ │ │ └── SignInFragment.kt
│ │ │ ├── kayit
│ │ │ └── SignUpFragment.kt
│ │ │ ├── odeme
│ │ │ ├── PaymentFragment.kt
│ │ │ └── ResultFragment.kt
│ │ │ ├── profil
│ │ │ ├── ProfileFragment.kt
│ │ │ └── ProfileViewModel.kt
│ │ │ ├── sepet
│ │ │ ├── CartFragment.kt
│ │ │ ├── CartProductsAdapter.kt
│ │ │ └── CartViewModel.kt
│ │ │ ├── splash
│ │ │ └── SplashFragment.kt
│ │ │ └── viewmodel
│ │ │ └── BaseViewModel.kt
│ └── res
│ │ ├── drawable
│ │ ├── avatarboy.png
│ │ ├── avatargirl.png
│ │ ├── back.jpg
│ │ ├── backg.jpg
│ │ ├── baseline_add_24.xml
│ │ ├── baseline_add_circle_24.xml
│ │ ├── baseline_arrow_circle_left_24.xml
│ │ ├── baseline_delete_24.xml
│ │ ├── baseline_favorite_24.xml
│ │ ├── baseline_home_24.xml
│ │ ├── baseline_indeterminate_check_box_24.xml
│ │ ├── baseline_keyboard_double_arrow_left_24.xml
│ │ ├── baseline_person_24.xml
│ │ ├── baseline_shopping_cart_24.xml
│ │ ├── baseline_youtube_searched_for_24.xml
│ │ ├── bg_rectangle.xml
│ │ ├── cargo.gif
│ │ ├── cartt_background.xml
│ │ ├── cartt_foreground.xml
│ │ ├── file.png
│ │ ├── ic_calendar.xml
│ │ ├── ic_card.xml
│ │ ├── ic_cart.xml
│ │ ├── ic_delete.xml
│ │ ├── ic_error.xml
│ │ ├── ic_favorite.xml
│ │ ├── ic_favorite_white.xml
│ │ ├── ic_home.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_lock.xml
│ │ ├── ic_payment.xml
│ │ ├── ic_profile.xml
│ │ └── splas.jpg
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── fragment_cart.xml
│ │ ├── fragment_favorite.xml
│ │ ├── fragment_home.xml
│ │ ├── fragment_payment.xml
│ │ ├── fragment_product_detail.xml
│ │ ├── fragment_profile.xml
│ │ ├── fragment_result.xml
│ │ ├── fragment_search.xml
│ │ ├── fragment_sign_in.xml
│ │ ├── fragment_sign_up.xml
│ │ ├── fragment_splash.xml
│ │ ├── item_cart_product.xml
│ │ ├── item_favorite.xml
│ │ ├── item_product.xml
│ │ ├── item_sales_product.xml
│ │ └── item_search.xml
│ │ ├── menu
│ │ ├── bottom_menu.xml
│ │ └── menu_toolbar.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── cartt.xml
│ │ ├── cartt_round.xml
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── app_icon.png
│ │ ├── app_icond.png
│ │ ├── app_icons.png
│ │ ├── cartt.png
│ │ ├── cartt_foreground.png
│ │ ├── cartt_round.png
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── iconagapp.png
│ │ ├── mipmap-mdpi
│ │ ├── app_icon.png
│ │ ├── app_icond.png
│ │ ├── app_icons.png
│ │ ├── cartt.png
│ │ ├── cartt_foreground.png
│ │ ├── cartt_round.png
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── iconagapp.png
│ │ ├── mipmap-xhdpi
│ │ ├── app_icon.png
│ │ ├── app_icond.png
│ │ ├── app_icons.png
│ │ ├── cartt.png
│ │ ├── cartt_foreground.png
│ │ ├── cartt_round.png
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── iconagapp.png
│ │ ├── mipmap-xxhdpi
│ │ ├── app_icon.png
│ │ ├── app_icond.png
│ │ ├── app_icons.png
│ │ ├── cartt.png
│ │ ├── cartt_foreground.png
│ │ ├── cartt_round.png
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── iconagapp.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── app_icon.png
│ │ ├── app_icond.png
│ │ ├── app_icons.png
│ │ ├── cartt.png
│ │ ├── cartt_foreground.png
│ │ ├── cartt_round.png
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── iconagapp.png
│ │ ├── navigation
│ │ └── nav_graph.xml
│ │ ├── values-night
│ │ └── themes.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ └── data_extraction_rules.xml
│ └── test
│ └── java
│ └── com
│ └── adilegungor
│ └── gungorecommerce
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GungorEcommerce
2 | Final assignment | Android Programming with Kotlin Academy - Sisterslab
3 |
4 | ## Açıklama:
5 | Yeni mimariler, eksik kullanımlar veya herhangi bir öneriniz için bana profilimdeki adreslerden ulaşmanız mümkün. Mutlu kodlamalar!
6 |
7 | ## Özellikler
8 |
9 | Uygulama aşağıdaki temel özelliklere sahiptir:
10 |
11 | - **MVVM (Model-View-ViewModel)**: Uygulama, Model-View-ViewModel tasarım deseni kullanılarak geliştirilmiştir. Bu, uygulamanın daha iyi modüler ve bakımı kolay bir şekilde oluşturulmasına yardımcı olur.
12 |
13 | - **Hilt**: Hilt, bağımlılık enjeksiyonu için kullanılan bir kütüphanedir. Bu sayede uygulamada bağımlılıkların yönetimi kolaylaşır.
14 |
15 | - **Coroutines**: Kotlin Coroutines, uygulamanın asenkron işlemlerini kolayca yönetmesine yardımcı olan bir özelliktir. Bu, arka planda ağ istekleri ve uzun süreli işlemler için idealdir.
16 |
17 | - **Navigation Component**: Navigation Component, uygulamanın gezinme (navigation) mantığını basitleştirmek için kullanılır. Bu sayede farklı ekranlar arasında geçiş yapmak daha kolay hale gelir.
18 |
19 | - **Retrofit**: Retrofit, RESTful API'lar ile iletişim kurmak için kullanılan bir HTTP istemcisidir. Uygulama, bu kütüphane aracılığıyla API verilerini alır.
20 |
21 | - **Room & Shared Preferences**: Room, yerel veritabanı işlemleri için kullanılırken, Shared Preferences küçük verilerin depolanmasında kullanılır. Bu sayede verilerin depolanması ve erişimi daha kolaydır.
22 |
23 | - **FirebaseAuth**: Firebase Authentication, kullanıcıların kayıt olması ve giriş yapması için kullanılır. Bu sayede kullanıcı yönetimi sağlanır.
24 |
25 | - **Glide**: Glide, görüntülerin yüklenmesi ve görüntülenmesi için kullanılan bir kütüphanedir. Bu, ürün resimlerinin ve kullanıcı profil resimlerinin gösterilmesinde kullanılır.
26 |
27 | - **Chucker**: Chucker, ağ isteklerini ve yanıtlarını izlemek ve hata ayıklamak için kullanılır. Bu sayede ağ isteklerinin izlenmesi ve hata ayıklanması daha kolay hale gelir.
28 |
29 | ## Kullanım
30 |
31 | Uygulamanın kullanımı oldukça basittir:
32 |
33 | 1. Uygulamayı cihazınıza yükleyin.
34 | 2. Kayıt olun veya giriş yapın.
35 | 3. Ürünleri kategorilere göre göz atın ve arama yapın.
36 | 4. Ürünleri sepetinize ekleyin ve favori ürünlerinizi listenize ekleyin.
37 | 5. Ödeme sayfasına giderek alışverişi tamamlayın.
38 | 6. Sonuçlar sayfasında sipariş detaylarını görüntüleyin.
39 | 7. Profil sayfasında kullanıcı bilgilerinizi düzenleyin.
40 |
41 | ## Kurulum
42 |
43 | Uygulamanın yerel olarak çalıştırılması için aşağıdaki adımları takip edebilirsiniz:
44 |
45 | 1. Depoyu klonlayın.
46 | 2. Android Studio veya başka bir uygun IDE kullanarak projeyi açın.
47 | 3. API anahtarları, Firebase yapılandırmaları ve diğer gerekli ayarları yapılandırın.
48 | 4. Uygulamayı bir Android cihazı veya emülatörü üzerinde çalıştırın.
49 |
50 | Uygulamayı geliştirmek veya özelleştirmek için dökümantasyon ve kaynak kodu inceleyebilirsiniz.
51 |
52 | ## Modül
53 | Proje akışı ve modüllerden kısaca bahsettiğim şu mini yazıya bakın lütfen.
54 | https://adilegungor.medium.com/e-ticaret-uygulamas%C4%B1-ba078fec348d
55 |
56 | ## uygulama demo:
57 |
58 | https://github.com/Adl1coder/GungorEcommerce/assets/93915867/58ef3023-afd1-4123-acdf-19a95992ae78
59 |
60 | ## Sunum:
61 | https://www.canva.com/design/DAFv5_8tzZs/olTATfYxKP9uBoToJ1YFRg/edit?utm_content=DAFv5_8tzZs&utm_campaign=designshare&utm_medium=link2&utm_source=sharebutton
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'androidx.navigation.safeargs'
5 | id("com.google.gms.google-services")
6 | id("kotlin-parcelize")
7 | id 'kotlin-kapt'
8 | id 'dagger.hilt.android.plugin'
9 | }
10 |
11 | android {
12 | namespace 'com.adilegungor.gungorecommerce'
13 | compileSdk 34
14 |
15 | defaultConfig {
16 | applicationId "com.adilegungor.gungorecommerce"
17 | minSdk 24
18 | targetSdk 34
19 | versionCode 1
20 | versionName "1.0"
21 |
22 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
23 | }
24 | buildFeatures {
25 | viewBinding true
26 | }
27 | buildTypes {
28 | release {
29 | minifyEnabled false
30 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
31 | }
32 | }
33 | compileOptions {
34 | sourceCompatibility JavaVersion.VERSION_17
35 | targetCompatibility JavaVersion.VERSION_17
36 | }
37 | kotlinOptions {
38 | jvmTarget = '17'
39 | }
40 | }
41 |
42 | dependencies {
43 | implementation 'androidx.core:core-ktx:1.12.0'
44 | implementation 'androidx.appcompat:appcompat:1.6.1'
45 | implementation 'com.google.android.material:material:1.9.0'
46 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
47 | testImplementation 'junit:junit:4.13.2'
48 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
49 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
50 | //gezinme işlemleri
51 | implementation "androidx.navigation:navigation-fragment-ktx:2.7.3"
52 | //gezinme düğmeleri
53 | implementation "androidx.navigation:navigation-ui-ktx:2.7.3"
54 |
55 | //restful api ile iletişim
56 | implementation "com.squareup.retrofit2:retrofit:2.9.0"
57 |
58 | //Json verilerini nesnelere dönüştürür
59 | implementation "com.squareup.retrofit2:converter-gson:2.9.0"
60 |
61 | //web veya localde alınan verilerin yüklenmesi
62 | implementation "com.github.bumptech.glide:glide:4.15.1"
63 |
64 | //yuvarlatılmış köşeli arayüz için
65 | implementation 'com.github.zladnrms:RoundableLayout:1.1.4'
66 |
67 | //ağ trafiğini izlemek ve hata ayıklamak için kullanılır
68 | implementation "com.github.chuckerteam.chucker:library:4.0.0"
69 |
70 | //bağımlılıkları enjekte eder
71 | implementation 'com.google.dagger:hilt-android:2.47'
72 | //hiltin kodlarını işler
73 | kapt 'com.google.dagger:hilt-compiler:2.47'
74 |
75 | //viewModel:ui ile veri arasındaki bağlantı
76 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"
77 |
78 | //liveData: veri değşimini izler ve ui'a aktarır
79 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
80 |
81 | //Coroutines: arka plan işlemleri ve çoklu iş parçacıkları
82 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
83 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
84 |
85 | //Glide
86 | implementation 'com.github.bumptech.glide:glide:4.15.1'
87 | annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'
88 |
89 |
90 | implementation(platform("com.google.firebase:firebase-bom:32.2.2"))
91 | //firebase auth: kullanıcı kimlik doğrulama
92 | implementation("com.google.firebase:firebase-auth-ktx")
93 | //firebase firestore: db ve clloud storage
94 | implementation("com.google.firebase:firebase-firestore-ktx")
95 |
96 | //SQL Lite veritabanlarına erişim
97 | implementation "androidx.room:room-runtime:2.5.2"
98 | kapt "androidx.room:room-compiler:2.5.2"
99 | implementation "androidx.room:room-ktx:2.5.2"
100 |
101 | // GIF yüklemek ve göstermek için
102 | implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.22'
103 |
104 |
105 | }
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "1040336219074",
4 | "firebase_url": "https://personelkaydet-b1b25-default-rtdb.firebaseio.com",
5 | "project_id": "personelkaydet-b1b25",
6 | "storage_bucket": "personelkaydet-b1b25.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:1040336219074:android:41244fc438fa356a29c45b",
12 | "android_client_info": {
13 | "package_name": "com.adilegungor.gungorecommerce"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "1040336219074-qc522fe5naaf7csa4mrfbtdlqq81ta7l.apps.googleusercontent.com",
19 | "client_type": 3
20 | }
21 | ],
22 | "api_key": [
23 | {
24 | "current_key": "AIzaSyABPWPT5_WByX1iDXA_ORbObEF1BlU83sk"
25 | }
26 | ],
27 | "services": {
28 | "appinvite_service": {
29 | "other_platform_oauth_client": [
30 | {
31 | "client_id": "1040336219074-qc522fe5naaf7csa4mrfbtdlqq81ta7l.apps.googleusercontent.com",
32 | "client_type": 3
33 | }
34 | ]
35 | }
36 | }
37 | }
38 | ],
39 | "configuration_version": "1"
40 | }
--------------------------------------------------------------------------------
/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/androidTest/java/com/adilegungor/gungorecommerce/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.adilegungor.gungorecommerce", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/cartt-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/cartt-playstore.png
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/MainApplication.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor
2 | import android.app.Application
3 | import dagger.hilt.android.HiltAndroidApp
4 |
5 | @HiltAndroidApp
6 | class MainApplication : Application()
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.navigation.fragment.NavHostFragment
6 | import androidx.navigation.ui.NavigationUI
7 | import com.adilegungor.gungorecommerce.R
8 | import com.adilegungor.gungorecommerce.common.viewBinding
9 | import com.adilegungor.gungorecommerce.databinding.ActivityMainBinding
10 | import dagger.hilt.android.AndroidEntryPoint
11 |
12 | @AndroidEntryPoint
13 | class MainActivity : AppCompatActivity() {
14 |
15 | private val binding by viewBinding(ActivityMainBinding::inflate)
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 |
20 | with(binding) {
21 | val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
22 | NavigationUI.setupWithNavController(bottomNavigationView, navHostFragment.navController)
23 | }
24 |
25 | setContentView(binding.root)
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/common/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.common
2 |
3 | object Constants {
4 | //temel url
5 | const val BASE_URL = "https://api.canerture.com/ecommerce/"
6 |
7 | object Endpoint {
8 | //istekleri getiren endpoint noktalarımız
9 | const val ADD_CART_PRODUCTS = "add_to_cart.php"
10 | const val DELETE_CART_PRODUCTS = "delete_from_cart.php"
11 | const val GET_PRODUCTS = "get_products.php"
12 | const val GET_PRODUCT_DETAIL = "get_product_detail.php"
13 | const val GET_SALE_PRODUCTS = "get_sale_products.php"//indirimdekiler
14 | const val CLEAR_CART_PRODUCTS = "clear_cart.php"
15 | const val GET_PRODUCTS_BY_CATEGORY = "get_products_by_category.php"
16 | const val GET_CART_PRODUCTS = "get_cart_products.php"
17 | const val GET_SEARCH_PRODUCT = "search_product.php"
18 |
19 |
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/common/Extensions.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.common
2 |
3 | import android.widget.ImageView
4 | import com.bumptech.glide.Glide
5 | import android.view.View
6 |
7 | // Resim yükleme işlevi
8 | fun ImageView.loadImage(url: String?) {
9 | Glide.with(this.context).load(url).into(this)
10 | }
11 |
12 | // Görünürlüğü gizleme işlevi
13 | fun View.gone() {
14 | visibility = View.GONE // View'ı görünmez yapar
15 | }
16 |
17 | // Görünürlüğü gösterme işlevi
18 | fun View.visible() {
19 | visibility = View.VISIBLE // View'ı görünür yapar
20 | //buraya yeni eklemeler yapılabilir kod geliştirilebilir
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/common/Resource.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.common
2 |
3 | // kaynak sınıfı
4 |
5 | // veri almayı kolaylaştırma
6 |
7 | sealed class Resource {
8 | // Başarılı durum - alt sınıf
9 | data class Success(val data: T) : Resource()
10 |
11 | // Hata durumu - alt sınıf
12 | data class Error(val throwable: Throwable) : Resource()
13 | }
14 | /*val result: Resource = when (someCondition) {
15 | true -> Resource.Success("Başarılı sonuç")
16 | false -> Resource.Error(Exception("Hata oluştu"))
17 | }
18 | */
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/common/ViewBindingExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.common
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 | // AppCompatActivity için bir extension fonksiyonu.
15 | // Verilen bir LayoutInflater işlevi kullanarak ViewBinding oluşturur.
16 | inline fun AppCompatActivity.viewBinding(
17 | crossinline factory: (LayoutInflater) -> T
18 | //lazy: viewbindng nesnesini sadece ilk kez ihtiyaç olunca oluştur.
19 | ) = lazy(LazyThreadSafetyMode.NONE) { // bu işlemi tek bir iş parçacığında gerçekleştir
20 | factory(layoutInflater)
21 | }
22 |
23 | // Fragment için bir extension fonksiyonu. ViewBinding'i oluştururken bir view oluşturucu işlevini kullanır.
24 | fun Fragment.viewBinding(factory: (View) -> T): ReadOnlyProperty =
25 | object : ReadOnlyProperty, DefaultLifecycleObserver {
26 |
27 | private var binding: T? = null
28 |
29 | // ViewBinding'i temsil eden değeri döndürür. Eğer henüz oluşturulmamışsa oluşturur.
30 | override fun getValue(thisRef: Fragment, property: KProperty<*>): T =
31 | binding ?: factory(requireView()).also {
32 | if (viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
33 | // ViewLifecycleOwner'ın yaşam döngüsünü izler ve bağlantıyı korur.
34 | viewLifecycleOwner.lifecycle.addObserver(this)
35 | binding = it
36 | }
37 | }
38 |
39 | // Fragment öldüğünde, ViewBinding'i temizler.
40 | override fun onDestroy(owner: LifecycleOwner) {
41 | binding = null
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/model/AddToCartRequest.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.model
2 | //JSON formatına göre classlar.
3 | data class AddToCartRequest(
4 | val userId: String,
5 | val productId: Int
6 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/model/CRUDResponse.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.model
2 | //CRUD işl. için ol. cl
3 | data class CRUDResponse(
4 | val status: Int?,
5 | val message: String?,
6 | )
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/model/ClearCartRequest.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.model
2 | //sepeeti temizle-kull id. gr
3 | data class ClearCartRequest(
4 | val userId: String,
5 | )
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/model/DeleteFromCartRequest.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.model
2 | //id il sl
3 | data class DeleteFromCartRequest (
4 | val id: Int
5 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/model/GetProductDetailResponse.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.model
2 | //seçilen ürün detayı
3 | data class GetProductDetailResponse(
4 | val status: Int?,
5 | val message: String?,
6 | val product: Product? //nesne
7 | )
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/model/GetProductsResponse.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.model
2 |
3 | data class GetProductsResponse(
4 | val status: Int?,
5 | val message: String?,
6 | val products: List?//tüm liste(ürün)
7 | )
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/model/Product.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.model
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 | //dönüşüm
6 | @Parcelize
7 | data class Product(
8 | val id: Int?,
9 | val title: String?,
10 | val price: Double?,
11 | val salePrice: Double?,
12 | val description: String?,
13 | val category: String?,
14 | val imageOne: String?,
15 | val imageTwo: String?,
16 | val imageThree: String?,
17 | val rate: Double?,
18 | val count: Int?,
19 | val saleState: Boolean? //indirim durumu
20 | // Product sınıfını ProductUI sınıfına dönüştüren işlev
21 | ): Parcelable {
22 | //verileri kullanıcı aryüzünde göstermek için
23 | fun mapToProductUI(): ProductUI {
24 | return ProductUI(
25 | id = id ?: 1,
26 | title = title.orEmpty(),
27 | price = price ?: 0.0,
28 | salePrice = salePrice ?: 0.0,
29 | description = description.orEmpty(),
30 | category = category.orEmpty(),
31 | imageOne = imageOne.orEmpty(),
32 | imageTwo = imageTwo.orEmpty(),
33 | imageThree = imageThree.orEmpty(),
34 | rate = rate ?: 0.0,
35 | count = count ?: 1,
36 | saleState = saleState ?: false
37 | )
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/model/ProductEntity.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.model
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 | // yerel veritabanı kullanımı
7 | @Entity(tableName = "cart_products") //
8 | data class ProductEntity(
9 | //autogenerate: otomatik artış
10 | @PrimaryKey(autoGenerate = true)
11 | @ColumnInfo(name = "id")
12 | val id: Int?,
13 |
14 | @ColumnInfo(name = "title")
15 | val title: String?,
16 |
17 | @ColumnInfo(name = "price")
18 | val price: Double?,
19 |
20 | @ColumnInfo(name = "salePrice")
21 | val salePrice: Double?,
22 |
23 | @ColumnInfo(name = "description")
24 | val description: String?,
25 |
26 | @ColumnInfo(name = "category")
27 | val category: String?,
28 |
29 | @ColumnInfo(name = "imageOne")
30 | val imageOne: String?,
31 |
32 | @ColumnInfo(name = "imageTwo")
33 | val imageTwo: String?,
34 |
35 | @ColumnInfo(name = "imageThree")
36 | val imageThree: String?,
37 |
38 | @ColumnInfo(name = "rate")
39 | val rate: Double?,
40 |
41 | @ColumnInfo(name = "count")
42 | val count: Int?,
43 |
44 | @ColumnInfo(name = "saleState")
45 | val saleState: Boolean?
46 | ) {
47 | //bu fonksiyon product entitiy i product ui a çeviriyor.
48 | fun mapToProductUI(): ProductUI {
49 | return ProductUI(
50 | id = id ?: 1,
51 | title = title.orEmpty(),
52 | price = price ?: 0.0,
53 | salePrice = salePrice ?: 0.0,
54 | description = description.orEmpty(),
55 | category = category.orEmpty(),
56 | imageOne = imageOne.orEmpty(),
57 | imageTwo = imageTwo.orEmpty(),
58 | imageThree = imageThree.orEmpty(),
59 | rate = rate ?: 0.0,
60 | count = count ?: 1,
61 | saleState = saleState ?: false
62 | )
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/model/ProductUI.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.model
2 |
3 | data class ProductUI(
4 | val id: Int,
5 | val title: String,
6 | val price: Double,
7 | val salePrice: Double,
8 | val description: String,
9 | val category: String,
10 | val imageOne: String,
11 | val imageTwo: String,
12 | val imageThree: String,
13 | val rate: Double,
14 | val count: Int,
15 | val saleState: Boolean
16 | ) {
17 | //bu fonksiyon da product ui deki yani kull. dan ald. verileri product entitye e çeviriyor,
18 | // işleme kolaylığı
19 | fun mapToProductEntity(): ProductEntity {
20 | return ProductEntity(
21 | id = id,
22 | title = title,
23 | price = price,
24 | salePrice = salePrice,
25 | description = description,
26 | category = category,
27 | imageOne = imageOne,
28 | imageTwo = imageTwo,
29 | imageThree = imageThree,
30 | rate = rate,
31 | count = count,
32 | saleState = saleState
33 | )
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/repository/ProductRepository.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.repository
2 |
3 | import com.adilegungor.gungorecommerce.common.Resource
4 | import com.adilegungor.gungorecommerce.data.model.AddToCartRequest
5 | import com.adilegungor.gungorecommerce.data.model.CRUDResponse
6 | import com.adilegungor.gungorecommerce.data.model.ClearCartRequest
7 | import com.adilegungor.gungorecommerce.data.model.DeleteFromCartRequest
8 | import com.adilegungor.gungorecommerce.data.model.ProductUI
9 | import com.adilegungor.gungorecommerce.data.source.local.ProductDao
10 | import com.adilegungor.gungorecommerce.data.source.remote.ProductService
11 | import javax.inject.Inject
12 | //try-catch blokları
13 | //response and process
14 | //hilt
15 | class ProductRepository @Inject constructor(
16 | //uzak ve yerel veritabanı erişimi
17 | private val productService: ProductService,
18 | private val productDao: ProductDao,
19 | ) {
20 |
21 | suspend fun getProducts(): Resource> {
22 | //uzaktan veri kayn. erişir verileri dönüştürür(product ui obj)sonra resource u kull.
23 | return try {
24 | Resource.Success(productService.getProducts().products?.map { it.mapToProductUI() }.orEmpty())
25 | } catch (e: Exception) {
26 | Resource.Error(e)
27 | }
28 | }
29 | //tüm ürünler
30 | suspend fun getSaleProducts(): Resource> {
31 | return try {
32 | Resource.Success(productService.getSaleProducts().products?.map { it.mapToProductUI() }.orEmpty())
33 | } catch (e: Exception) {
34 | Resource.Error(e)
35 | }
36 | }
37 | //belli kategoriye aiy ürünler
38 | suspend fun getProductsByCategory(category: String): Resource> {
39 | return try {
40 | Resource.Success(productService.getProductsByCategory(category).products?.map { it.mapToProductUI() }.orEmpty())
41 | } catch (e: Exception) {
42 | Resource.Error(e)
43 | }
44 | }
45 | //ürün detay
46 | suspend fun getProductsDetail(id: Int): Resource {
47 | return try {
48 | productService.getProductDetail(id).product?.let {
49 | Resource.Success(it.mapToProductUI())
50 | } ?: kotlin.run {
51 | Resource.Error(Exception("Product not found"))
52 | }
53 | } catch (e: Exception) {
54 | Resource.Error(e)
55 | }
56 | }
57 |
58 | suspend fun getSearchProduct(query: String): Resource> {
59 | return try {
60 | val response = productService.getSearchProduct(query)
61 | Resource.Success(response.products?.map { it.mapToProductUI() }.orEmpty())
62 | } catch (e: Exception) {
63 | Resource.Error(e)
64 | }
65 | }
66 |
67 | suspend fun deleteProductFromFav(product: ProductUI) {
68 | productDao.deleteProduct(product.mapToProductEntity())
69 | }
70 |
71 | suspend fun getFavProducts(): Resource> {
72 | return try {
73 | Resource.Success(productDao.getProducts().map {
74 | it.mapToProductUI()
75 | })
76 | } catch (e: Exception) {
77 | Resource.Error(e)
78 | }
79 | }
80 | //favoriye ekle
81 | suspend fun addProductToFav(product: ProductUI) {
82 | productDao.addProduct(product.mapToProductEntity())
83 | }
84 | //sepete ekle
85 | suspend fun addProductToCart(addToCartRequest: AddToCartRequest): CRUDResponse {
86 | return productService.addProductToCart(addToCartRequest)
87 | }
88 | //sepettekşleri listele
89 | suspend fun getCartProduct(userId: String): Resource> {
90 | return try {
91 | val response = productService.getCartProducts(userId)
92 | Resource.Success(response.products?.map { it.mapToProductUI() }.orEmpty())
93 | } catch (e: Exception) {
94 | Resource.Error(e)
95 | }
96 | }
97 | //sepetten ürün sil
98 | suspend fun deleteProductFromCart(request: DeleteFromCartRequest): CRUDResponse {
99 | return productService.deleteProductFromCart(request)
100 | }
101 | //sepeti boşalt
102 | //product service ile uzak veri kaynağına req atar ve sonucu resource formda döndürür.
103 | suspend fun clearProductFromCart(request: ClearCartRequest): Resource {
104 | return try {
105 | val response = productService.clearProductFromCart(request)
106 | Resource.Success(response)
107 | } catch (e: Exception) {
108 | Resource.Error(e)
109 | }
110 | }
111 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/source/local/ProductDao.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.source.local
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Delete
5 | import androidx.room.Insert
6 | import androidx.room.OnConflictStrategy
7 | import androidx.room.Query
8 | import com.adilegungor.gungorecommerce.data.model.ProductEntity
9 |
10 |
11 | @Dao //sınıf:roomdao
12 | interface ProductDao {
13 |
14 | @Query("SELECT * FROM cart_products")//get all pro
15 | suspend fun getProducts(): List
16 | //product entity veri listesi
17 | //askıya alınır işlem- tüm ürünleri al.
18 |
19 | @Insert(onConflict = OnConflictStrategy.REPLACE)
20 | //onflict:çakışma=>yeniyi ekle
21 | suspend fun addProduct(product: ProductEntity)
22 |
23 | @Delete
24 | suspend fun deleteProduct(product: ProductEntity)
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/source/local/ProductRoomDB.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.source.local
2 |
3 |
4 | import androidx.room.Database
5 | import androidx.room.RoomDatabase
6 | import com.adilegungor.gungorecommerce.data.model.ProductEntity
7 |
8 | //favoriler için @Database(entities = [ProductEntity::class, ProductEntity::class], version = 1)
9 | //veritabanısınıf:local dbleri yönet.
10 | //[ProductEntity::class] hangi db kull. tanım
11 | @Database(entities = [ProductEntity::class], version = 1)
12 | //db değiş. sürüm upd. et. vers.
13 |
14 | //roomdb local db işl. için.
15 | //kalıtım
16 | abstract class ProductRoomDB : RoomDatabase(){
17 |
18 | abstract fun productsDao(): ProductDao
19 | //db işlemlerinin nin olduğu daoya erişim
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/data/source/remote/ProductService.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.data.source.remote
2 |
3 | import com.adilegungor.gungorecommerce.common.Constants.Endpoint.ADD_CART_PRODUCTS
4 | import com.adilegungor.gungorecommerce.common.Constants.Endpoint.CLEAR_CART_PRODUCTS
5 | import com.adilegungor.gungorecommerce.common.Constants.Endpoint.DELETE_CART_PRODUCTS
6 | import com.adilegungor.gungorecommerce.common.Constants.Endpoint.GET_CART_PRODUCTS
7 | import com.adilegungor.gungorecommerce.common.Constants.Endpoint.GET_PRODUCTS
8 | import com.adilegungor.gungorecommerce.common.Constants.Endpoint.GET_PRODUCTS_BY_CATEGORY
9 | import com.adilegungor.gungorecommerce.common.Constants.Endpoint.GET_PRODUCT_DETAIL
10 | import com.adilegungor.gungorecommerce.common.Constants.Endpoint.GET_SALE_PRODUCTS
11 | import com.adilegungor.gungorecommerce.common.Constants.Endpoint.GET_SEARCH_PRODUCT
12 | import com.adilegungor.gungorecommerce.data.model.AddToCartRequest
13 | import com.adilegungor.gungorecommerce.data.model.CRUDResponse
14 | import com.adilegungor.gungorecommerce.data.model.ClearCartRequest
15 | import com.adilegungor.gungorecommerce.data.model.DeleteFromCartRequest
16 | import com.adilegungor.gungorecommerce.data.model.GetProductDetailResponse
17 | import com.adilegungor.gungorecommerce.data.model.GetProductsResponse
18 | import retrofit2.http.Body
19 | import retrofit2.http.GET
20 | import retrofit2.http.POST
21 | import retrofit2.http.Query
22 | //http istekleri
23 | interface ProductService {
24 | @GET(GET_PRODUCTS)
25 |
26 | //retrofitin coroutine desteği
27 | suspend fun getProducts(): GetProductsResponse
28 |
29 | @GET(GET_PRODUCT_DETAIL)
30 | suspend fun getProductDetail(@Query("id") id: Int): GetProductDetailResponse
31 |
32 | @GET(GET_SALE_PRODUCTS)
33 | suspend fun getSaleProducts(): GetProductsResponse
34 |
35 | @GET(GET_PRODUCTS_BY_CATEGORY)
36 | suspend fun getProductsByCategory(@Query("category") categoryValue: String): GetProductsResponse
37 |
38 | @GET(GET_SEARCH_PRODUCT)
39 | suspend fun getSearchProduct(@Query("query") queryValue: String): GetProductsResponse
40 |
41 | @GET(GET_CART_PRODUCTS)
42 | suspend fun getCartProducts(@Query("userId") userId: String): GetProductsResponse
43 |
44 | @POST(ADD_CART_PRODUCTS)
45 | suspend fun addProductToCart(@Body request: AddToCartRequest): CRUDResponse
46 |
47 | @POST(DELETE_CART_PRODUCTS)
48 | suspend fun deleteProductFromCart(@Body request: DeleteFromCartRequest): CRUDResponse//yanıt
49 | //body type: veriyi gövdeye koy
50 | @POST(CLEAR_CART_PRODUCTS)
51 | suspend fun clearProductFromCart(@Body request: ClearCartRequest): CRUDResponse
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/di/NetworkModule.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.di
2 |
3 | import android.content.Context
4 | import com.chuckerteam.chucker.api.ChuckerInterceptor
5 | import com.adilegungor.gungorecommerce.common.Constants.BASE_URL
6 | import com.adilegungor.gungorecommerce.data.source.remote.ProductService
7 | import dagger.Module
8 | import dagger.Provides
9 | import dagger.hilt.InstallIn
10 | import dagger.hilt.android.qualifiers.ApplicationContext
11 | import dagger.hilt.components.SingletonComponent
12 | import okhttp3.OkHttpClient
13 | import retrofit2.Retrofit
14 | import retrofit2.converter.gson.GsonConverterFactory
15 | import retrofit2.create
16 | import java.util.concurrent.TimeUnit
17 | import javax.inject.Singleton
18 | //dagger ile ağ işlemleri bağımlılıkları vs.
19 | //aş. etiketler modülün dagger olduğunu ve bağımlıkların singletona kurulcağını gösterir. isimden bariz.
20 | //yaşam döngüsü boyunca 1 kez kur bağ.ın yön.
21 | @Module
22 | @InstallIn(SingletonComponent::class)
23 | //hilt bağ. tems. eden modülümüz
24 | object NetworkModule {
25 | //zaman aşımı ağ isteklerinin ne kadar bekleyeceiği hk.
26 | private const val TIMEOUT = 60L
27 |
28 | @Provides
29 | @Singleton
30 | fun provideChuckerInterceptor(@ApplicationContext context:Context) = ChuckerInterceptor.Builder(context).build()
31 | //chucker ı burada kullandım. Ağ isteklerini uygulama çalışma esnasında izlemek için.
32 | @Provides
33 | @Singleton
34 | fun provideOkHttpClient(chuckerInterceptor: ChuckerInterceptor) = OkHttpClient.Builder().apply {
35 | addInterceptor { chain ->
36 | val originalRequest = chain.request()
37 | val modifiedRequest = originalRequest.newBuilder()
38 | .addHeader("store", "canerture")
39 | .build()
40 | chain.proceed(modifiedRequest)
41 | }
42 | //addıntercopter ile ağ isteklerine özel başlık ekkl.
43 | addInterceptor(chuckerInterceptor)
44 |
45 | //zaman aşımı süreleri belirleniyor
46 | readTimeout(TIMEOUT, TimeUnit.SECONDS)
47 | connectTimeout(TIMEOUT, TimeUnit.SECONDS)
48 | writeTimeout(TIMEOUT, TimeUnit.SECONDS)
49 | }.build()
50 |
51 | @Provides
52 | @Singleton
53 |
54 | //okhhttp ile retrofit istemcisi oluşturur ve gson ekler, gson eklenmiş: JSON verileri nesnelere çeviriyor
55 | fun provideRetrofit(okHttpClient: OkHttpClient) = Retrofit.Builder()
56 | .baseUrl(BASE_URL)
57 | .client(okHttpClient)
58 | .addConverterFactory(GsonConverterFactory.create())
59 | .build()
60 |
61 | @Provides
62 | @Singleton
63 | fun provideService(retrofit: Retrofit) = retrofit.create()
64 | //api çağırmak için retrofit nesnesi kull. Product service oluşturuldu.
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/di/RepositoryModule.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.di
2 |
3 | import com.adilegungor.gungorecommerce.data.repository.ProductRepository
4 | import com.adilegungor.gungorecommerce.data.source.local.ProductDao
5 | import com.adilegungor.gungorecommerce.data.source.remote.ProductService
6 | import dagger.Module
7 | import dagger.Provides
8 | import dagger.hilt.InstallIn
9 | import dagger.hilt.components.SingletonComponent
10 | import javax.inject.Singleton
11 |
12 | @Module
13 | @InstallIn(SingletonComponent::class)
14 | object RepositoryModule {
15 |
16 | @Provides
17 | @Singleton
18 | fun provideRepository(productService: ProductService, productDao: ProductDao) : ProductRepository =
19 | ProductRepository(productService, productDao)
20 | //uzak sunucudan veri çekmede retrofit servisini temsil eden nesne:product service
21 | //local db veri yönetimi sağlar: productdao obj.
22 | //ağ üzerinden veri çekme + yerel veri db ye bunları kaydetme: ProductRepository obj.
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/di/RoomDBModule.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.di
2 |
3 | import android.content.Context
4 | import androidx.room.Room
5 | import com.adilegungor.gungorecommerce.data.source.local.ProductRoomDB
6 | import dagger.Module
7 | import dagger.Provides
8 | import dagger.hilt.InstallIn
9 | import dagger.hilt.android.qualifiers.ApplicationContext
10 | import dagger.hilt.components.SingletonComponent
11 | import javax.inject.Singleton
12 |
13 | @Module
14 | @InstallIn(SingletonComponent::class)
15 | object RoomDBModule {
16 |
17 | @Provides
18 | @Singleton
19 |
20 | //aş. @ notasyonu uyg. genel bağlamını (context) alır ve db yi oluşturur.
21 | fun provideRoomDB(@ApplicationContext context: Context) =
22 | Room.databaseBuilder(context, ProductRoomDB::class.java, "product_room_db").build()
23 | //burada bir product roomdb oluşturuldu
24 | @Provides
25 | @Singleton
26 |
27 | //aş. fonk. roomdb den dao oluşt. ve döndürür. - dao locale erişir-db etkileşimi
28 | fun provideDao(roomDB: ProductRoomDB) = roomDB.productsDao()
29 |
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/anasayfa/HomeFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.anasayfa
2 |
3 | import android.os.Bundle
4 | import android.view.MenuItem
5 | import android.view.View
6 | import androidx.appcompat.widget.Toolbar
7 | import androidx.fragment.app.Fragment
8 | import androidx.fragment.app.viewModels
9 | import androidx.navigation.fragment.findNavController
10 | import com.adilegungor.gungorecommerce.R
11 | import com.adilegungor.gungorecommerce.common.viewBinding
12 | import com.adilegungor.gungorecommerce.data.model.ProductUI
13 | import com.adilegungor.gungorecommerce.databinding.FragmentHomeBinding
14 | import com.google.android.material.bottomnavigation.BottomNavigationView
15 | import com.google.android.material.snackbar.Snackbar
16 | import dagger.hilt.android.AndroidEntryPoint
17 | //hilt usg
18 | @AndroidEntryPoint
19 | class HomeFragment : Fragment(R.layout.fragment_home), ProductAdapter.ProductListener, SalesProductAdapter.ProductListener {
20 | //viewbinding ile xml deki görünümlere erişim
21 | private val binding by viewBinding(FragmentHomeBinding::bind)
22 |
23 | private var bottomNavigationView: BottomNavigationView? = null
24 | private val productAdapter by lazy { ProductAdapter(this) }
25 | private val viewModel by viewModels()
26 | //indirimli ürünleri listeler, dinleyici kendisi
27 | private val salesProductAdapter by lazy { SalesProductAdapter(this) }
28 |
29 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
30 | super.onViewCreated(view, savedInstanceState)
31 |
32 | //visibility:görünürlük
33 | bottomNavigationView = getActivity()?.findViewById(R.id.bottomNavigationView);
34 | bottomNavigationView?.setVisibility(View.VISIBLE);
35 | with(binding) {
36 | rvAllProducts.adapter = productAdapter
37 | rvDiscountedProducts.adapter = salesProductAdapter
38 | radioGroup.setOnCheckedChangeListener { group, checkedId ->
39 | if (checkedId == R.id.rb_all) {
40 | viewModel.getProducts()
41 | } else {
42 | //kategoriye göre listeleme
43 | val category = when (checkedId) {
44 | R.id.rb_notebook -> "notebook"
45 | R.id.rbmntr -> "monitor"
46 | R.id.rbhdst->"headset"
47 | R.id.rbcnsl->"console"
48 | R.id.rbdsktop->"desktop"
49 | else -> "all"
50 | }
51 | viewModel.getProductsByCategory(category)
52 | }
53 | }
54 |
55 |
56 |
57 | toolbar.setOnMenuItemClickListener (object : MenuItem.OnMenuItemClickListener,
58 | Toolbar.OnMenuItemClickListener {
59 | override fun onMenuItemClick(item: MenuItem): Boolean {
60 | when (item.itemId) {
61 | R.id.action_profile -> {
62 | findNavController().navigate(HomeFragmentDirections.actionHomeFragmentToProfileFragment())
63 | return true
64 | }
65 | }
66 |
67 | return false
68 | }
69 | })
70 | }
71 |
72 | viewModel.getProducts()
73 | viewModel.getSaleProducts()
74 |
75 | observeData()
76 | }
77 | // verilerin ya dhata durumlarını gözlenmesi
78 | private fun observeData() = with(binding) {
79 | viewModel.homeState.observe(viewLifecycleOwner) { state ->
80 | when (state) {
81 | HomeState.Loading -> {
82 | progressBar2.visibility = View.VISIBLE
83 | }
84 |
85 | is HomeState.Data -> {
86 | progressBar2.visibility = View.GONE
87 | productAdapter.submitList(state.productsResponse)
88 | }
89 |
90 | is HomeState.Error -> {
91 | tvError.setText(state.throwable.message.orEmpty())
92 | //veri gelince progress bar gizlenir. Recyclerviewe veri eklenir
93 | progressBar2.visibility = View.GONE
94 | rvAllProducts.visibility = View.GONE
95 | ivError.visibility = View.VISIBLE
96 | tvError.visibility = View.VISIBLE
97 | Snackbar.make(requireView(), state.throwable.message.orEmpty(), 1000).show()
98 | }
99 | }
100 | }
101 |
102 | viewModel.salesState.observe(viewLifecycleOwner) { state ->
103 | when (state) {
104 | SalesState.Loading -> {
105 | progressBar2.visibility = View.VISIBLE
106 | }
107 |
108 | is SalesState.Data -> {
109 | progressBar2.visibility = View.GONE
110 | salesProductAdapter.submitList(state.productsResponse)
111 | }
112 |
113 | is SalesState.Error -> {
114 | progressBar2.visibility = View.GONE
115 | Snackbar.make(requireView(), state.throwable.message.orEmpty(), 1000).show()
116 | }
117 | }
118 | }
119 | }
120 |
121 | //ürüne tıklayınca detaya git
122 | override fun onProductClick(id: Int) {
123 | val action = HomeFragmentDirections.actionHomeFragmentToProductDetailFragment(id)
124 | findNavController().navigate(action)
125 | }
126 |
127 | //fav a tıklayınca fav e ekle ve msg göster.
128 | override fun onFavoriteClick(product: ProductUI) {
129 | viewModel.addProductToFav(product)
130 | Snackbar.make(requireView(), "Favorilere Eklendi!", Snackbar.LENGTH_SHORT).show()
131 | }
132 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/anasayfa/HomeViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.anasayfa
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import com.adilegungor.gungorecommerce.common.Resource
7 | import com.adilegungor.gungorecommerce.data.model.ProductUI
8 | import com.adilegungor.gungorecommerce.data.repository.ProductRepository
9 | import com.adilegungor.gungorecommerce.ui.viewmodel.BaseViewModel
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.launch
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | //kalıtım + repo ile verilere erişim
16 | class HomeViewModel
17 | @Inject constructor(
18 | private val productRepository: ProductRepository, application: Application
19 | ): BaseViewModel(application) {
20 |
21 | private var _homeState = MutableLiveData()
22 | val homeState: LiveData
23 | get() = _homeState
24 |
25 | private var _salesState = MutableLiveData()
26 | val salesState: LiveData
27 | get() = _salesState
28 |
29 |
30 | //başlatıcı
31 | init {
32 | }
33 |
34 | fun getProducts() {
35 | launch {
36 | _homeState.value = HomeState.Loading
37 | val result = productRepository.getProducts()
38 |
39 | when (result) {
40 | is Resource.Success -> {
41 | _homeState.value = HomeState.Data(result.data)
42 | }
43 |
44 | is Resource.Error -> {
45 | _homeState.value = HomeState.Error(result.throwable)
46 | }
47 | }
48 | }
49 | }
50 |
51 | fun getSaleProducts() {
52 | launch {
53 | _salesState.value = SalesState.Loading
54 | val result = productRepository.getSaleProducts()
55 |
56 | when (result) {
57 | is Resource.Success -> {
58 | _salesState.value = SalesState.Data(result.data)
59 | }
60 |
61 | is Resource.Error -> {
62 | _salesState.value = SalesState.Error(result.throwable)
63 | }
64 | }
65 | }
66 | }
67 |
68 | fun getProductsByCategory(category: String) {
69 | launch {
70 | _homeState.value = HomeState.Loading
71 | val result = productRepository.getProductsByCategory(category)
72 |
73 | when (result) {
74 | is Resource.Success -> {
75 | _homeState.value = HomeState.Data(result.data)
76 | }
77 |
78 | is Resource.Error -> {
79 | _homeState.value = HomeState.Error(result.throwable)
80 | }
81 | }
82 | }
83 | }
84 |
85 | fun addProductToFav(product: ProductUI) {
86 | launch {
87 | productRepository.addProductToFav(product)
88 | }
89 | }
90 | }
91 |
92 | sealed interface HomeState {
93 | object Loading: HomeState
94 | data class Data(val productsResponse: List): HomeState
95 |
96 | data class Error(val throwable: Throwable): HomeState
97 | }
98 |
99 | sealed interface SalesState {
100 | object Loading: SalesState
101 | data class Data(val productsResponse: List): SalesState
102 |
103 | data class Error(val throwable: Throwable): SalesState
104 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/anasayfa/ProductAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.anasayfa
2 |
3 | import android.graphics.Paint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.core.view.isVisible
7 | import androidx.recyclerview.widget.DiffUtil
8 | import androidx.recyclerview.widget.ListAdapter
9 | import androidx.recyclerview.widget.RecyclerView
10 | import com.adilegungor.gungorecommerce.common.loadImage
11 | import com.adilegungor.gungorecommerce.data.model.ProductUI
12 | import com.adilegungor.gungorecommerce.databinding.ItemProductBinding
13 |
14 | class ProductAdapter (
15 | private val productListener: ProductListener
16 | ) : ListAdapter(ProductDiffCallBack()) {
17 |
18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder =
19 | ProductViewHolder(
20 | ItemProductBinding.inflate(LayoutInflater.from(parent.context), parent, false),
21 | productListener
22 | )
23 |
24 | override fun onBindViewHolder(holder: ProductViewHolder, position: Int) =
25 | holder.bind(getItem(position))
26 |
27 | class ProductViewHolder(
28 | private val binding: ItemProductBinding,
29 | private val productListener: ProductListener
30 | ) : RecyclerView.ViewHolder(binding.root) {
31 |
32 | fun bind(product: ProductUI) = with(binding) {
33 | tvTitle.text = product.title
34 | tvDesc.text = product.description
35 | tvCategory.text = product.category
36 |
37 | imgProduct.loadImage(product.imageOne)
38 |
39 | if (product.saleState == true) {
40 | tvSalePrice.isVisible = true
41 | tvSalePrice.text = "${product.salePrice} ₺"
42 | tvPrice.text = "${product.price} ₺"
43 | tvPrice.paintFlags = tvPrice.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
44 | } else {
45 | tvPrice.text = "${product.price} ₺"
46 | tvSalePrice.isVisible = false
47 | }
48 |
49 | imgFavorite.setOnClickListener {
50 | productListener.onFavoriteClick(product)
51 | }
52 |
53 | root.setOnClickListener {
54 | productListener.onProductClick(product.id)
55 | }
56 |
57 |
58 | }
59 | }
60 |
61 | class ProductDiffCallBack : DiffUtil.ItemCallback() {
62 | override fun areItemsTheSame(oldItem: ProductUI, newItem: ProductUI): Boolean {
63 | return oldItem.id == newItem.id
64 | }
65 |
66 | override fun areContentsTheSame(oldItem: ProductUI, newItem: ProductUI): Boolean {
67 | return oldItem == newItem
68 | }
69 | //ürün karş.
70 | }
71 |
72 | interface ProductListener {
73 | fun onProductClick(id: Int)
74 | fun onFavoriteClick(product: ProductUI)
75 | }
76 |
77 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/anasayfa/SalesProductAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.anasayfa
2 |
3 | import android.graphics.Paint
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.core.view.isVisible
7 | import androidx.recyclerview.widget.DiffUtil
8 | import androidx.recyclerview.widget.ListAdapter
9 | import androidx.recyclerview.widget.RecyclerView
10 | import com.adilegungor.gungorecommerce.common.loadImage
11 | import com.adilegungor.gungorecommerce.data.model.ProductUI
12 | import com.adilegungor.gungorecommerce.databinding.ItemSalesProductBinding
13 |
14 | class SalesProductAdapter (
15 | private val productListener: ProductListener
16 | ) : ListAdapter(ProductDiffCallBack()) {
17 |
18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SalesProductViewHolder =
19 | SalesProductViewHolder(
20 | ItemSalesProductBinding.inflate(LayoutInflater.from(parent.context), parent, false),
21 | productListener
22 | )
23 |
24 | override fun onBindViewHolder(holder: SalesProductViewHolder, position: Int) =
25 | holder.bind(getItem(position))
26 |
27 | class SalesProductViewHolder(
28 | private val binding: ItemSalesProductBinding,
29 | private val productListener: ProductListener
30 | ) : RecyclerView.ViewHolder(binding.root) {
31 |
32 | fun bind(product: ProductUI) = with(binding) {
33 | tvTitle.text = product.title
34 | tvCategory.text = product.category
35 | tvPrice.text = "${product.price} ₺"
36 |
37 | imgProduct.loadImage(product.imageOne)
38 |
39 | if (product.saleState == true) {
40 | tvSalePrice.isVisible = true
41 | tvSalePrice.text = "${product.salePrice} ₺"
42 | tvPrice.text = "${product.price} ₺"
43 | tvPrice.paintFlags = tvPrice.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
44 | } else {
45 | tvPrice.text = "${product.price} ₺"
46 | tvSalePrice.isVisible = false
47 | }
48 |
49 | imgFavorite.setOnClickListener {
50 | productListener.onFavoriteClick(product)
51 | }
52 |
53 | root.setOnClickListener {
54 | productListener.onProductClick(product.id ?: 1)
55 | }
56 | }
57 | }
58 |
59 | class ProductDiffCallBack : DiffUtil.ItemCallback() {
60 | override fun areItemsTheSame(oldItem: ProductUI, newItem: ProductUI): Boolean {
61 | return oldItem.id == newItem.id
62 | }
63 |
64 | override fun areContentsTheSame(oldItem: ProductUI, newItem: ProductUI): Boolean {
65 | return oldItem == newItem
66 | }
67 | }
68 |
69 | interface ProductListener {
70 | fun onProductClick(id: Int)
71 | fun onFavoriteClick(product: ProductUI)
72 | }
73 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/arama/SearchAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.arama
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.DiffUtil
6 | import androidx.recyclerview.widget.ListAdapter
7 | import androidx.recyclerview.widget.RecyclerView
8 | import com.adilegungor.gungorecommerce.common.loadImage
9 | import com.adilegungor.gungorecommerce.data.model.ProductUI
10 | import com.adilegungor.gungorecommerce.databinding.ItemSearchBinding
11 |
12 | class SearchAdapter (
13 | private val searchProductListener: SearchProductListener
14 | ) : ListAdapter(ProductDiffCallBack()) {
15 |
16 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchProductViewHolder =
17 | SearchProductViewHolder(
18 | ItemSearchBinding.inflate(LayoutInflater.from(parent.context), parent, false),
19 | searchProductListener
20 | )
21 |
22 | override fun onBindViewHolder(holder: SearchProductViewHolder, position: Int) = holder.bind(getItem(position))
23 |
24 | class SearchProductViewHolder(
25 | private val binding: ItemSearchBinding,
26 | private val searchProductListener: SearchProductListener
27 | ) : RecyclerView.ViewHolder(binding.root) {
28 |
29 | fun bind(product: ProductUI) = with(binding) {
30 | tvTitle.text = product.title
31 | ivProduct.loadImage(product.imageOne)
32 |
33 | root.setOnClickListener {
34 | searchProductListener.onProductClick(product.id)
35 | }
36 |
37 | }
38 | }
39 |
40 | class ProductDiffCallBack : DiffUtil.ItemCallback() {
41 | override fun areItemsTheSame(oldItem: ProductUI, newItem: ProductUI): Boolean {
42 | return oldItem.id == newItem.id
43 | }
44 |
45 | override fun areContentsTheSame(oldItem: ProductUI, newItem: ProductUI): Boolean {
46 | return oldItem == newItem
47 | }
48 | }
49 |
50 | interface SearchProductListener {
51 | fun onProductClick(id: Int)
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/arama/SearchFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.arama
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.activity.OnBackPressedCallback
6 | import androidx.appcompat.widget.SearchView
7 | import androidx.fragment.app.Fragment
8 | import androidx.fragment.app.viewModels
9 | import androidx.navigation.fragment.findNavController
10 | import com.adilegungor.gungorecommerce.R
11 | import com.adilegungor.gungorecommerce.common.gone
12 | import com.adilegungor.gungorecommerce.common.viewBinding
13 | import com.adilegungor.gungorecommerce.common.visible
14 | import com.adilegungor.gungorecommerce.databinding.FragmentSearchBinding
15 | import com.google.android.material.snackbar.Snackbar
16 | import dagger.hilt.android.AndroidEntryPoint
17 |
18 | @AndroidEntryPoint
19 | class SearchFragment : Fragment(R.layout.fragment_search), SearchAdapter.SearchProductListener {
20 |
21 | private val binding by viewBinding(FragmentSearchBinding::bind)
22 |
23 | private val viewModel by viewModels()
24 |
25 | private val searchAdapter by lazy { SearchAdapter(this) }
26 |
27 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
28 | super.onViewCreated(view, savedInstanceState)
29 |
30 | with(binding) {
31 | rvSearch.adapter = searchAdapter
32 |
33 | searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
34 | override fun onQueryTextSubmit(query: String?): Boolean {
35 | return false
36 | }
37 |
38 | override fun onQueryTextChange(newText: String?): Boolean {
39 | newText?.let { query ->
40 | if (query.length >= 3) {
41 | viewModel.getSearchProduct(query)
42 | } else {
43 | Snackbar.make(requireView(), "Aramak istediğiniz ürün için en az 3 karakter giriniz", 1000).show()
44 | }
45 | }
46 | return true
47 | }
48 | })
49 | }
50 |
51 | val callback = object : OnBackPressedCallback(true) {
52 | override fun handleOnBackPressed() {
53 | val action = SearchFragmentDirections.actionSearchFragmentToHomeFragment()
54 | findNavController().navigate(action)
55 | }
56 | }
57 |
58 | requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)
59 |
60 | observeData()
61 | }
62 |
63 | private fun observeData() = with(binding) {
64 | viewModel.searchState.observe(viewLifecycleOwner) { state ->
65 | when (state) {
66 | is SearchState.Loading -> {
67 | progressBar2.visible()
68 | }
69 |
70 | is SearchState.Data -> {
71 | progressBar2.gone()
72 | searchAdapter.submitList(state.products)
73 | }
74 |
75 | is SearchState.Error -> {
76 | progressBar2.gone()
77 | }
78 | }
79 | }
80 | }
81 | override fun onProductClick(id: Int) {
82 | val action = SearchFragmentDirections.actionSearchFragmentToProductDetailFragment(id)
83 | findNavController().navigate(action)
84 | }
85 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/arama/SearchViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.arama
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import com.adilegungor.gungorecommerce.common.Resource
7 | import com.adilegungor.gungorecommerce.data.model.ProductUI
8 | import com.adilegungor.gungorecommerce.data.repository.ProductRepository
9 | import com.adilegungor.gungorecommerce.ui.viewmodel.BaseViewModel
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.launch
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class SearchViewModel @Inject constructor(
16 | private val productRepository: ProductRepository, application: Application
17 | ) : BaseViewModel(application) {
18 |
19 | private var _searchState = MutableLiveData()
20 | val searchState: LiveData
21 | get() = _searchState
22 |
23 | fun getSearchProduct(query: String) {
24 | launch {
25 | _searchState.value = SearchState.Loading
26 | when (val result = productRepository.getSearchProduct(query)) {
27 | is Resource.Success -> {
28 | _searchState.value = SearchState.Data(result.data)
29 | }
30 |
31 | is Resource.Error -> {
32 | _searchState.value = SearchState.Error(result.throwable)
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
39 | sealed interface SearchState {
40 | object Loading : SearchState
41 | data class Data(val products: List) : SearchState
42 | data class Error(val throwable: Throwable) : SearchState
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/detay/ProductDetailFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.detay
2 |
3 | import android.graphics.Paint
4 | import android.os.Bundle
5 | import android.view.View
6 | import androidx.core.view.isVisible
7 | import androidx.fragment.app.Fragment
8 | import androidx.fragment.app.viewModels
9 | import androidx.navigation.fragment.findNavController
10 | import androidx.navigation.fragment.navArgs
11 | import com.adilegungor.gungorecommerce.R
12 | import com.adilegungor.gungorecommerce.common.loadImage
13 | import com.adilegungor.gungorecommerce.common.viewBinding
14 | import com.adilegungor.gungorecommerce.data.model.AddToCartRequest
15 | import com.adilegungor.gungorecommerce.data.model.ProductUI
16 | import com.adilegungor.gungorecommerce.databinding.FragmentProductDetailBinding
17 | import com.google.android.material.bottomnavigation.BottomNavigationView
18 | import com.google.android.material.snackbar.Snackbar
19 | import com.google.firebase.auth.FirebaseAuth
20 | import com.google.firebase.auth.ktx.auth
21 | import com.google.firebase.ktx.Firebase
22 | import dagger.hilt.android.AndroidEntryPoint
23 |
24 | @AndroidEntryPoint
25 | class ProductDetailFragment : Fragment(R.layout.fragment_product_detail) {
26 |
27 | private val binding by viewBinding(FragmentProductDetailBinding::bind)
28 |
29 | private val args by navArgs()
30 |
31 | private val viewModel by viewModels()
32 |
33 | private var bottomNavigationView: BottomNavigationView? = null
34 |
35 | private lateinit var auth: FirebaseAuth
36 |
37 | var product: ProductUI ?= null
38 |
39 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
40 | super.onViewCreated(view, savedInstanceState)
41 |
42 | auth = Firebase.auth
43 | val userId = auth.currentUser!!.uid
44 |
45 | viewModel.getProductsDetail(args.productId)
46 |
47 | val request = AddToCartRequest(userId, args.productId)
48 |
49 | // Bottom Navigation Visibility
50 | bottomNavigationView = getActivity()?.findViewById(R.id.bottomNavigationView);
51 | bottomNavigationView?.setVisibility(View.GONE);
52 |
53 | with(binding) {
54 | toolbar.setNavigationOnClickListener {
55 | findNavController().navigateUp()
56 | }
57 |
58 | btnAddCart.setOnClickListener {
59 | viewModel.addProductToCart(request)
60 | Snackbar.make(requireView(), "Ürün sepete eklendi!", 1000).show()
61 | }
62 | }
63 | observeData()
64 | }
65 |
66 | private fun observeData() = with(binding) {
67 |
68 | viewModel.productDetailState.observe(viewLifecycleOwner) { state ->
69 | when (state) {
70 | ProductDetailState.Loading -> {
71 | detailProgressBar.visibility = View.VISIBLE
72 | }
73 |
74 | is ProductDetailState.Data -> {
75 | detailProgressBar.visibility = View.GONE
76 | val scaledRating = (state.productResponse?.rate?.toFloat()!! / 5.0f) * 100.0f // Rate değeri
77 | product = state.productResponse
78 | if (state.productResponse != null) {
79 | tvTitle.text = state.productResponse.title
80 | tvDesc.text = state.productResponse.description
81 | tvCategory.text = state.productResponse.category
82 | ivProduct.loadImage(state.productResponse.imageOne)
83 | ratingBar.rating = scaledRating / 20.0f
84 |
85 | if (state.productResponse.saleState == true) {
86 | tvDetailSalePrice.isVisible = true
87 | tvDetailSalePrice.text = "${state.productResponse.salePrice } TL"
88 | tvPrice.text = "${state.productResponse.price * state.productResponse.count} TL"
89 | tvPrice.paintFlags = tvPrice.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
90 | } else {
91 | tvPrice.text = "${state.productResponse.price * state.productResponse.count} TL"
92 | tvDetailSalePrice.isVisible = false
93 | }
94 |
95 | }
96 | }
97 |
98 | is ProductDetailState.Error -> {
99 | detailProgressBar.visibility = View.GONE
100 | Snackbar.make(requireView(), state.throwable.message.orEmpty(), 1000).show()
101 | }
102 | }
103 | }
104 | }
105 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/detay/ProductDetailViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.detay
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import com.adilegungor.gungorecommerce.common.Resource
7 | import com.adilegungor.gungorecommerce.data.model.AddToCartRequest
8 | import com.adilegungor.gungorecommerce.data.model.ProductUI
9 | import com.adilegungor.gungorecommerce.data.repository.ProductRepository
10 | import com.adilegungor.gungorecommerce.ui.viewmodel.BaseViewModel
11 | import dagger.hilt.android.lifecycle.HiltViewModel
12 | import kotlinx.coroutines.launch
13 | import javax.inject.Inject
14 |
15 | @HiltViewModel
16 | class ProductDetailViewModel @Inject constructor(
17 | private val productRepository: ProductRepository, application: Application
18 | ): BaseViewModel(application) {
19 |
20 | private var _productDetailState = MutableLiveData()
21 | val productDetailState: LiveData
22 | get() = _productDetailState
23 |
24 | fun getProductsDetail(id: Int) {
25 | launch {
26 | _productDetailState.value = ProductDetailState.Loading
27 | val result = productRepository.getProductsDetail(id)
28 |
29 | when (result) {
30 | is Resource.Success -> {
31 | _productDetailState.value = ProductDetailState.Data(result.data)
32 | }
33 |
34 | is Resource.Error -> {
35 | _productDetailState.value = ProductDetailState.Error(result.throwable)
36 | }
37 | }
38 | }
39 | }
40 |
41 | fun addProductToCart(addToCartRequest: AddToCartRequest) {
42 | launch {
43 | productRepository.addProductToCart(addToCartRequest)
44 | }
45 | }
46 | }
47 |
48 | sealed interface ProductDetailState {
49 | object Loading: ProductDetailState
50 | data class Data(val productResponse: ProductUI): ProductDetailState
51 | data class Error(val throwable: Throwable): ProductDetailState
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/favori/FavoriteAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.favori
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.DiffUtil
6 | import androidx.recyclerview.widget.ListAdapter
7 | import androidx.recyclerview.widget.RecyclerView
8 | import com.adilegungor.gungorecommerce.common.loadImage
9 | import com.adilegungor.gungorecommerce.data.model.ProductUI
10 | import com.adilegungor.gungorecommerce.databinding.ItemFavoriteBinding
11 |
12 | class FavoriteAdapter(
13 | private val favProductListener: FavProductListener
14 | ) : ListAdapter(ProductDiffCallBack()) {
15 |
16 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavProductViewHolder =
17 | FavProductViewHolder(
18 | ItemFavoriteBinding.inflate(LayoutInflater.from(parent.context), parent, false),
19 | favProductListener
20 | )
21 |
22 | override fun onBindViewHolder(holder: FavProductViewHolder, position: Int) = holder.bind(getItem(position))
23 |
24 | class FavProductViewHolder(
25 | private val binding: ItemFavoriteBinding,
26 | private val favProductListener: FavProductListener
27 | ) : RecyclerView.ViewHolder(binding.root) {
28 |
29 | fun bind(product: ProductUI) = with(binding) {
30 | tvTitle.text = product.title
31 | tvPrice.text = "${product.price} ₺"
32 |
33 | ivProduct.loadImage(product.imageOne)
34 |
35 | root.setOnClickListener {
36 | favProductListener.onProductClick(product.id)
37 | }
38 |
39 | ivDelete.setOnClickListener {
40 | favProductListener.onDeleteClick(product)
41 | }
42 | }
43 | }
44 |
45 | class ProductDiffCallBack : DiffUtil.ItemCallback() {
46 | override fun areItemsTheSame(oldItem: ProductUI, newItem: ProductUI): Boolean {
47 | return oldItem.id == newItem.id
48 | }
49 |
50 | override fun areContentsTheSame(oldItem: ProductUI, newItem: ProductUI): Boolean {
51 | return oldItem == newItem
52 | }
53 | }
54 |
55 | interface FavProductListener {
56 | fun onProductClick(id: Int)
57 | fun onDeleteClick(product: ProductUI)
58 | }
59 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/favori/FavoriteFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.favori
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.activity.OnBackPressedCallback
6 | import androidx.fragment.app.Fragment
7 | import androidx.fragment.app.viewModels
8 | import androidx.navigation.fragment.findNavController
9 | import com.adilegungor.gungorecommerce.R
10 | import com.adilegungor.gungorecommerce.common.gone
11 | import com.adilegungor.gungorecommerce.common.viewBinding
12 | import com.adilegungor.gungorecommerce.common.visible
13 | import com.adilegungor.gungorecommerce.data.model.ProductUI
14 | import com.adilegungor.gungorecommerce.databinding.FragmentFavoriteBinding
15 | import dagger.hilt.android.AndroidEntryPoint
16 |
17 | @AndroidEntryPoint
18 | class FavoriteFragment : Fragment(R.layout.fragment_favorite), FavoriteAdapter.FavProductListener {
19 |
20 | private val binding by viewBinding(FragmentFavoriteBinding::bind)
21 |
22 | private val viewModel by viewModels()
23 |
24 | private val favAdapter by lazy { FavoriteAdapter(this) }
25 |
26 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
27 | super.onViewCreated(view, savedInstanceState)
28 |
29 | viewModel.getFavProducts()
30 |
31 | binding.rvFavorites.adapter = favAdapter
32 |
33 | observeData()
34 |
35 | val callback = object : OnBackPressedCallback(true) {
36 | override fun handleOnBackPressed() {
37 | val action = FavoriteFragmentDirections.actionFavoriteFragmentToHomeFragment()
38 | findNavController().navigate(action)
39 | }
40 | }
41 |
42 | requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)
43 |
44 |
45 | }
46 |
47 | private fun observeData() = with(binding) {
48 | viewModel.favState.observe(viewLifecycleOwner) { state ->
49 | when (state) {
50 | is FavState.Loading -> {
51 | progressBar.visible()
52 | }
53 |
54 | is FavState.Data -> {
55 | favAdapter.submitList(state.products)
56 | progressBar.gone()
57 | }
58 |
59 | is FavState.Error -> {
60 | progressBar.gone()
61 | }
62 | }
63 | }
64 | }
65 |
66 | override fun onProductClick(id: Int) {
67 | val action = FavoriteFragmentDirections.actionFavoriteFragmentToProductDetailFragment(id)
68 | findNavController().navigate(action)
69 | }
70 |
71 | override fun onDeleteClick(product: ProductUI) {
72 | viewModel.deleteProduct(product)
73 | }
74 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/favori/FavoriteViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.favori
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import com.adilegungor.gungorecommerce.common.Resource
7 | import com.adilegungor.gungorecommerce.data.model.ProductUI
8 | import com.adilegungor.gungorecommerce.data.repository.ProductRepository
9 | import com.adilegungor.gungorecommerce.ui.viewmodel.BaseViewModel
10 | import dagger.hilt.android.lifecycle.HiltViewModel
11 | import kotlinx.coroutines.launch
12 | import javax.inject.Inject
13 |
14 | @HiltViewModel
15 | class FavoriteViewModel @Inject constructor(
16 | private val productRepository: ProductRepository, application: Application
17 | ) : BaseViewModel(application) {
18 |
19 | private var _favState = MutableLiveData()
20 | val favState: LiveData
21 | get() = _favState
22 |
23 | fun getFavProducts() {
24 | launch {
25 | _favState.value = FavState.Loading
26 | when (val result = productRepository.getFavProducts()) {
27 | is Resource.Success -> {
28 | _favState.value = FavState.Data(result.data)
29 | }
30 |
31 | is Resource.Error -> {
32 | _favState.value = FavState.Error(result.throwable)
33 | }
34 | }
35 | }
36 | }
37 |
38 | fun deleteProduct(product: ProductUI) {
39 | launch {
40 | productRepository.deleteProductFromFav(product)
41 | }
42 | }
43 | }
44 |
45 | sealed interface FavState {
46 | object Loading : FavState
47 | data class Data(val products: List) : FavState
48 | data class Error(val throwable: Throwable) : FavState
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/giris/SignInFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.giris
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.navigation.fragment.findNavController
7 | import com.adilegungor.gungorecommerce.R
8 | import com.adilegungor.gungorecommerce.common.viewBinding
9 | import com.adilegungor.gungorecommerce.databinding.FragmentSignInBinding
10 | import com.google.android.material.bottomnavigation.BottomNavigationView
11 | import com.google.android.material.snackbar.Snackbar
12 | import com.google.firebase.auth.FirebaseAuth
13 | import dagger.hilt.android.AndroidEntryPoint
14 |
15 | @AndroidEntryPoint
16 | class SignInFragment : Fragment(R.layout.fragment_sign_in) {
17 |
18 | private val binding by viewBinding(FragmentSignInBinding::bind)
19 | private lateinit var auth: FirebaseAuth
20 | private var bottomNavigationView: BottomNavigationView? = null
21 |
22 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
23 | super.onViewCreated(view, savedInstanceState)
24 |
25 | auth = FirebaseAuth.getInstance()
26 |
27 | // Bottom Navigation Visibility
28 | bottomNavigationView = getActivity()?.findViewById(R.id.bottomNavigationView);
29 | bottomNavigationView?.setVisibility(View.GONE);
30 |
31 | with(binding) {
32 | tvDontHaveAnAccount.setOnClickListener {
33 | val action = SignInFragmentDirections.actionSignInFragmentToSignUpFragment()
34 | findNavController().navigate(action)
35 | }
36 |
37 | btnLogin.setOnClickListener {
38 | val email = etEmail.text.toString()
39 | val password = etPassword.text.toString()
40 |
41 | if (email.isNotEmpty() && password.isNotEmpty()) {
42 | signIn(email, password)
43 | } else {
44 | Snackbar.make(requireView(), "Boş alanları doldurunuz.", 1000).show()
45 | }
46 | }
47 | }
48 | }
49 |
50 | private fun signIn(email: String, password: String) {
51 | if (isValidEmail(email) && isValidPassword(password)) {
52 | auth.signInWithEmailAndPassword(email, password)
53 | .addOnSuccessListener {
54 | findNavController().navigate(R.id.signInFragmentToHomeFragment)
55 | }
56 | .addOnFailureListener {
57 | Snackbar.make(requireView(), it.message.orEmpty(), 1000).show()
58 | }
59 | } else {
60 | Snackbar.make(requireView(), "Geçersiz mail veya şifre", Snackbar.LENGTH_SHORT).show()
61 | }
62 | }
63 |
64 | private fun isValidEmail(email: String): Boolean {
65 | val emailPattern = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+"
66 | return email.matches(emailPattern.toRegex())
67 | }
68 |
69 | private fun isValidPassword(password: String): Boolean {
70 | return password.length >= 6
71 | }
72 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/kayit/SignUpFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.kayit
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.navigation.fragment.findNavController
7 | import com.adilegungor.gungorecommerce.R
8 | import com.adilegungor.gungorecommerce.common.viewBinding
9 | import com.adilegungor.gungorecommerce.databinding.FragmentSignUpBinding
10 | import com.google.android.material.bottomnavigation.BottomNavigationView
11 | import com.google.android.material.snackbar.Snackbar
12 | import com.google.firebase.auth.FirebaseAuth
13 | import com.google.firebase.auth.ktx.auth
14 | import com.google.firebase.ktx.Firebase
15 | import dagger.hilt.android.AndroidEntryPoint
16 |
17 | @AndroidEntryPoint
18 | class SignUpFragment : Fragment(R.layout.fragment_sign_up) {
19 |
20 | private val binding by viewBinding(FragmentSignUpBinding::bind)
21 | private lateinit var auth: FirebaseAuth
22 | private var bottomNavigationView: BottomNavigationView? = null
23 |
24 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
25 | super.onViewCreated(view, savedInstanceState)
26 |
27 | auth = Firebase.auth
28 |
29 | auth.currentUser?.let {
30 | findNavController().navigate(R.id.signUpFragmenttohomeFragment)
31 | }
32 |
33 | // Bottom Navigation Visibility
34 | bottomNavigationView = getActivity()?.findViewById(R.id.bottomNavigationView);
35 | bottomNavigationView?.setVisibility(View.GONE);
36 |
37 | with(binding) {
38 | btnSignup.setOnClickListener {
39 | val email = etEmail.text.toString()
40 | val password = etPassword.text.toString()
41 |
42 | if (email.isNotEmpty() && password.isNotEmpty()) {
43 | signUp(email, password)
44 | } else {
45 | Snackbar.make(requireView(), "Boşlukları doldurunuz", 1000).show()
46 | }
47 | }
48 |
49 | tvHaveAnAccount.setOnClickListener {
50 | val action = SignUpFragmentDirections.actionSignUpFragmentToSignInFragment()
51 | findNavController().navigate(action)
52 | }
53 | }
54 | }
55 |
56 | private fun signUp(email: String, password: String) {
57 | if (isValidEmail(email) && isValidPassword(password)) {
58 | auth.createUserWithEmailAndPassword(email, password)
59 | .addOnSuccessListener {
60 | findNavController().navigate(R.id.signUpFragmenttohomeFragment)
61 | }
62 | .addOnFailureListener {
63 | Snackbar.make(requireView(), it.message.orEmpty(), 1000).show()
64 | }
65 | } else {
66 | Snackbar.make(requireView(), "Geçersiz mail veya şifre", Snackbar.LENGTH_SHORT).show()
67 | }
68 | }
69 |
70 | private fun isValidEmail(email: String): Boolean {
71 | val emailPattern = "[a-zA-Z0-9._-]+@[a-z]+\\.+[a-z]+"
72 | return email.matches(emailPattern.toRegex())
73 | }
74 |
75 | private fun isValidPassword(password: String): Boolean {
76 | return password.length >= 6
77 | }
78 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/odeme/PaymentFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.odeme
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.navigation.fragment.findNavController
7 | import com.adilegungor.gungorecommerce.R
8 | import com.adilegungor.gungorecommerce.common.viewBinding
9 | import com.adilegungor.gungorecommerce.databinding.FragmentPaymentBinding
10 | import com.google.android.material.bottomnavigation.BottomNavigationView
11 | import com.google.android.material.snackbar.Snackbar
12 |
13 | class PaymentFragment : Fragment(R.layout.fragment_payment) {
14 |
15 | private val binding by viewBinding(FragmentPaymentBinding::bind)
16 | private var bottomNavigationView: BottomNavigationView? = null
17 |
18 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
19 | super.onViewCreated(view, savedInstanceState)
20 |
21 | // Bottom Navigation Visibility
22 | bottomNavigationView = getActivity()?.findViewById(R.id.bottomNavigationView);
23 | bottomNavigationView?.setVisibility(View.GONE);
24 |
25 | with(binding) {
26 | btnPay.setOnClickListener {
27 | val address = etAddress.text.toString()
28 | val name = etNameSurname.text.toString()
29 | val cardNumber = etCardNumber.text.toString()
30 | val cardDate = etCardDate.text.toString()
31 | val cvc = etCvc.text.toString()
32 |
33 | if (cardNumber.length == 16 && cardDate.isNotEmpty() && cvc.isNotEmpty() && address.isNotEmpty() && name.isNotEmpty()) {
34 | findNavController().navigate(PaymentFragmentDirections.actionPaymentFragmentToResultFragment())
35 | } else {
36 | Snackbar.make(requireView(), "Tüm boşluklar doldurulmalı ve kart numaranız en az 16 karakter içermelidir", Snackbar.LENGTH_SHORT).show()
37 | }
38 | }
39 |
40 | }
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/odeme/ResultFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.odeme
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.navigation.fragment.findNavController
7 | import com.adilegungor.gungorecommerce.R
8 | import com.adilegungor.gungorecommerce.common.viewBinding
9 | import com.adilegungor.gungorecommerce.databinding.FragmentResultBinding
10 | import com.google.android.material.bottomnavigation.BottomNavigationView
11 |
12 | class ResultFragment : Fragment(R.layout.fragment_result) {
13 |
14 | private val binding by viewBinding(FragmentResultBinding::bind)
15 | private var bottomNavigationView: BottomNavigationView? = null
16 |
17 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
18 | super.onViewCreated(view, savedInstanceState)
19 |
20 | // Bottom Navigation Visibility
21 | bottomNavigationView = getActivity()?.findViewById(R.id.bottomNavigationView);
22 | bottomNavigationView?.setVisibility(View.GONE);
23 |
24 | val gifImg = pl.droidsonroids.gif.GifDrawable(resources, R.drawable.cargo)
25 |
26 | with(binding) {
27 | ivCargo.setImageDrawable(gifImg)
28 |
29 | btnHome.setOnClickListener {
30 | findNavController().navigate(ResultFragmentDirections.actionResultFragmentToHomeFragment())
31 | }
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/profil/ProfileFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.profil
2 |
3 | import android.content.Context
4 | import android.content.SharedPreferences
5 | import android.os.Bundle
6 | import android.view.View
7 | import androidx.fragment.app.Fragment
8 | import androidx.fragment.app.viewModels
9 | import com.adilegungor.gungorecommerce.R
10 | import com.adilegungor.gungorecommerce.common.viewBinding
11 | import com.adilegungor.gungorecommerce.databinding.FragmentProfileBinding
12 | import com.google.android.material.bottomnavigation.BottomNavigationView
13 | import com.google.firebase.auth.FirebaseAuth
14 | import com.google.firebase.auth.ktx.auth
15 | import com.google.firebase.ktx.Firebase
16 | import androidx.navigation.fragment.findNavController
17 | import dagger.hilt.android.AndroidEntryPoint
18 |
19 | @AndroidEntryPoint
20 | class ProfileFragment : Fragment(R.layout.fragment_profile) {
21 |
22 | private val binding by viewBinding(FragmentProfileBinding::bind)
23 | private lateinit var auth: FirebaseAuth
24 | private var bottomNavigationView: BottomNavigationView? = null
25 | private val viewModel by viewModels()
26 |
27 | private val sharedPreferencesName = "MyPreferences"
28 | private val keyGender = "userGender"
29 | private val keyAvatar = "userAvatar"
30 | private lateinit var sharedPreferences: SharedPreferences
31 |
32 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
33 | super.onViewCreated(view, savedInstanceState)
34 |
35 | sharedPreferences = requireContext().getSharedPreferences(sharedPreferencesName, Context.MODE_PRIVATE)
36 |
37 |
38 | // Bottom Navigation Visibility
39 | bottomNavigationView = getActivity()?.findViewById(R.id.bottomNavigationView);
40 | bottomNavigationView?.setVisibility(View.GONE);
41 |
42 | auth = Firebase.auth
43 |
44 | with(binding) {
45 |
46 | // Verileri SharedPreferences'ten yükle
47 | val savedGender = sharedPreferences.getString(keyGender, null)
48 | val savedAvatarResource = sharedPreferences.getInt(keyAvatar, R.drawable.avatargirl)
49 |
50 | if (savedGender != null) {
51 | if (savedGender == "boy") {
52 | rbBoy.isChecked = true
53 | } else if (savedGender == "girl") {
54 | rbGirl.isChecked = true
55 | }
56 |
57 | ivProfile.setImageResource(savedAvatarResource)
58 | }
59 |
60 | radioGroup.setOnCheckedChangeListener { group, checkedId ->
61 |
62 | when (checkedId) {
63 | R.id.rb_boy -> {
64 | ivProfile.setImageResource(R.drawable.avatarboy)
65 | saveAvatarAndGender(R.drawable.avatarboy, "boy")
66 | }
67 | R.id.rb_girl -> {
68 | ivProfile.setImageResource(R.drawable.avatargirl)
69 | saveAvatarAndGender(R.drawable.avatargirl, "girl")
70 | }
71 | }
72 | }
73 |
74 | tvEmail.text = auth.currentUser?.email.toString()
75 |
76 | tvProfileFavorites.setOnClickListener {
77 | findNavController().navigate(ProfileFragmentDirections.actionProfileFragmentToFavoriteFragment())
78 | }
79 |
80 | tvProfileCart.setOnClickListener {
81 | findNavController().navigate(ProfileFragmentDirections.actionProfileFragmentToCartFragment())
82 | }
83 |
84 | btnSignOut.setOnClickListener {
85 | auth.signOut()
86 | findNavController().navigate(ProfileFragmentDirections.actionProfileFragmentToSignInFragment())
87 | }
88 |
89 | // Observe LiveData for selected gender
90 | viewModel.selectedGender.observe(viewLifecycleOwner) { gender ->
91 | when (gender) {
92 | "boy" -> {
93 | binding.rbBoy.isChecked = true
94 | }
95 |
96 | "girl" -> {
97 | binding.rbGirl.isChecked = true
98 | }
99 | }
100 | }
101 |
102 | // Observe LiveData for avatar resource
103 | viewModel.avatarResource.observe(viewLifecycleOwner) { avatarResource ->
104 | binding.ivProfile.setImageResource(avatarResource)
105 | }
106 | }
107 | }
108 |
109 | // Save gender to shared preferences
110 | fun saveGender(gender: String) {
111 | val editor = sharedPreferences.edit()
112 | editor.putString(keyGender, gender)
113 | editor.apply()
114 | }
115 |
116 | private fun saveAvatar(avatarResource: Int) {
117 | val editor = sharedPreferences.edit()
118 | editor.putInt(keyAvatar, avatarResource)
119 | editor.apply()
120 | }
121 |
122 | private fun saveAvatarAndGender(avatarResource: Int, gender: String) {
123 | viewModel.updateAvatar(avatarResource, gender)
124 | saveAvatar(avatarResource)
125 | saveGender(gender)
126 | }
127 |
128 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/profil/ProfileViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.profil
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import com.adilegungor.gungorecommerce.R
7 |
8 | class ProfileViewModel : ViewModel() {
9 |
10 | // LiveData for avatar resource ID
11 | private val _avatarResource = MutableLiveData()
12 | val avatarResource: LiveData
13 | get() = _avatarResource
14 |
15 | // LiveData for selected gender
16 | private val _selectedGender = MutableLiveData()
17 | val selectedGender: LiveData
18 | get() = _selectedGender
19 |
20 | // Initialize ViewModel with default values
21 | init {
22 | // Initialize LiveData with default values here
23 | _avatarResource.value = R.drawable.avatargirl
24 | _selectedGender.value = "girl"
25 | }
26 |
27 | // Update avatar resource and selected gender
28 | fun updateAvatar(avatarResource: Int, gender: String) {
29 | _avatarResource.value = avatarResource
30 | _selectedGender.value = gender
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/sepet/CartFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.sepet
2 |
3 | import android.content.Context
4 | import android.content.SharedPreferences
5 | import android.os.Bundle
6 | import android.view.View
7 | import androidx.activity.OnBackPressedCallback
8 | import androidx.core.view.isVisible
9 | import androidx.fragment.app.Fragment
10 | import androidx.fragment.app.viewModels
11 | import androidx.navigation.fragment.findNavController
12 | import com.adilegungor.gungorecommerce.R
13 | import com.adilegungor.gungorecommerce.common.gone
14 | import com.adilegungor.gungorecommerce.common.viewBinding
15 | import com.adilegungor.gungorecommerce.common.visible
16 | import com.adilegungor.gungorecommerce.data.model.ClearCartRequest
17 | import com.adilegungor.gungorecommerce.data.model.DeleteFromCartRequest
18 | import com.adilegungor.gungorecommerce.databinding.FragmentCartBinding
19 | import com.google.firebase.auth.FirebaseAuth
20 | import com.google.firebase.auth.ktx.auth
21 | import com.google.firebase.ktx.Firebase
22 | import dagger.hilt.android.AndroidEntryPoint
23 |
24 | @AndroidEntryPoint
25 | class CartFragment : Fragment(R.layout.fragment_cart), CartProductsAdapter.CartProductListener {
26 |
27 | private val binding by viewBinding(FragmentCartBinding::bind)
28 |
29 | private val viewModel by viewModels()
30 |
31 | private lateinit var sharedPreferences: SharedPreferences
32 |
33 | private lateinit var cartProductsAdapter: CartProductsAdapter
34 |
35 | private lateinit var auth: FirebaseAuth
36 |
37 | private lateinit var userId: String
38 |
39 | private var totalAmount = 0.0
40 |
41 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
42 | super.onViewCreated(view, savedInstanceState)
43 | auth = Firebase.auth
44 | userId = auth.currentUser!!.uid
45 | val request = ClearCartRequest(userId)
46 |
47 | sharedPreferences = requireContext().getSharedPreferences("UserPrefs", Context.MODE_PRIVATE)
48 | cartProductsAdapter = CartProductsAdapter(this, sharedPreferences)
49 |
50 | val callback = object : OnBackPressedCallback(true) {
51 | override fun handleOnBackPressed() {
52 | val action = CartFragmentDirections.actionCartFragmentToHomeFragment()
53 | findNavController().navigate(action)
54 | }
55 | }
56 |
57 | requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)
58 |
59 | viewModel.getCartProducts(userId)
60 |
61 | with (binding) {
62 | rvCartProducts.adapter = cartProductsAdapter
63 |
64 | btnClear.setOnClickListener {
65 | viewModel.clearProduct(request,userId)
66 |
67 | totalAmount = 0.0
68 |
69 | val editor = sharedPreferences.edit()
70 | for (product in cartProductsAdapter.currentList) {
71 | editor.putInt("count_key_${product.id}", 0)
72 | }
73 | editor.apply()
74 | }
75 |
76 | btnBuy.setOnClickListener {
77 | findNavController().navigate(CartFragmentDirections.actionCartFragmentToPaymentFragment())
78 | }
79 | }
80 |
81 | observeData()
82 | }
83 |
84 | private fun observeData() = with(binding) {
85 | viewModel.cartState.observe(viewLifecycleOwner) { state ->
86 | when (state) {
87 | is CartState.Loading -> {
88 | progressBar.visible()
89 | }
90 |
91 | is CartState.Data -> {
92 | cartProductsAdapter.submitList(state.products)
93 | rvCartProducts.isVisible = state.products.isNotEmpty()
94 | progressBar.gone()
95 |
96 | if (state.products.isEmpty()) {
97 | rvCartProducts.visibility = View.GONE
98 | tvTotal.visibility = View.GONE
99 | tvAmount.visibility = View.GONE
100 | btnClear.visibility = View.GONE
101 | btnBuy.visibility = View.GONE
102 |
103 | tvError.visibility = View.VISIBLE
104 | tvError.setText("Sepetinizde hiç ürün yok!")
105 | } else {
106 | rvCartProducts.visibility = View.VISIBLE
107 | tvTotal.visibility = View.VISIBLE
108 | tvAmount.visibility = View.VISIBLE
109 | btnClear.visibility = View.VISIBLE
110 | btnBuy.visibility = View.VISIBLE
111 | tvError.visibility = View.GONE
112 |
113 | }
114 |
115 | }
116 |
117 | is CartState.Error -> {
118 | progressBar.gone()
119 | }
120 | }
121 | }
122 |
123 | viewModel.totalAmount.observe(viewLifecycleOwner) {
124 | tvTotal.text = "${it} ₺"
125 | }
126 | }
127 |
128 | override fun onProductClick(id: Int) {
129 | val action = CartFragmentDirections.actionCartFragmentToProductDetailFragment(id)
130 | findNavController().navigate(action)
131 | }
132 |
133 | override fun onDeleteClick(id: Int, price: Double) {
134 | val request = DeleteFromCartRequest(id)
135 | viewModel.deleteProduct(request, price)
136 | viewModel.getCartProducts(userId)
137 | }
138 |
139 | override fun onIncreaseClick(price: Double) {
140 | viewModel.onIncreaseClick(price)
141 | }
142 |
143 | override fun onDecreaseClick(price: Double) {
144 | viewModel.onDecreaseClick(price)
145 | }
146 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/sepet/CartProductsAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.sepet
2 |
3 | import android.content.SharedPreferences
4 | import android.provider.Settings.Global.getString
5 | import android.view.LayoutInflater
6 | import android.view.ViewGroup
7 | import androidx.lifecycle.LiveData
8 | import androidx.lifecycle.MutableLiveData
9 | import androidx.recyclerview.widget.DiffUtil
10 | import androidx.recyclerview.widget.ListAdapter
11 | import androidx.recyclerview.widget.RecyclerView
12 | import com.adilegungor.gungorecommerce.R
13 | import kotlinx.coroutines.launch
14 | import com.adilegungor.gungorecommerce.common.loadImage
15 | import com.adilegungor.gungorecommerce.data.model.ProductUI
16 | import com.adilegungor.gungorecommerce.databinding.ItemCartProductBinding
17 |
18 | class CartProductsAdapter(
19 | private val cartProductListener: CartProductListener,
20 | private val sharedPreferences: SharedPreferences
21 | ) : ListAdapter(ProductDiffCallBack()) {
22 |
23 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartProductViewHolder =
24 | CartProductViewHolder(
25 | ItemCartProductBinding.inflate(LayoutInflater.from(parent.context), parent, false),
26 | cartProductListener
27 | )
28 |
29 | override fun onBindViewHolder(holder: CartProductViewHolder, position: Int) = holder.bind(getItem(position))
30 |
31 | inner class CartProductViewHolder(
32 | private val binding: ItemCartProductBinding,
33 | private val cartProductListener: CartProductListener
34 | ) : RecyclerView.ViewHolder(binding.root) {
35 |
36 | private var currentCount = 1
37 | private lateinit var sharedPreferencesKey: String
38 |
39 | fun bind(product: ProductUI) = with(binding) {
40 | tvTitle.text = product.title
41 | tvPrice.text = "${product.price} ₺"
42 |
43 | ivProduct.loadImage(product.imageOne)
44 |
45 | sharedPreferencesKey = "count_key_${product.id}"
46 |
47 | currentCount = sharedPreferences.getInt(sharedPreferencesKey, 1)
48 | tvCount.text = currentCount.toString()
49 |
50 | root.setOnClickListener {
51 | cartProductListener.onProductClick(product.id)
52 | }
53 |
54 |
55 |
56 |
57 | btnAdd.setOnClickListener {
58 | if (currentCount == product.count) {
59 | tvCount.text = currentCount.toString()
60 | cartProductListener.onIncreaseClick(product.price)
61 | } else {
62 | currentCount += 1
63 |
64 | tvCount.text = currentCount.toString()
65 | val editor = sharedPreferences.edit()
66 | editor.putInt(sharedPreferencesKey, currentCount)
67 | editor.apply()
68 | }
69 | }
70 |
71 | btnMinus.setOnClickListener {
72 | if (currentCount >= 1) {
73 | currentCount -= 1
74 | cartProductListener.onDecreaseClick(product.price)
75 | } else {
76 | cartProductListener.onDeleteClick(product.id, product.price)
77 | }
78 |
79 | tvCount.text = currentCount.toString()
80 |
81 | val editor = sharedPreferences.edit()
82 | editor.putInt(sharedPreferencesKey, currentCount)
83 | editor.apply()
84 | }
85 |
86 | ivDelete.setOnClickListener {
87 | cartProductListener.onDeleteClick(product.id, product.price)
88 | currentCount = 0
89 | val editor = sharedPreferences.edit()
90 | editor.putInt(sharedPreferencesKey, currentCount+1)
91 | editor.apply()
92 | tvCount.text = currentCount.toString()
93 | }
94 | }
95 | }
96 |
97 | class ProductDiffCallBack : DiffUtil.ItemCallback() {
98 | override fun areItemsTheSame(oldItem: ProductUI, newItem: ProductUI): Boolean {
99 | return oldItem.id == newItem.id
100 | }
101 |
102 | override fun areContentsTheSame(oldItem: ProductUI, newItem: ProductUI): Boolean {
103 | return oldItem == newItem
104 | }
105 | }
106 |
107 | interface CartProductListener {
108 | fun onProductClick(id: Int)
109 | fun onDeleteClick(id: Int, price: Double)
110 | fun onIncreaseClick(price: Double)
111 | fun onDecreaseClick(price: Double)
112 | }
113 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/sepet/CartViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.sepet
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import com.adilegungor.gungorecommerce.common.Resource
7 | import com.adilegungor.gungorecommerce.data.model.ClearCartRequest
8 | import com.adilegungor.gungorecommerce.data.model.DeleteFromCartRequest
9 | import com.adilegungor.gungorecommerce.data.model.ProductUI
10 | import com.adilegungor.gungorecommerce.data.repository.ProductRepository
11 | import com.adilegungor.gungorecommerce.ui.viewmodel.BaseViewModel
12 | import dagger.hilt.android.lifecycle.HiltViewModel
13 | import kotlinx.coroutines.launch
14 | import javax.inject.Inject
15 |
16 | @HiltViewModel
17 | class CartViewModel @Inject constructor(
18 | private val productRepository: ProductRepository, application: Application
19 | ) : BaseViewModel(application) {
20 |
21 | private var _cartState = MutableLiveData()
22 | val cartState: LiveData
23 | get() = _cartState
24 |
25 | private var _totalAmount = MutableLiveData()
26 | val totalAmount: LiveData
27 | get() = _totalAmount
28 |
29 |
30 |
31 |
32 | fun getCartProducts(userId: String) {
33 | launch {
34 | _cartState.value = CartState.Loading
35 | when (val result = productRepository.getCartProduct(userId)) {
36 | is Resource.Success -> {
37 | _cartState.value = CartState.Data(result.data)
38 | _totalAmount.value = result.data.sumOf { it.price }
39 | }
40 |
41 | is Resource.Error -> {
42 | _cartState.value = CartState.Error(result.throwable)
43 | }
44 | }
45 | }
46 | }
47 |
48 | fun deleteProduct(request: DeleteFromCartRequest, price: Double) {
49 | launch {
50 | productRepository.deleteProductFromCart(request)
51 | _totalAmount.value = _totalAmount.value?.minus(price)
52 | }
53 | }
54 |
55 | fun clearProduct(request: ClearCartRequest, userId: String) {
56 | launch {
57 | when (val result = productRepository.clearProductFromCart(request)) {
58 | is Resource.Success -> {
59 | getCartProducts(userId)
60 | _totalAmount.value = 0.0
61 | }
62 |
63 | is Resource.Error -> {
64 | _cartState.value = CartState.Error(result.throwable)
65 | }
66 | }
67 | }
68 | }
69 |
70 | fun onIncreaseClick(price: Double) {
71 | _totalAmount.value = _totalAmount.value?.plus(price)
72 | }
73 |
74 | fun onDecreaseClick(price: Double) {
75 | _totalAmount.value = _totalAmount.value?.minus(price)
76 | }
77 | }
78 |
79 | sealed interface CartState {
80 | object Loading : CartState
81 | data class Data(val products: List) : CartState
82 | data class Error(val throwable: Throwable) : CartState
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/splash/SplashFragment.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.splash
2 |
3 | import android.content.res.Configuration
4 | import android.graphics.Color
5 | import android.os.Build
6 | import android.os.Bundle
7 | import android.os.Handler
8 | import android.os.Looper
9 | import android.view.LayoutInflater
10 | import android.view.View
11 | import android.view.ViewGroup
12 | import androidx.fragment.app.Fragment
13 | import androidx.navigation.fragment.findNavController
14 | import com.adilegungor.gungorecommerce.R
15 | import com.adilegungor.gungorecommerce.databinding.FragmentSplashBinding
16 | import com.google.android.material.bottomnavigation.BottomNavigationView
17 | import com.google.firebase.auth.FirebaseAuth
18 | import com.google.firebase.auth.ktx.auth
19 | import com.google.firebase.ktx.Firebase
20 | import dagger.hilt.android.AndroidEntryPoint
21 |
22 | @AndroidEntryPoint
23 | class SplashFragment : Fragment() {
24 |
25 | private var _binding: FragmentSplashBinding? = null
26 | private val binding get() = _binding!!
27 | private lateinit var auth: FirebaseAuth
28 | private var bottomNavigationView: BottomNavigationView? = null
29 |
30 | override fun onCreateView(
31 | inflater: LayoutInflater, container: ViewGroup?,
32 | savedInstanceState: Bundle?
33 | ): View? {
34 | // Inflate the layout for this fragment
35 | _binding = FragmentSplashBinding.inflate(inflater, container, false)
36 | auth = Firebase.auth
37 |
38 | // Bottom Navigation Visibility
39 | bottomNavigationView = getActivity()?.findViewById(R.id.bottomNavigationView);
40 | bottomNavigationView?.setVisibility(View.GONE);
41 |
42 | //Status Bar
43 | val window = requireActivity().window
44 |
45 | // Before Android 6.0 Marshmallow
46 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
47 | // Status bar will be white
48 | window.statusBarColor = Color.WHITE
49 | } else {
50 | if (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_NO) {
51 | // Light mode
52 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
53 | window.statusBarColor = Color.WHITE
54 | } else {
55 | // Dark mode
56 | window.decorView.systemUiVisibility = 0
57 | window.statusBarColor = Color.BLACK
58 | }
59 | }
60 |
61 | return binding.root
62 | }
63 |
64 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
65 | super.onViewCreated(view, savedInstanceState)
66 |
67 | auth = FirebaseAuth.getInstance()
68 | val currentUser = auth.currentUser
69 |
70 | Handler(Looper.getMainLooper()).postDelayed({
71 | if (currentUser != null) {
72 | // If user is logged in, redirect to Home screen.
73 | findNavController().navigate(R.id.action_splashFragment_to_homeFragment)
74 | } else {
75 | // If the user is not logged in, redirect them to the SignIn screen.
76 | findNavController().navigate(R.id.action_splashFragment_to_signInFragment)
77 | }
78 | }, SPLASH_TIME_OUT)
79 | }
80 |
81 | companion object {
82 | private const val SPLASH_TIME_OUT: Long = 3000
83 | }
84 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/adilegungor/gungorecommerce/ui/viewmodel/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce.ui.viewmodel
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.AndroidViewModel
5 | import kotlinx.coroutines.CoroutineScope
6 | import kotlinx.coroutines.Dispatchers
7 | import kotlinx.coroutines.Job
8 | import kotlin.coroutines.CoroutineContext
9 |
10 | abstract class BaseViewModel(application: Application) : AndroidViewModel(application),
11 | CoroutineScope {
12 |
13 | private val job = Job()
14 |
15 | override val coroutineContext: CoroutineContext
16 | get() = job + Dispatchers.Main
17 |
18 | override fun onCleared() {
19 | super.onCleared()
20 | job.cancel()
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/avatarboy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/drawable/avatarboy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/avatargirl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/drawable/avatargirl.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/back.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/drawable/back.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/backg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/drawable/backg.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_add_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_add_circle_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_arrow_circle_left_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_delete_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_favorite_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_home_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_indeterminate_check_box_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_keyboard_double_arrow_left_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_person_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_shopping_cart_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_youtube_searched_for_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_rectangle.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cargo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/drawable/cargo.gif
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cartt_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/cartt_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/drawable/file.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_calendar.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_card.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cart.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_error.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite_white.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_home.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_lock.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_payment.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_profile.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/splas.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/drawable/splas.jpg
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_cart.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
23 |
24 |
36 |
37 |
51 |
52 |
62 |
63 |
75 |
76 |
91 |
92 |
101 |
102 |
117 |
118 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_favorite.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
23 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_profile.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
31 |
32 |
41 |
42 |
51 |
52 |
61 |
62 |
63 |
64 |
77 |
78 |
91 |
92 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_result.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
23 |
24 |
45 |
46 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
23 |
24 |
36 |
37 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_sign_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
27 |
28 |
34 |
35 |
36 |
55 |
56 |
57 |
64 |
65 |
66 |
83 |
84 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_sign_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
28 |
29 |
34 |
35 |
36 |
55 |
56 |
57 |
63 |
64 |
65 |
83 |
84 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_cart_product.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
27 |
28 |
44 |
45 |
57 |
58 |
66 |
67 |
68 |
79 |
80 |
91 |
92 |
101 |
102 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_favorite.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
24 |
25 |
41 |
42 |
54 |
55 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_product.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
25 |
26 |
35 |
36 |
52 |
53 |
68 |
69 |
79 |
80 |
90 |
91 |
107 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_sales_product.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
25 |
26 |
35 |
36 |
52 |
53 |
63 |
64 |
74 |
75 |
87 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
24 |
25 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/cartt.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/cartt_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.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/mipmap-hdpi/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-hdpi/app_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/app_icond.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-hdpi/app_icond.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/app_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-hdpi/app_icons.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/cartt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-hdpi/cartt.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/cartt_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-hdpi/cartt_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/cartt_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-hdpi/cartt_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/iconagapp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-hdpi/iconagapp.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-mdpi/app_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/app_icond.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-mdpi/app_icond.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/app_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-mdpi/app_icons.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/cartt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-mdpi/cartt.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/cartt_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-mdpi/cartt_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/cartt_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-mdpi/cartt_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/iconagapp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-mdpi/iconagapp.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xhdpi/app_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/app_icond.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xhdpi/app_icond.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/app_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xhdpi/app_icons.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/cartt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xhdpi/cartt.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/cartt_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xhdpi/cartt_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/cartt_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xhdpi/cartt_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/iconagapp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xhdpi/iconagapp.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxhdpi/app_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/app_icond.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxhdpi/app_icond.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/app_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxhdpi/app_icons.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/cartt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxhdpi/cartt.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/cartt_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxhdpi/cartt_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/cartt_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxhdpi/cartt_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/iconagapp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxhdpi/iconagapp.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/app_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxxhdpi/app_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/app_icond.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxxhdpi/app_icond.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/app_icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxxhdpi/app_icons.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/cartt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxxhdpi/cartt.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/cartt_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxxhdpi/cartt_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/cartt_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxxhdpi/cartt_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/iconagapp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/app/src/main/res/mipmap-xxxhdpi/iconagapp.png
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
16 |
21 |
22 |
26 |
29 |
33 |
34 |
38 |
41 |
46 |
47 |
51 |
56 |
59 |
60 |
64 |
67 |
68 |
72 |
77 |
80 |
83 |
84 |
88 |
91 |
94 |
95 |
99 |
104 |
107 |
108 |
112 |
115 |
120 |
123 |
124 |
128 |
131 |
132 |
136 |
139 |
140 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF000000
4 | #FFFFFFFF
5 | #83E120
6 | #F3EBFF
7 | #ffc93c
8 | #E64918
9 | #33123C
10 | #11142B
11 | #ffe3b0
12 | #070C29
13 | #eb2632
14 | #66bfbf
15 | #FFD003
16 | #0D1233
17 | #0B011E
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | GİRİŞ
3 | KAYIT
4 | Hesabın var mı? KAYDOL
5 | Zaten hesabım var, GİRİŞ YAP
6 | Selamlar
7 | Şifre
8 | Email
9 | İNDİRİMLER!
10 | TÜM ÜRÜNLER
11 | notebook
12 | monitor
13 | Tümü
14 | FAVORİLER
15 | FAVORİLER
16 | SEPET
17 | ÖDEME BİLGİLERİ
18 | SEPET
19 | ARAMA
20 | ANASAYFA
21 | FAVORİLERİM
22 | Kullanıcı Adı
23 | ÇIKIŞ
24 | Erkek
25 | Kadın
26 | Adres
27 | TÜMÜNÜ SİL
28 | Toplam Tutar
29 | Kart Üzerindeki İsim ve Soyisim
30 | Kart Numaranız
31 | Ay / Yıl
32 | CVC
33 | Ödeme
34 | Alışverişe devam ediniz.
35 | Siparişiniz alındı !
36 | Satın Al
37 | Mağazanız
38 | Konsol
39 | Desktop
40 | Kulaklık
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/test/java/com/adilegungor/gungorecommerce/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.adilegungor.gungorecommerce
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | dependencies {
3 | classpath 'com.google.gms:google-services:4.3.14'
4 | }
5 | }
6 |
7 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
8 | plugins {
9 | id 'com.android.application' version '8.0.2' apply false
10 | id 'com.android.library' version '8.0.2' apply false
11 | id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
12 | id 'androidx.navigation.safeargs.kotlin' version '2.5.2' apply false
13 | id 'com.google.dagger.hilt.android' version "2.44" apply false
14 | id("com.google.gms.google-services") version "4.3.14" apply false
15 | }
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Adl1coder/GungorEcommerce/c1b4fdc795510031dad544d970e179709f9d8182/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Sep 28 15:49:39 TRT 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | maven { url "https://jitpack.io" }
14 | }
15 | }
16 | rootProject.name = "GungorECommerce"
17 | include ':app'
18 |
--------------------------------------------------------------------------------