diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml
new file mode 100644
index 0000000..371f2e2
--- /dev/null
+++ b/.idea/appInsightsSettings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/other.xml b/.idea/other.xml
index 49481ad..dba9935 100644
--- a/.idea/other.xml
+++ b/.idea/other.xml
@@ -14,6 +14,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -113,6 +124,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -135,6 +157,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -168,6 +212,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -223,6 +278,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -262,7 +328,7 @@
-
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 6a36f55..3983e2a 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,6 +1,10 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
+ id("kotlin-kapt")
+ id ("androidx.navigation.safeargs")
+ id("kotlin-parcelize")
+// id("com.google.dagger.hilt.android")
}
android {
@@ -9,7 +13,7 @@ android {
defaultConfig {
applicationId = "com.alya.ecommerce_serang"
- minSdk = 24
+ minSdk = 21
targetSdk = 34
versionCode = 1
versionName = "1.0"
@@ -19,21 +23,26 @@ android {
buildTypes {
release {
+ buildConfigField("String", "BASE_URL", "\"http://192.168.1.13:3000/\"")
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
+ debug {
+ buildConfigField("String", "BASE_URL", "\"http://192.168.1.13:3000/\"")
+ }
}
compileOptions {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
- jvmTarget = "1.8"
+ jvmTarget = "11"
}
buildFeatures {
+ buildConfig = true
viewBinding = true
}
}
@@ -45,7 +54,34 @@ dependencies {
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
+ implementation(libs.androidx.legacy.support.v4)
+ implementation(libs.androidx.lifecycle.livedata.ktx)
+ implementation(libs.androidx.lifecycle.viewmodel.ktx)
+ implementation(libs.androidx.fragment.ktx)
+ implementation(libs.androidx.navigation.fragment.ktx)
+ implementation(libs.androidx.navigation.ui.ktx)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
-}
\ No newline at end of file
+
+ //retrofit
+ implementation("com.squareup.retrofit2:retrofit:2.9.0")
+ implementation("com.squareup.retrofit2:converter-gson:2.9.0")
+ implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
+
+
+
+// implementation("com.github.zhpanvip:viewpagerindicator:1.2.3")
+ implementation("com.github.bumptech.glide:glide:4.16.0")
+ implementation("androidx.paging:paging-runtime:3.2.1")
+ implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
+
+
+// implementation(libs.hilt.android)
+// kapt("com.google.dagger:hilt-compiler:2.48")
+//
+// // For ViewModel injection (if needed)
+// implementation(libs.androidx.hilt.lifecycle.viewmodel)
+// kapt("androidx.hilt:hilt-compiler:1.0.0")
+}
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1cac3c4..8a7221b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,8 @@
+
+
+ tools:targetApi="31"
+ android:usesCleartextTraffic="true"
+ android:networkSecurityConfig="@xml/network_security_config">
diff --git a/app/src/main/java/com/alya/ecommerce_serang/app/App.kt b/app/src/main/java/com/alya/ecommerce_serang/app/App.kt
new file mode 100644
index 0000000..31a11eb
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/app/App.kt
@@ -0,0 +1,7 @@
+package com.alya.ecommerce_serang.app
+
+import android.app.Application
+
+//@HiltAndroidApp
+class App : Application(){
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Category.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Category.kt
new file mode 100644
index 0000000..95fe0bc
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Category.kt
@@ -0,0 +1,11 @@
+package com.alya.ecommerce_serang.data.api.dto
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class Category(
+ val id: String,
+ val image: String,
+ val title: String
+): Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/DetailProduct.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/DetailProduct.kt
new file mode 100644
index 0000000..fe2355f
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/DetailProduct.kt
@@ -0,0 +1,22 @@
+package com.alya.ecommerce_serang.data.api.dto
+
+import com.google.gson.annotations.SerializedName
+
+data class DetailProduct(
+ val category: String,
+ val description: String,
+ val discount: Double?,
+ @SerializedName("favorite")
+ val wishlist: Boolean,
+ val id: String,
+ val images: List,
+ @SerializedName("in_stock")
+ val inStock: Int,
+ val price: Double,
+ val rating: Double,
+ val related: List,
+ val reviews: Int,
+ val title: String,
+ @SerializedName("free_delivery")
+ val freeDelivery:Boolean
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Product.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Product.kt
new file mode 100644
index 0000000..4af2851
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Product.kt
@@ -0,0 +1,17 @@
+package com.alya.ecommerce_serang.data.api.dto
+
+
+import com.google.gson.annotations.SerializedName
+
+data class Product (
+ val id: String,
+ val discount: Double?,
+ @SerializedName("favorite")
+ var wishlist: Boolean,
+ val image: String,
+ val price: Double,
+ val rating: Double,
+ @SerializedName("rating_count")
+ val ratingCount: Int,
+ val title: String,
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/AllProductResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/AllProductResponse.kt
new file mode 100644
index 0000000..f4fd1a5
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/AllProductResponse.kt
@@ -0,0 +1,57 @@
+package com.alya.ecommerce_serang.data.api.response
+
+import com.google.gson.annotations.SerializedName
+
+data class AllProductResponse(
+
+ @field:SerializedName("message")
+ val message: String,
+
+ @field:SerializedName("products")
+ val products: List
+)
+
+data class ProductsItem(
+
+ @field:SerializedName("store_id")
+ val storeId: Int,
+
+ @field:SerializedName("image")
+ val image: String,
+
+ @field:SerializedName("rating")
+ val rating: String,
+
+ @field:SerializedName("description")
+ val description: String,
+
+ @field:SerializedName("weight")
+ val weight: Int,
+
+ @field:SerializedName("is_pre_order")
+ val isPreOrder: Boolean,
+
+ @field:SerializedName("category_id")
+ val categoryId: Int,
+
+ @field:SerializedName("price")
+ val price: String,
+
+ @field:SerializedName("name")
+ val name: String,
+
+ @field:SerializedName("id")
+ val id: Int,
+
+ @field:SerializedName("min_order")
+ val minOrder: Int,
+
+ @field:SerializedName("total_sold")
+ val totalSold: Int,
+
+ @field:SerializedName("stock")
+ val stock: Int,
+
+ @field:SerializedName("status")
+ val status: String
+)
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ProductResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ProductResponse.kt
new file mode 100644
index 0000000..26b1130
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/ProductResponse.kt
@@ -0,0 +1,60 @@
+package com.alya.ecommerce_serang.data.api.response
+
+import com.google.gson.annotations.SerializedName
+
+data class ProductResponse(
+
+ @field:SerializedName("product")
+ val product: Product,
+
+ @field:SerializedName("message")
+ val message: String
+)
+
+data class Product(
+
+ @field:SerializedName("store_id")
+ val storeId: Int,
+
+ @field:SerializedName("image")
+ val image: String,
+
+ @field:SerializedName("rating")
+ val rating: String,
+
+ @field:SerializedName("description")
+ val description: String,
+
+ @field:SerializedName("weight")
+ val weight: Int,
+
+ @field:SerializedName("product_name")
+ val productName: String,
+
+ @field:SerializedName("is_pre_order")
+ val isPreOrder: Boolean,
+
+ @field:SerializedName("duration")
+ val duration: Any,
+
+ @field:SerializedName("category_id")
+ val categoryId: Int,
+
+ @field:SerializedName("price")
+ val price: String,
+
+ @field:SerializedName("product_id")
+ val productId: Int,
+
+ @field:SerializedName("min_order")
+ val minOrder: Int,
+
+ @field:SerializedName("total_sold")
+ val totalSold: Int,
+
+ @field:SerializedName("stock")
+ val stock: Int,
+
+ @field:SerializedName("product_category")
+ val productCategory: String
+)
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiConfig.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiConfig.kt
new file mode 100644
index 0000000..3a2e8f4
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiConfig.kt
@@ -0,0 +1,25 @@
+package com.alya.ecommerce_serang.data.api.retrofit
+
+import com.alya.ecommerce_serang.BuildConfig
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+
+class ApiConfig {
+ companion object{
+ fun getApiService(): ApiService {
+ val loggingInterceptor =
+ HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
+ val client = OkHttpClient.Builder()
+ .addInterceptor(loggingInterceptor)
+ .build()
+ val retrofit = Retrofit.Builder()
+ .baseUrl(BuildConfig.BASE_URL)
+ .addConverterFactory(GsonConverterFactory.create())
+ .client(client)
+ .build()
+ return retrofit.create(ApiService::class.java)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt
new file mode 100644
index 0000000..711291d
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/retrofit/ApiService.kt
@@ -0,0 +1,22 @@
+package com.alya.ecommerce_serang.data.api.retrofit
+
+import com.alya.ecommerce_serang.data.api.response.AllProductResponse
+import com.alya.ecommerce_serang.data.api.response.ProductResponse
+import retrofit2.Call
+import retrofit2.http.GET
+import retrofit2.http.Header
+import retrofit2.http.Path
+
+interface ApiService {
+ @GET("product")
+ fun getAllProduct(
+ @Header("Authorization") token: String = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NzEsIm5hbWUiOiJhbHlhIiwiZW1haWwiOiJha3VuYmVsYWphci5hbHlhQGdtYWlsLmNvbSIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzM4NDg0OTc0LCJleHAiOjE3NDEwNzY5NzR9.0JyXJQ_6CKiZEi0gvk1gcn-0ILu3a9lOr3HqjhJXbBE"
+ ): Call
+
+
+ @GET("product/detail/{id}")
+ fun getDetailProduct (
+ @Header("Authorization") token: String,
+ @Path("id") productId: Int
+ ): Call
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/model/Product.kt b/app/src/main/java/com/alya/ecommerce_serang/data/model/Product.kt
new file mode 100644
index 0000000..a5f79ea
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/model/Product.kt
@@ -0,0 +1,51 @@
+package com.alya.ecommerce_serang.data.model
+
+import com.google.gson.annotations.SerializedName
+
+data class Product(
+
+ @field:SerializedName("store_id")
+ val storeId: Int,
+
+ @field:SerializedName("image")
+ val image: String,
+
+ @field:SerializedName("rating")
+ val rating: String,
+
+ @field:SerializedName("description")
+ val description: String,
+
+ @field:SerializedName("weight")
+ val weight: Int,
+
+ @field:SerializedName("product_name")
+ val productName: String,
+
+ @field:SerializedName("is_pre_order")
+ val isPreOrder: Boolean,
+
+ @field:SerializedName("duration")
+ val duration: Any,
+
+ @field:SerializedName("category_id")
+ val categoryId: Int,
+
+ @field:SerializedName("price")
+ val price: String,
+
+ @field:SerializedName("product_id")
+ val productId: Int,
+
+ @field:SerializedName("min_order")
+ val minOrder: Int,
+
+ @field:SerializedName("total_sold")
+ val totalSold: Int,
+
+ @field:SerializedName("stock")
+ val stock: Int,
+
+ @field:SerializedName("product_category")
+ val productCategory: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/model/User.kt b/app/src/main/java/com/alya/ecommerce_serang/data/model/User.kt
new file mode 100644
index 0000000..c04a59b
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/model/User.kt
@@ -0,0 +1,9 @@
+package com.alya.ecommerce_serang.data.model
+
+data class User(
+ val username: String,
+ val avatar:String?,
+ val email:String,
+ val firstName:String?,
+ val lastName:String?
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt b/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt
new file mode 100644
index 0000000..1f73cbd
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/repository/ProductRepository.kt
@@ -0,0 +1,35 @@
+package com.alya.ecommerce_serang.data.repository
+
+import android.util.Log
+import com.alya.ecommerce_serang.data.api.response.ProductsItem
+import com.alya.ecommerce_serang.data.api.retrofit.ApiService
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+class ProductRepository(private val apiService: ApiService) {
+ suspend fun getAllProducts(): Result> =
+ withContext(Dispatchers.IO) {
+ try {
+ Log.d("ProductRepository", "Attempting to fetch products")
+ val response = apiService.getAllProduct().execute()
+ Log.d("ProductRepository", "Response received. Success: ${response.isSuccessful}")
+ Log.d("ProductRepository", "Response code: ${response.code()}")
+ Log.d("ProductRepository", "Response message: ${response.message()}")
+
+ if (response.isSuccessful) {
+ Result.success(response.body()?.products ?: emptyList())
+ } else {
+ Result.failure(Exception("Failed to fetch products"))
+ }
+ } catch (e: Exception) {
+ Result.failure(e)
+ }
+ }
+// suspend fun getCategories():List
+//
+// fun getProducts(query: ProductQuery) : Flow>
+// fun getRecentSearchs(): Flow>
+// suspend fun clearRecents()
+// suspend fun addRecents(search:String)
+// suspend fun getProduct(id:String):DetailProduct
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/MainActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/MainActivity.kt
index 15e1e6e..9450c13 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/ui/MainActivity.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/MainActivity.kt
@@ -1,31 +1,57 @@
package com.alya.ecommerce_serang.ui
import android.os.Bundle
-import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.isVisible
+import androidx.navigation.fragment.NavHostFragment
+import androidx.navigation.ui.setupWithNavController
import com.alya.ecommerce_serang.R
import com.alya.ecommerce_serang.databinding.ActivityMainBinding
-import com.google.android.material.bottomnavigation.BottomNavigationView
-
+//@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
+ private val navController by lazy {
+ (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
- enableEdgeToEdge()
- setContentView(R.layout.activity_main)
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
- val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
- insets
- }
-
- val bottomNavigationView = findViewById(R.id.bottom_navigation)
+ setupBottomNavigation()
+ observeDestinationChanges()
}
+
+ private fun setupBottomNavigation() {
+ binding.bottomNavigation.setupWithNavController(navController)
+
+ binding.bottomNavigation.setOnItemSelectedListener { menuItem ->
+ when (menuItem.itemId) {
+ R.id.home_item_fragment -> {
+ navController.navigate(R.id.homeFragment)
+ true
+ }
+ R.id.chat_item_fragment -> {
+ navController.navigate(R.id.chatFragment)
+ true
+ }
+ R.id.profile_item_fragment -> {
+ navController.navigate(R.id.profileFragment)
+ true
+ }
+ else -> false
+ }
+ }
+ }
+
+ private fun observeDestinationChanges() {
+ navController.addOnDestinationChangedListener { _, destination, _ ->
+ binding.bottomNavigation.isVisible = when (destination.id) {
+ R.id.homeFragment, R.id.chatFragment, R.id.profileFragment -> true
+ else -> false // Bottom Navigation tidak terlihat di layar lain
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatFragment.kt
new file mode 100644
index 0000000..614134d
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatFragment.kt
@@ -0,0 +1,31 @@
+package com.alya.ecommerce_serang.ui.chat
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import com.alya.ecommerce_serang.R
+
+class ChatFragment : Fragment() {
+
+ companion object {
+ fun newInstance() = ChatFragment()
+ }
+
+ private val viewModel: ChatViewModel by viewModels()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // TODO: Use the ViewModel
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ return inflater.inflate(R.layout.fragment_chat, container, false)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatViewModel.kt
new file mode 100644
index 0000000..01319f3
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/chat/ChatViewModel.kt
@@ -0,0 +1,7 @@
+package com.alya.ecommerce_serang.ui.chat
+
+import androidx.lifecycle.ViewModel
+
+class ChatViewModel : ViewModel() {
+ // TODO: Implement the ViewModel
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/home/HomeCategoryAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/home/HomeCategoryAdapter.kt
new file mode 100644
index 0000000..a2b2009
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/home/HomeCategoryAdapter.kt
@@ -0,0 +1,39 @@
+package com.alya.ecommerce_serang.ui.home
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.alya.ecommerce_serang.data.api.dto.Category
+import com.alya.ecommerce_serang.databinding.ItemCategoryHomeBinding
+import com.bumptech.glide.Glide
+
+class HomeCategoryAdapter(
+ private val categories:List,
+ //A lambda function that will be invoked when a category item is clicked.
+ private val onClick:(category:Category) -> Unit
+): RecyclerView.Adapter() {
+
+ /*
+ ViewHolder is responsible for caching and managing the view references for each item in
+ the RecyclerView.It binds the Category data to the corresponding views within the item layout.
+ */
+ inner class ViewHolder(private val binding: ItemCategoryHomeBinding): RecyclerView.ViewHolder(binding.root){
+ fun bind(category: Category) = with(binding){
+ Glide.with(root).load(category.image).into(image)
+ name.text = category.title
+ root.setOnClickListener{
+ onClick(category)
+ }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder (
+ ItemCategoryHomeBinding.inflate(LayoutInflater.from(parent.context),parent,false)
+ )
+
+ override fun getItemCount() = categories.size
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ holder.bind(categories[position])
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/home/HomeFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/home/HomeFragment.kt
new file mode 100644
index 0000000..41e667e
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/home/HomeFragment.kt
@@ -0,0 +1,145 @@
+package com.alya.ecommerce_serang.ui.home
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.alya.ecommerce_serang.R
+import com.alya.ecommerce_serang.data.api.response.ProductsItem
+import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
+import com.alya.ecommerce_serang.data.repository.ProductRepository
+import com.alya.ecommerce_serang.databinding.FragmentHomeBinding
+import com.alya.ecommerce_serang.utils.BaseViewModelFactory
+import com.alya.ecommerce_serang.utils.HorizontalMarginItemDecoration
+import com.alya.ecommerce_serang.utils.setLightStatusBar
+import kotlinx.coroutines.launch
+
+//@AndroidEntryPoint
+class HomeFragment : Fragment() {
+
+ private var _binding: FragmentHomeBinding? = null
+ private val binding get() = _binding!!
+ private lateinit var viewModel: HomeViewModel
+ private var productAdapter: HorizontalProductAdapter? = null
+
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentHomeBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val repository = ProductRepository(ApiConfig.getApiService())
+ viewModel = ViewModelProvider(
+ this,
+ // Pass a lambda that creates the ViewModel
+ BaseViewModelFactory {
+ HomeViewModel(repository)
+ }
+ )[HomeViewModel::class.java]
+
+ initUi()
+ setupRecyclerView()
+ observeData()
+ }
+
+ private fun setupRecyclerView() {
+ productAdapter = HorizontalProductAdapter(
+ products = emptyList(),
+ onClick = { product -> handleProductClick(product) }
+ )
+
+ binding.newProducts.apply {
+ adapter = productAdapter
+ layoutManager = LinearLayoutManager(
+ context,
+ LinearLayoutManager.HORIZONTAL,
+ false
+ )
+ }
+ }
+
+ private fun observeData() {
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewModel.uiState.collect { state ->
+ when (state) {
+ is HomeUiState.Loading -> {
+ binding.loading.root.isVisible = true
+ binding.error.root.isVisible = false
+ binding.home.isVisible = false
+ }
+ is HomeUiState.Success -> {
+ binding.loading.root.isVisible = false
+ binding.error.root.isVisible = false
+ binding.home.isVisible = true
+ productAdapter?.updateProducts(state.products)
+ }
+ is HomeUiState.Error -> {
+ binding.loading.root.isVisible = false
+ binding.error.root.isVisible = true
+ binding.home.isVisible = false
+ binding.error.errorMessage.text = state.message
+ binding.error.retryButton.setOnClickListener {
+ viewModel.retry()
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun initUi() {
+ // For LightStatusBar
+ setLightStatusBar()
+ val banners = binding.banners
+ banners.offscreenPageLimit = 1
+
+ val nextItemVisiblePx = resources.getDimension(R.dimen.viewpager_next_item_visible)
+ val currentItemHorizontalMarginPx =
+ resources.getDimension(R.dimen.viewpager_current_item_horizontal_margin)
+ val pageTranslationX = nextItemVisiblePx + currentItemHorizontalMarginPx
+
+ banners.setPageTransformer { page, position ->
+ page.translationX = -pageTranslationX * position
+ page.scaleY = 1 - (0.25f * kotlin.math.abs(position))
+ }
+
+ banners.addItemDecoration(
+ HorizontalMarginItemDecoration(
+ requireContext(),
+ R.dimen.viewpager_current_item_horizontal_margin
+ )
+ )
+ }
+
+
+ private fun handleProductClick(product: ProductsItem) {
+ // Navigate to product detail
+// findNavController().navigate(
+// HomeFragmentDirections.actionHomeToDetail(product.id)
+// )
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+
+ private fun showLoading(isLoading: Boolean) {
+ if (isLoading) {
+ binding.progressBar.visibility = View.VISIBLE
+ } else {
+ binding.progressBar.visibility = View.GONE
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/home/HomeViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/home/HomeViewModel.kt
new file mode 100644
index 0000000..71b52ce
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/home/HomeViewModel.kt
@@ -0,0 +1,60 @@
+package com.alya.ecommerce_serang.ui.home
+
+import android.util.Log
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.alya.ecommerce_serang.data.api.response.AllProductResponse
+import com.alya.ecommerce_serang.data.api.response.ProductsItem
+import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
+import com.alya.ecommerce_serang.data.repository.ProductRepository
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+
+class HomeViewModel (
+ private val productRepository: ProductRepository
+): ViewModel() {
+ private val _uiState = MutableStateFlow(HomeUiState.Loading)
+ val uiState: StateFlow = _uiState.asStateFlow()
+ val home = MutableLiveData(null)
+ constructor() : this(ProductRepository(ApiConfig.getApiService()))
+
+
+ init {
+ loadProducts()
+ }
+
+ private fun loadProducts() {
+ viewModelScope.launch {
+ _uiState.value = HomeUiState.Loading
+ productRepository.getAllProducts()
+ .onSuccess { products ->
+ _uiState.value = HomeUiState.Success(products)
+ }
+ .onFailure { error ->
+ _uiState.value = HomeUiState.Error(error.message ?: "Unknown error")
+ Log.e("ProductViewModel", "Products fetch failed", error)
+ }
+ }
+ }
+
+ fun retry() {
+ loadProducts()
+ }
+
+// fun toggleWishlist(product: Product) = viewModelScope.launch {
+// try {
+// productRepository.toggleWishlist(product.id,product.wishlist)
+// }catch (e:Exception){
+//
+// }
+// }
+}
+
+sealed class HomeUiState {
+ object Loading : HomeUiState()
+ data class Success(val products: List) : HomeUiState()
+ data class Error(val message: String) : HomeUiState()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/home/HorizontalProductAdapter.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/home/HorizontalProductAdapter.kt
new file mode 100644
index 0000000..61c48b8
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/home/HorizontalProductAdapter.kt
@@ -0,0 +1,52 @@
+package com.alya.ecommerce_serang.ui.home
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.alya.ecommerce_serang.data.api.response.ProductsItem
+import com.alya.ecommerce_serang.databinding.ItemProductHorizontalBinding
+import com.bumptech.glide.Glide
+
+class HorizontalProductAdapter(
+ private var products: List,
+ private val onClick: (ProductsItem) -> Unit
+) : RecyclerView.Adapter() {
+
+ inner class ProductViewHolder(private val binding: ItemProductHorizontalBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+
+ fun bind(product: ProductsItem) = with(binding) {
+ itemName.text = product.name
+ itemPrice.text = product.price
+ rating.text = product.rating
+// productSold.text = "${product.totalSold} sold"
+
+ // Load image using Glide
+ Glide.with(itemView)
+// .load("${BuildConfig.BASE_URL}/product/${product.image}")
+// .load("${BuildConfig.BASE_URL}/${product.image}")
+ .load(product.image)
+ .into(image)
+
+ root.setOnClickListener { onClick(product) }
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
+ val binding = ItemProductHorizontalBinding.inflate(
+ LayoutInflater.from(parent.context), parent, false
+ )
+ return ProductViewHolder(binding)
+ }
+
+ override fun getItemCount() = products.size
+
+ override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
+ holder.bind(products[position])
+ }
+
+ fun updateProducts(newProducts: List) {
+ products = newProducts
+ notifyDataSetChanged()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/product/ProductViewHolder.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/product/ProductViewHolder.kt
new file mode 100644
index 0000000..43a7e0e
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/product/ProductViewHolder.kt
@@ -0,0 +1,35 @@
+package com.alya.ecommerce_serang.ui.product
+
+import androidx.recyclerview.widget.RecyclerView
+import com.alya.ecommerce_serang.R
+import com.alya.ecommerce_serang.data.api.dto.Product
+import com.alya.ecommerce_serang.databinding.ItemProductHorizontalBinding
+import com.bumptech.glide.Glide
+
+class ProductViewHolder(private val binding: ItemProductHorizontalBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+ fun bind(
+ product: Product,
+ onClick: (product: Product) -> Unit,
+ ) = with(binding) {
+ Glide.with(root).load(product.image).into(image)
+
+// discount.isVisible = product.discount != null
+// product.discount?.let {
+// val discount = (product.discount / product.price * 100).roundToInt()
+// binding.discount.text =
+// root.context.getString(R.string.fragment_item_product_discount, discount)
+// }
+
+ itemName.text = product.title
+ rating.text = String.format("%.1f", product.rating)
+
+// val current = product.price - (product.discount ?: 0.0)
+ val current = product.price
+ itemPrice.text = root.context.getString(R.string.item_price_txt, current)
+
+ root.setOnClickListener {
+ onClick(product)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/ProfileFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/ProfileFragment.kt
new file mode 100644
index 0000000..2c7a149
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/ProfileFragment.kt
@@ -0,0 +1,31 @@
+package com.alya.ecommerce_serang.ui.profile
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import com.alya.ecommerce_serang.R
+
+class ProfileFragment : Fragment() {
+
+ companion object {
+ fun newInstance() = ProfileFragment()
+ }
+
+ private val viewModel: ProfileViewModel by viewModels()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // TODO: Use the ViewModel
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ return inflater.inflate(R.layout.fragment_profile, container, false)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/profile/ProfileViewModel.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/ProfileViewModel.kt
new file mode 100644
index 0000000..fb0e34f
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/profile/ProfileViewModel.kt
@@ -0,0 +1,7 @@
+package com.alya.ecommerce_serang.ui.profile
+
+import androidx.lifecycle.ViewModel
+
+class ProfileViewModel : ViewModel() {
+ // TODO: Implement the ViewModel
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/BaseFragment.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/BaseFragment.kt
new file mode 100644
index 0000000..19b9ea1
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/BaseFragment.kt
@@ -0,0 +1,7 @@
+package com.alya.ecommerce_serang.utils
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+
+typealias Inflate = (LayoutInflater, ViewGroup?, Boolean) -> T
+
diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/BaseViewModelFactory.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/BaseViewModelFactory.kt
new file mode 100644
index 0000000..9673190
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/BaseViewModelFactory.kt
@@ -0,0 +1,13 @@
+package com.alya.ecommerce_serang.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+
+class BaseViewModelFactory(
+ private val creator: () -> VM
+) : ViewModelProvider.Factory {
+ override fun create(modelClass: Class): T {
+ @Suppress("UNCHECKED_CAST")
+ return creator() as T
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/Functions.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/Functions.kt
new file mode 100644
index 0000000..9e1ba9c
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/Functions.kt
@@ -0,0 +1,22 @@
+package com.alya.ecommerce_serang.utils
+
+import android.os.Build
+import android.view.View
+import android.view.WindowInsetsController
+import androidx.fragment.app.Fragment
+
+fun Fragment.setLightStatusBar(){
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ requireActivity().window.insetsController?.setSystemBarsAppearance(
+ WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
+ WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS)
+ } else {
+ @Suppress("DEPRECATION")
+ requireActivity().window.decorView.systemUiVisibility = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
+ } else {
+ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/HorizontalMarginItemDecoration.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/HorizontalMarginItemDecoration.kt
new file mode 100644
index 0000000..28d9a19
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/HorizontalMarginItemDecoration.kt
@@ -0,0 +1,22 @@
+package com.alya.ecommerce_serang.utils
+
+import android.content.Context
+import android.graphics.Rect
+import android.view.View
+import androidx.annotation.DimenRes
+import androidx.recyclerview.widget.RecyclerView
+
+class HorizontalMarginItemDecoration(context: Context, @DimenRes horizontalMarginInDp: Int) :
+ RecyclerView.ItemDecoration() {
+
+ private val horizontalMarginInPx: Int =
+ context.resources.getDimension(horizontalMarginInDp).toInt()
+
+ override fun getItemOffsets(
+ outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
+ ) {
+ outRect.right = horizontalMarginInPx
+ outRect.left = horizontalMarginInPx
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/ProductQuery.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/ProductQuery.kt
new file mode 100644
index 0000000..83f557e
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/ProductQuery.kt
@@ -0,0 +1,20 @@
+package com.alya.ecommerce_serang.utils
+
+import android.os.Parcelable
+import com.alya.ecommerce_serang.data.api.dto.Category
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class ProductQuery (
+ val category: Category? = null,
+ val search:String? = null,
+ val range:Pair = 0f to 10000f,
+ val rating:Int? = null,
+ val discount:Int? = null,
+ val sort:List = emptyList(),
+ val favorite:Boolean = false
+): Parcelable
+
+enum class Sort{
+ disconunt, voucher, shipping, delivery
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/banner_default.jpg b/app/src/main/res/drawable/banner_default.jpg
new file mode 100644
index 0000000..4b227f5
Binary files /dev/null and b/app/src/main/res/drawable/banner_default.jpg differ
diff --git a/app/src/main/res/drawable/baseline_account_circle_24.xml b/app/src/main/res/drawable/baseline_account_circle_24.xml
new file mode 100644
index 0000000..da4b6e5
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_account_circle_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_arrow_back_24.xml b/app/src/main/res/drawable/baseline_arrow_back_24.xml
new file mode 100644
index 0000000..f9c67c9
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_arrow_back_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_chat_24.xml b/app/src/main/res/drawable/baseline_chat_24.xml
new file mode 100644
index 0000000..7fc5c09
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_chat_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_home_24.xml b/app/src/main/res/drawable/baseline_home_24.xml
new file mode 100644
index 0000000..b464bbb
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_home_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_search_24.xml b/app/src/main/res/drawable/baseline_search_24.xml
new file mode 100644
index 0000000..27a43c1
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_search_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_star_24.xml b/app/src/main/res/drawable/baseline_star_24.xml
new file mode 100644
index 0000000..cbd9a83
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_star_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/makanan_ringan.jpg b/app/src/main/res/drawable/makanan_ringan.jpg
new file mode 100644
index 0000000..1ff7d41
Binary files /dev/null and b/app/src/main/res/drawable/makanan_ringan.jpg differ
diff --git a/app/src/main/res/drawable/outline_notifications_24.xml b/app/src/main/res/drawable/outline_notifications_24.xml
new file mode 100644
index 0000000..aeb6101
--- /dev/null
+++ b/app/src/main/res/drawable/outline_notifications_24.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/outline_shopping_cart_24.xml b/app/src/main/res/drawable/outline_shopping_cart_24.xml
new file mode 100644
index 0000000..8680c2d
--- /dev/null
+++ b/app/src/main/res/drawable/outline_shopping_cart_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/rating_background.xml b/app/src/main/res/drawable/rating_background.xml
new file mode 100644
index 0000000..4dfd157
--- /dev/null
+++ b/app/src/main/res/drawable/rating_background.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/search_background.xml b/app/src/main/res/drawable/search_background.xml
new file mode 100644
index 0000000..86c8a8f
--- /dev/null
+++ b/app/src/main/res/drawable/search_background.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_account.xml b/app/src/main/res/drawable/selector_account.xml
new file mode 100644
index 0000000..e20e513
--- /dev/null
+++ b/app/src/main/res/drawable/selector_account.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_chat.xml b/app/src/main/res/drawable/selector_chat.xml
new file mode 100644
index 0000000..0675b22
--- /dev/null
+++ b/app/src/main/res/drawable/selector_chat.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/selector_home.xml b/app/src/main/res/drawable/selector_home.xml
new file mode 100644
index 0000000..67b8c01
--- /dev/null
+++ b/app/src/main/res/drawable/selector_home.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index a953d86..c53dea4 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,32 +1,35 @@
-
-
-
-
-
+
+
+
+
+ app:itemIconSize="@dimen/m3_comp_navigation_bar_active_indicator_height" />
-
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_chat.xml b/app/src/main/res/layout/fragment_chat.xml
new file mode 100644
index 0000000..4f1189a
--- /dev/null
+++ b/app/src/main/res/layout/fragment_chat.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
new file mode 100644
index 0000000..fa6588a
--- /dev/null
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml
new file mode 100644
index 0000000..28e1eec
--- /dev/null
+++ b/app/src/main/res/layout/fragment_profile.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_category.xml b/app/src/main/res/layout/item_category.xml
new file mode 100644
index 0000000..77d9ef6
--- /dev/null
+++ b/app/src/main/res/layout/item_category.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_category_home.xml b/app/src/main/res/layout/item_category_home.xml
new file mode 100644
index 0000000..6a78067
--- /dev/null
+++ b/app/src/main/res/layout/item_category_home.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_product_horizontal.xml b/app/src/main/res/layout/item_product_horizontal.xml
new file mode 100644
index 0000000..e40ba47
--- /dev/null
+++ b/app/src/main/res/layout/item_product_horizontal.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_section_horizontal.xml b/app/src/main/res/layout/item_section_horizontal.xml
new file mode 100644
index 0000000..41fd5e3
--- /dev/null
+++ b/app/src/main/res/layout/item_section_horizontal.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_section_vertical.xml b/app/src/main/res/layout/item_section_vertical.xml
new file mode 100644
index 0000000..fe2883b
--- /dev/null
+++ b/app/src/main/res/layout/item_section_vertical.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_error.xml b/app/src/main/res/layout/view_error.xml
new file mode 100644
index 0000000..971a5e9
--- /dev/null
+++ b/app/src/main/res/layout/view_error.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_loading.xml b/app/src/main/res/layout/view_loading.xml
new file mode 100644
index 0000000..77d9ef6
--- /dev/null
+++ b/app/src/main/res/layout/view_loading.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_search.xml b/app/src/main/res/layout/view_search.xml
new file mode 100644
index 0000000..9e75d20
--- /dev/null
+++ b/app/src/main/res/layout/view_search.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_navigation_menu.xml b/app/src/main/res/menu/bottom_navigation_menu.xml
index c49220d..eca7241 100644
--- a/app/src/main/res/menu/bottom_navigation_menu.xml
+++ b/app/src/main/res/menu/bottom_navigation_menu.xml
@@ -1,18 +1,18 @@
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
new file mode 100644
index 0000000..245ec4e
--- /dev/null
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index c8524cd..a0d6d78 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -2,4 +2,8 @@
#FF000000
#FFFFFFFF
+ #E8ECF2
+ #7D8FAB
+ #303733
+ #489EC6
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..384454c
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+
+
+ 32dp
+ 16dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 2a045f7..007a5f4 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,14 @@
ecommerce_serang
+
+
+
+ Cari produk
+ Kategori Produk
+ Makanan Ringan
+ Lainnya
+
+ Rp%.1f
+ Coba lagi\n
+ Terdapat error...
\ No newline at end of file
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..f9cb96f
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+ 192.168.1.13
+ localhost
+
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index f74b04b..1bd531d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,4 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ dependencies {
+ classpath ("androidx.navigation:navigation-safe-args-gradle-plugin:2.5.1")
+// classpath("com.google.dagger:hilt-android-gradle-plugin:2.55")
+ }
+}
+
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.jetbrains.kotlin.android) apply false
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index da02889..9a7ecd6 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,5 +1,7 @@
[versions]
agp = "8.5.2"
+hiltAndroid = "2.51"
+hiltLifecycleViewmodel = "1.0.0-alpha03"
kotlin = "1.9.0"
coreKtx = "1.10.1"
junit = "4.13.2"
@@ -9,9 +11,17 @@ appcompat = "1.7.0"
material = "1.12.0"
activity = "1.9.2"
constraintlayout = "2.1.4"
+legacySupportV4 = "1.0.0"
+lifecycleLivedataKtx = "2.8.7"
+lifecycleViewmodelKtx = "2.8.7"
+fragmentKtx = "1.5.6"
+navigationFragmentKtx = "2.8.5"
+navigationUiKtx = "2.8.5"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+androidx-hilt-lifecycle-viewmodel = { module = "androidx.hilt:hilt-lifecycle-viewmodel", version.ref = "hiltLifecycleViewmodel" }
+hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
@@ -19,6 +29,12 @@ androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+androidx-legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacySupportV4" }
+androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
+androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
+androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragmentKtx" }
+androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
+androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }