diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index cc9e2b6..2e2e461 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -23,7 +23,7 @@ android {
buildTypes {
release {
- buildConfigField("String", "BASE_URL", "\"http://192.168.1.3:3000/\"")
+ buildConfigField("String", "BASE_URL", "\"http://192.168.1.4:3000/\"")
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
@@ -31,7 +31,7 @@ android {
)
}
debug {
- buildConfigField("String", "BASE_URL", "\"http://192.168.1.3:3000/\"")
+ buildConfigField("String", "BASE_URL", "\"http://192.168.1.4:3000/\"")
}
}
compileOptions {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8986548..ac53989 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">
+
+
@@ -36,9 +40,7 @@
android:exported="false" />
-
-
+ android:exported="true">
\ 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
deleted file mode 100644
index 95fe0bc..0000000
--- a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Category.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-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/CategoryItem.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/CategoryItem.kt
new file mode 100644
index 0000000..ca0963d
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/CategoryItem.kt
@@ -0,0 +1,22 @@
+package com.alya.ecommerce_serang.data.api.dto
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+
+data class CategoryItem(
+
+ @field:SerializedName("image")
+ val image: String,
+
+ @field:SerializedName("name")
+ val name: String,
+
+ @field:SerializedName("id")
+ val id: Int,
+
+ @field:SerializedName("store_type_id")
+ val storeTypeId: Int
+) : 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
index fe2355f..0680a18 100644
--- 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
@@ -14,7 +14,7 @@ data class DetailProduct(
val inStock: Int,
val price: Double,
val rating: Double,
- val related: List,
+ val related: List,
val reviews: Int,
val title: String,
@SerializedName("free_delivery")
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
deleted file mode 100644
index 4af2851..0000000
--- a/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/Product.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-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/dto/ProductsItem.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/ProductsItem.kt
new file mode 100644
index 0000000..37a5bf2
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/dto/ProductsItem.kt
@@ -0,0 +1,49 @@
+package com.alya.ecommerce_serang.data.api.dto
+
+
+import com.google.gson.annotations.SerializedName
+
+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
+)
\ 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
index f4fd1a5..e45093f 100644
--- 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
@@ -1,5 +1,6 @@
package com.alya.ecommerce_serang.data.api.response
+import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.google.gson.annotations.SerializedName
data class AllProductResponse(
@@ -11,47 +12,4 @@ data class AllProductResponse(
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/CategoryResponse.kt b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/CategoryResponse.kt
new file mode 100644
index 0000000..26867ca
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/data/api/response/CategoryResponse.kt
@@ -0,0 +1,15 @@
+package com.alya.ecommerce_serang.data.api.response
+
+import com.alya.ecommerce_serang.data.api.dto.CategoryItem
+import com.google.gson.annotations.SerializedName
+
+data class CategoryResponse(
+
+ @field:SerializedName("Category")
+ val category: List,
+
+ @field:SerializedName("message")
+ val message: String
+)
+
+
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
index 7981961..0d4a120 100644
--- 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
@@ -4,6 +4,7 @@ import com.alya.ecommerce_serang.data.api.dto.LoginRequest
import com.alya.ecommerce_serang.data.api.dto.OtpRequest
import com.alya.ecommerce_serang.data.api.dto.RegisterRequest
import com.alya.ecommerce_serang.data.api.response.AllProductResponse
+import com.alya.ecommerce_serang.data.api.response.CategoryResponse
import com.alya.ecommerce_serang.data.api.response.LoginResponse
import com.alya.ecommerce_serang.data.api.response.OtpResponse
import com.alya.ecommerce_serang.data.api.response.ProductResponse
@@ -32,6 +33,10 @@ interface ApiService {
@Body loginRequest: LoginRequest
): Response
+ @GET("category")
+ suspend fun allCategory(
+ ): Response
+
@GET("product")
suspend fun getAllProduct(): Response
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
index d43462f..cfe5e8a 100644
--- 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
@@ -1,7 +1,8 @@
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.dto.CategoryItem
+import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.alya.ecommerce_serang.data.api.retrofit.ApiService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -15,7 +16,9 @@ class ProductRepository(private val apiService: ApiService) {
if (response.isSuccessful) {
// Return a Result.Success with the list of products
+
Result.Success(response.body()?.products ?: emptyList())
+
} else {
// Return a Result.Error with a custom Exception
Result.Error(Exception("Failed to fetch products. Code: ${response.code()}"))
@@ -26,7 +29,24 @@ class ProductRepository(private val apiService: ApiService) {
}
}
-// suspend fun getUserData(): Response {
-// return apiService.getProtectedData()
-// }
+ suspend fun getAllCategories(): Result> =
+ withContext(Dispatchers.IO) {
+ try {
+ Log.d("Categories", "Attempting to fetch categories")
+ val response = apiService.allCategory()
+
+ if (response.isSuccessful) {
+ val categories = response.body()?.category ?: emptyList()
+ Log.d("Categories", "Fetched categories: $categories")
+ categories.forEach { Log.d("Category Image", "Category: ${it.name}, Image: ${it.image}") }
+ Result.Success(categories)
+ } else {
+ Result.Error(Exception("Failed to fetch categories. Code: ${response.code()}"))
+ }
+ } catch (e: Exception) {
+ Log.e("Categories", "Error fetching categories", e)
+ Result.Error(e)
+ }
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/RegisterActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/RegisterActivity.kt
index 5a10983..f9205f7 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/ui/auth/RegisterActivity.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/auth/RegisterActivity.kt
@@ -12,10 +12,13 @@ import com.alya.ecommerce_serang.data.api.retrofit.ApiConfig
import com.alya.ecommerce_serang.data.repository.Result
import com.alya.ecommerce_serang.data.repository.UserRepository
import com.alya.ecommerce_serang.databinding.ActivityRegisterBinding
+import com.alya.ecommerce_serang.ui.MainActivity
import com.alya.ecommerce_serang.utils.BaseViewModelFactory
+import com.alya.ecommerce_serang.utils.SessionManager
class RegisterActivity : AppCompatActivity() {
private lateinit var binding: ActivityRegisterBinding
+ private lateinit var sessionManager: SessionManager
private val registerViewModel: RegisterViewModel by viewModels{
BaseViewModelFactory {
val apiService = ApiConfig.getUnauthenticatedApiService()
@@ -26,6 +29,14 @@ class RegisterActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+
+ sessionManager = SessionManager(this)
+ if (!sessionManager.getToken().isNullOrEmpty()) {
+ // User already logged in, redirect to MainActivity
+ startActivity(Intent(this, MainActivity::class.java))
+ finish()
+ }
+
enableEdgeToEdge()
binding = ActivityRegisterBinding.inflate(layoutInflater)
setContentView(binding.root)
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
index a2b2009..0e9a0bd 100644
--- 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
@@ -1,16 +1,19 @@
package com.alya.ecommerce_serang.ui.home
+import android.util.Log
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.BuildConfig.BASE_URL
+import com.alya.ecommerce_serang.R
+import com.alya.ecommerce_serang.data.api.dto.CategoryItem
import com.alya.ecommerce_serang.databinding.ItemCategoryHomeBinding
import com.bumptech.glide.Glide
class HomeCategoryAdapter(
- private val categories:List,
+ private var categories:List,
//A lambda function that will be invoked when a category item is clicked.
- private val onClick:(category:Category) -> Unit
+ private val onClick:(category:CategoryItem) -> Unit
): RecyclerView.Adapter() {
/*
@@ -18,12 +21,25 @@ class HomeCategoryAdapter(
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)
+ fun bind(category: CategoryItem) = with(binding) {
+ Log.d("CategoriesAdapter", "Binding category: ${category.name}, Image: ${category.image}")
+
+ val fullImageUrl = if (category.image.startsWith("/")) {
+ BASE_URL + category.image.removePrefix("/") // Append base URL if the path starts with "/"
+ } else {
+ category.image // Use as is if it's already a full URL
}
+
+ Log.d("CategoriesAdapter", "Loading image: $fullImageUrl")
+
+ Glide.with(itemView.context)
+ .load(fullImageUrl) // Ensure full URL
+ .placeholder(R.drawable.placeholder_image)
+ .into(imageCategory)
+
+ name.text = category.name
+
+ root.setOnClickListener { onClick(category) }
}
}
@@ -36,4 +52,14 @@ class HomeCategoryAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(categories[position])
}
+
+ fun updateData(newCategories: List) {
+ categories = newCategories.toList()
+ notifyDataSetChanged()
+ }
+
+ fun updateLimitedCategory(newCategories: List){
+ val limitedCategories = newCategories.take(10)
+ updateData(limitedCategories)
+ }
}
\ 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
index 08db098..902ab06 100644
--- 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
@@ -1,16 +1,20 @@
package com.alya.ecommerce_serang.ui.home
import android.os.Bundle
+import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
+import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
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.dto.CategoryItem
+import com.alya.ecommerce_serang.data.api.dto.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
@@ -26,6 +30,7 @@ class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
private var productAdapter: HorizontalProductAdapter? = null
+ private var categoryAdapter: HomeCategoryAdapter? = null
private lateinit var sessionManager: SessionManager
private val viewModel: HomeViewModel by viewModels {
BaseViewModelFactory {
@@ -62,6 +67,11 @@ class HomeFragment : Fragment() {
onClick = { product -> handleProductClick(product) }
)
+ categoryAdapter = HomeCategoryAdapter(
+ categories = emptyList(),
+ onClick = { category -> handleCategoryProduct(category)}
+ )
+
binding.newProducts.apply {
adapter = productAdapter
layoutManager = LinearLayoutManager(
@@ -70,37 +80,59 @@ class HomeFragment : Fragment() {
false
)
}
+
+ binding.categories.apply {
+ adapter = categoryAdapter
+ 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()
+ viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ 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?.updateLimitedProducts(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()
+ }
}
}
}
}
}
+
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.categories.collect { categories ->
+ Log.d("Categories", "Updated Categories: $categories")
+ categories.forEach { Log.d("Category Image", "Category: ${it.name}, Image: ${it.image}") }
+ categoryAdapter?.updateLimitedCategory(categories)
+ }
+ }
+ }
}
+
private fun initUi() {
// For LightStatusBar
setLightStatusBar()
@@ -130,16 +162,18 @@ class HomeFragment : Fragment() {
}
+ private fun handleCategoryProduct(category: CategoryItem) {
+
+ }
+
override fun onDestroyView() {
super.onDestroyView()
+ productAdapter = null
+ categoryAdapter = null
_binding = null
}
private fun showLoading(isLoading: Boolean) {
- if (isLoading) {
- binding.progressBar.visibility = View.VISIBLE
- } else {
- binding.progressBar.visibility = View.GONE
- }
+ binding.progressBar.isVisible = isLoading
}
}
\ 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
index 14e81af..265ea4d 100644
--- 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
@@ -3,7 +3,8 @@ package com.alya.ecommerce_serang.ui.home
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import com.alya.ecommerce_serang.data.api.response.ProductsItem
+import com.alya.ecommerce_serang.data.api.dto.CategoryItem
+import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.alya.ecommerce_serang.data.repository.ProductRepository
import com.alya.ecommerce_serang.data.repository.Result
import kotlinx.coroutines.flow.MutableStateFlow
@@ -17,25 +18,31 @@ class HomeViewModel (
private val _uiState = MutableStateFlow(HomeUiState.Loading)
val uiState: StateFlow = _uiState.asStateFlow()
+ private val _categories = MutableStateFlow>(emptyList())
+ val categories: StateFlow> = _categories.asStateFlow()
+
init {
loadProducts()
+ loadCategories()
}
private fun loadProducts() {
viewModelScope.launch {
_uiState.value = HomeUiState.Loading
-
when (val result = productRepository.getAllProducts()) {
- is Result.Success -> {
- _uiState.value = HomeUiState.Success(result.data)
- }
- is Result.Error -> {
- _uiState.value = HomeUiState.Error(result.exception.message ?: "Unknown error")
- Log.e("HomeViewModel", "Failed to fetch products", result.exception)
- }
- is Result.Loading-> {
+ is Result.Success -> _uiState.value = HomeUiState.Success(result.data)
+ is Result.Error -> _uiState.value = HomeUiState.Error(result.exception.message ?: "Unknown error")
+ is Result.Loading -> {}
+ }
+ }
+ }
- }
+ private fun loadCategories() {
+ viewModelScope.launch {
+ when (val result = productRepository.getAllCategories()) {
+ is Result.Success -> _categories.value = result.data
+ is Result.Error -> Log.e("HomeViewModel", "Failed to fetch categories", result.exception)
+ is Result.Loading -> {}
}
}
}
@@ -43,6 +50,7 @@ class HomeViewModel (
fun retry() {
loadProducts()
+ loadCategories()
}
// private fun fetchUserData() {
@@ -67,4 +75,4 @@ 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
index 61c48b8..8af4b5f 100644
--- 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
@@ -1,9 +1,13 @@
package com.alya.ecommerce_serang.ui.home
+import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
+import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
-import com.alya.ecommerce_serang.data.api.response.ProductsItem
+import com.alya.ecommerce_serang.BuildConfig.BASE_URL
+import com.alya.ecommerce_serang.R
+import com.alya.ecommerce_serang.data.api.dto.ProductsItem
import com.alya.ecommerce_serang.databinding.ItemProductHorizontalBinding
import com.bumptech.glide.Glide
@@ -16,17 +20,24 @@ class HorizontalProductAdapter(
RecyclerView.ViewHolder(binding.root) {
fun bind(product: ProductsItem) = with(binding) {
+
+ val fullImageUrl = if (product.image.startsWith("/")) {
+ BASE_URL + product.image.removePrefix("/") // Append base URL if the path starts with "/"
+ } else {
+ product.image // Use as is if it's already a full URL
+ }
+
+ Log.d("ProductAdapter", "Loading image: $fullImageUrl")
+
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)
+ .load(fullImageUrl)
+ .placeholder(R.drawable.placeholder_image)
+ .into(imageProduct)
root.setOnClickListener { onClick(product) }
}
@@ -46,7 +57,32 @@ class HorizontalProductAdapter(
}
fun updateProducts(newProducts: List) {
+ val diffCallback = ProductDiffCallback(products, newProducts)
+ val diffResult = DiffUtil.calculateDiff(diffCallback)
products = newProducts
- notifyDataSetChanged()
+ diffResult.dispatchUpdatesTo(this)
+ }
+
+ fun updateLimitedProducts(newProducts: List) {
+ val diffCallback = ProductDiffCallback(products, newProducts)
+ val limitedProducts = newProducts.take(10) // Limit to 10 items
+ val diffResult = DiffUtil.calculateDiff(diffCallback)
+ diffResult.dispatchUpdatesTo(this)
+ updateProducts(limitedProducts)
+ }
+
+ class ProductDiffCallback(
+ private val oldList: List,
+ private val newList: List
+ ) : DiffUtil.Callback() {
+
+ override fun getOldListSize() = oldList.size
+ override fun getNewListSize() = newList.size
+
+ override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
+ oldList[oldItemPosition].id == newList[newItemPosition].id // Compare unique IDs
+
+ override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
+ oldList[oldItemPosition] == newList[newItemPosition] // Compare entire object
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/alya/ecommerce_serang/ui/product/DetailProductActivity.kt b/app/src/main/java/com/alya/ecommerce_serang/ui/product/DetailProductActivity.kt
new file mode 100644
index 0000000..284f79d
--- /dev/null
+++ b/app/src/main/java/com/alya/ecommerce_serang/ui/product/DetailProductActivity.kt
@@ -0,0 +1,21 @@
+package com.alya.ecommerce_serang.ui.product
+
+import android.os.Bundle
+import androidx.activity.enableEdgeToEdge
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import com.alya.ecommerce_serang.R
+
+class DetailProductActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContentView(R.layout.activity_detail_product)
+ 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
+ }
+ }
+}
\ 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
deleted file mode 100644
index 43a7e0e..0000000
--- a/app/src/main/java/com/alya/ecommerce_serang/ui/product/ProductViewHolder.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-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/utils/ProductQuery.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/ProductQuery.kt
index 83f557e..e0cae06 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/utils/ProductQuery.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/ProductQuery.kt
@@ -1,12 +1,12 @@
package com.alya.ecommerce_serang.utils
import android.os.Parcelable
-import com.alya.ecommerce_serang.data.api.dto.Category
+import com.alya.ecommerce_serang.data.api.dto.CategoryItem
import kotlinx.parcelize.Parcelize
@Parcelize
data class ProductQuery (
- val category: Category? = null,
+ val category: CategoryItem,
val search:String? = null,
val range:Pair = 0f to 10000f,
val rating:Int? = null,
diff --git a/app/src/main/java/com/alya/ecommerce_serang/utils/SessionManager.kt b/app/src/main/java/com/alya/ecommerce_serang/utils/SessionManager.kt
index 52b405b..6feaa5c 100644
--- a/app/src/main/java/com/alya/ecommerce_serang/utils/SessionManager.kt
+++ b/app/src/main/java/com/alya/ecommerce_serang/utils/SessionManager.kt
@@ -19,7 +19,7 @@ class SessionManager(context: Context) {
}
fun getToken(): String? {
- val token = sharedPreferences.getString("auth_token", null)
+ val token = sharedPreferences.getString(USER_TOKEN, null)
Log.d("SessionManager", "Retrieved token: $token")
return token
}
diff --git a/app/src/main/res/layout/activity_detail_product.xml b/app/src/main/res/layout/activity_detail_product.xml
new file mode 100644
index 0000000..433367a
--- /dev/null
+++ b/app/src/main/res/layout/activity_detail_product.xml
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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
index 7cac89a..22ba7b6 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -92,7 +92,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="24dp"
- android:text="@string/new_products_text"
+ android:text="@string/sold_product_text"
android:textColor="@color/black"
android:textSize="22sp"
app:layout_constraintStart_toStartOf="parent"
diff --git a/app/src/main/res/layout/item_category_home.xml b/app/src/main/res/layout/item_category_home.xml
index 3a6604a..0f03704 100644
--- a/app/src/main/res/layout/item_category_home.xml
+++ b/app/src/main/res/layout/item_category_home.xml
@@ -17,7 +17,7 @@
diff --git a/app/src/main/res/layout/item_product_horizontal.xml b/app/src/main/res/layout/item_product_horizontal.xml
index bfae57b..dbc3c43 100644
--- a/app/src/main/res/layout/item_product_horizontal.xml
+++ b/app/src/main/res/layout/item_product_horizontal.xml
@@ -17,7 +17,7 @@
app:strokeWidth="1dp">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_review.xml b/app/src/main/res/layout/item_review.xml
new file mode 100644
index 0000000..8a22a07
--- /dev/null
+++ b/app/src/main/res/layout/item_review.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index af5beaa..7253878 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -46,4 +46,5 @@
Kata Sandi
Lupa Kata Sandi?
Masukkan Kode OTP
+ Produk Terlaris
\ No newline at end of file