diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..aa2b40b
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+Woka
\ No newline at end of file
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
new file mode 100644
index 0000000..63241c0
--- /dev/null
+++ b/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/other.xml b/.idea/other.xml
new file mode 100644
index 0000000..0d3a1fb
--- /dev/null
+++ b/.idea/other.xml
@@ -0,0 +1,263 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c75c7c6..cf07133 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -17,10 +17,13 @@
android:supportsRtl="true"
android:theme="@style/Theme.Woka"
tools:targetApi="31">
+
+ android:screenOrientation="portrait" />
(
+ DIFF_CONFIG
+ ) {
+
+ companion object {
+ private val DIFF_UTIL = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: BaseCategory, newItem: BaseCategory): Boolean =
+ oldItem.id == newItem.id
+
+ override fun areContentsTheSame(oldItem: BaseCategory, newItem: BaseCategory): Boolean =
+ oldItem == newItem
+ }
+
+ private val DIFF_CONFIG = AsyncDifferConfig.Builder(DIFF_UTIL)
+ .setBackgroundThreadExecutor(Executors.newSingleThreadExecutor())
+ .build()
+ }
+
+ inner class CategoryViewHolder(val binding: CategoryViweHolderBinding) :
+ ViewHolder(binding.root)
+
+ var onCategoryClickListener: ((BaseCategory) -> Unit)? = null
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryViewHolder {
+ return CategoryViewHolder(
+ CategoryViweHolderBinding.inflate(
+ LayoutInflater.from(parent.context),
+ parent,
+ false
+ )
+ )
+ }
+
+ override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) {
+ val category = getItem(holder.absoluteAdapterPosition)
+
+ holder.binding.apply {
+ image.loadImage(category.imageUrl)
+ title.text = category.title
+
+ holder.binding.root.setOnClickListener {
+ onCategoryClickListener?.invoke(category)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/shop/models/BaseCategory.kt b/app/src/main/java/com/woka/shop/models/BaseCategory.kt
new file mode 100644
index 0000000..3440619
--- /dev/null
+++ b/app/src/main/java/com/woka/shop/models/BaseCategory.kt
@@ -0,0 +1,7 @@
+package com.woka.shop.models
+
+data class BaseCategory(
+ val id: Int?,
+ val imageUrl: String?,
+ val title: String?
+)
diff --git a/app/src/main/java/com/woka/shop/models/subcategorylisting/SubCategoryResponse.kt b/app/src/main/java/com/woka/shop/models/subcategorylisting/SubCategoryResponse.kt
index e3f1a08..80f1552 100644
--- a/app/src/main/java/com/woka/shop/models/subcategorylisting/SubCategoryResponse.kt
+++ b/app/src/main/java/com/woka/shop/models/subcategorylisting/SubCategoryResponse.kt
@@ -1,6 +1,6 @@
package com.woka.shop.models.subcategorylisting
data class SubCategoryResponse(
- val subCategory: List?,
+ val result: List?,
val total_records: Int?
)
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/shop/viewmodels/ShopViewModel.kt b/app/src/main/java/com/woka/shop/viewmodels/ShopViewModel.kt
index 0d891d7..5897d39 100644
--- a/app/src/main/java/com/woka/shop/viewmodels/ShopViewModel.kt
+++ b/app/src/main/java/com/woka/shop/viewmodels/ShopViewModel.kt
@@ -63,6 +63,10 @@ class ShopViewModel: ViewModel() {
}
}
+ fun clearCategoryLiveData(){
+ _categoryLiveData.postValue(ApiResult.Loading())
+ }
+
// sub category listing
private val _subcategoryLiveData = MutableLiveData>>()
val subcategoryLiveData: LiveData>>
@@ -82,7 +86,7 @@ class ShopViewModel: ViewModel() {
is ApiResult.Error -> _subcategoryLiveData.postValue(ApiResult.Error(response.errorMessage, response.error))
is ApiResult.Loading -> {}
is ApiResult.Success -> {
- response.data?.subCategory?.filterNotNull()?.toMutableList()?.let {
+ response.data?.result?.filterNotNull()?.toMutableList()?.let {
subcategoryDataMap[categoryId] = it
_subcategoryLiveData.postValue(ApiResult.Success(it))
}
@@ -90,4 +94,8 @@ class ShopViewModel: ViewModel() {
}
}
}
+
+ fun clearSubCategoryLiveData(){
+ _subcategoryLiveData.postValue(ApiResult.Loading())
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/shop/views/ShopActivity.kt b/app/src/main/java/com/woka/shop/views/ShopActivity.kt
new file mode 100644
index 0000000..9eafc58
--- /dev/null
+++ b/app/src/main/java/com/woka/shop/views/ShopActivity.kt
@@ -0,0 +1,51 @@
+package com.woka.shop.views
+
+import android.os.Bundle
+import androidx.activity.enableEdgeToEdge
+import androidx.core.view.ViewCompat
+import androidx.core.view.WindowInsetsCompat
+import com.woka.R
+import com.woka.databinding.ActivityShopBinding
+import com.woka.shop.views.fragments.ShopFragment1
+import com.woka.utils.WokaBaseActivity
+
+class ShopActivity : WokaBaseActivity() {
+
+ private lateinit var binding: ActivityShopBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ binding = ActivityShopBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ 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
+ }
+
+ window.navigationBarColor = getColor(R.color.orders_bg)
+
+ supportFragmentManager.beginTransaction()
+ .add(R.id.fcv_shop, ShopFragment1.newInstance())
+ .commit()
+
+ initViews()
+
+ clickEvents()
+ }
+
+ private fun initViews(){
+ binding.apply {
+ title.text = getString(R.string.shop)
+ }
+ }
+
+ private fun clickEvents(){
+ binding.apply {
+ backBtn.setOnClickListener {
+ onBackPressedDispatcher.onBackPressed()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/shop/views/fragments/ShopFragment1.kt b/app/src/main/java/com/woka/shop/views/fragments/ShopFragment1.kt
new file mode 100644
index 0000000..e298567
--- /dev/null
+++ b/app/src/main/java/com/woka/shop/views/fragments/ShopFragment1.kt
@@ -0,0 +1,113 @@
+package com.woka.shop.views.fragments
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.woka.R
+import com.woka.databinding.FragmentShop1Binding
+import com.woka.networking.ApiResult
+import com.woka.shop.adapters.CategoryAdapter
+import com.woka.shop.models.BaseCategory
+import com.woka.shop.viewmodels.ShopViewModel
+import com.woka.utils.hide
+import com.woka.utils.show
+
+class ShopFragment1 private constructor(): Fragment() {
+
+ private lateinit var binding: FragmentShop1Binding
+ private lateinit var viewModel: ShopViewModel
+ private lateinit var adapter: CategoryAdapter
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentShop1Binding.inflate(inflater, container, false)
+ viewModel = ViewModelProvider(requireActivity())[ShopViewModel::class.java]
+ adapter = CategoryAdapter()
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ initViews()
+
+ clickEvents()
+
+ setObservers()
+
+ if (!viewModel.superCategoryLiveData.isInitialized ||
+ viewModel.superCategoryLiveData.value !is ApiResult.Success) {
+
+ viewModel.loadSuperCategories()
+ }
+ }
+
+ private fun initViews() {
+ binding.apply {
+ rvSuperCategory.adapter = adapter
+ }
+ }
+
+ private fun clickEvents() {
+ binding.apply {
+ retryButton.setOnClickListener {
+ viewModel.loadSuperCategories()
+ }
+
+ adapter.onCategoryClickListener = {
+ parentFragmentManager.beginTransaction()
+ .replace(R.id.fcv_shop, ShopFragment2.newInstance("${it.id}"))
+ .addToBackStack(null)
+ .commitAllowingStateLoss()
+ }
+ }
+ }
+
+ private fun setObservers() {
+ with(binding) {
+ viewModel.superCategoryLiveData.observe(viewLifecycleOwner) {
+ when (it) {
+ is ApiResult.Error -> {
+ rvSuperCategory.hide()
+ shimmer.hide()
+ errorView.show()
+ }
+
+ is ApiResult.Loading -> {
+ rvSuperCategory.hide()
+ shimmer.show()
+ errorView.hide()
+ }
+
+ is ApiResult.Success -> {
+ it.data?.let { categoryList ->
+ adapter.submitList(categoryList.map { category ->
+ BaseCategory(
+ category.id,
+ category.super_category_thumbnail,
+ category.super_category_name
+ )
+ }
+ ) {
+ rvSuperCategory.show()
+
+ shimmer.hide()
+ errorView.hide()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ fun newInstance() = ShopFragment1()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/shop/views/fragments/ShopFragment2.kt b/app/src/main/java/com/woka/shop/views/fragments/ShopFragment2.kt
new file mode 100644
index 0000000..a140d85
--- /dev/null
+++ b/app/src/main/java/com/woka/shop/views/fragments/ShopFragment2.kt
@@ -0,0 +1,114 @@
+package com.woka.shop.views.fragments
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.woka.R
+import com.woka.databinding.FragmentShop2Binding
+import com.woka.networking.ApiResult
+import com.woka.shop.adapters.CategoryAdapter
+import com.woka.shop.models.BaseCategory
+import com.woka.shop.viewmodels.ShopViewModel
+import com.woka.utils.hide
+import com.woka.utils.show
+
+class ShopFragment2 private constructor(private val superCategoryId: String): Fragment() {
+
+ private lateinit var binding: FragmentShop2Binding
+ private lateinit var viewModel: ShopViewModel
+ private lateinit var adapter: CategoryAdapter
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentShop2Binding.inflate(inflater, container, false)
+ viewModel = ViewModelProvider(requireActivity())[ShopViewModel::class.java]
+ adapter = CategoryAdapter()
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ initViews()
+
+ clickEvents()
+
+ setObservers()
+
+ viewModel.loadCategories(superCategoryId)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ viewModel.clearCategoryLiveData()
+ }
+
+ private fun initViews() {
+ binding.apply {
+ rvCategory.adapter = adapter
+ }
+ }
+
+ private fun clickEvents() {
+ binding.apply {
+ retryButton.setOnClickListener {
+ viewModel.loadCategories(superCategoryId)
+ }
+
+ adapter.onCategoryClickListener = {
+ parentFragmentManager.beginTransaction()
+ .replace(R.id.fcv_shop, ShopFragment3.newInstance("${it.id}"))
+ .addToBackStack(null)
+ .commitAllowingStateLoss()
+ }
+ }
+ }
+
+ private fun setObservers() {
+ with(binding) {
+ viewModel.categoryLiveData.observe(viewLifecycleOwner) {
+ when (it) {
+ is ApiResult.Error -> {
+ rvCategory.hide()
+ shimmer.hide()
+ errorView.show()
+ }
+
+ is ApiResult.Loading -> {
+ rvCategory.hide()
+ shimmer.show()
+ errorView.hide()
+ }
+
+ is ApiResult.Success -> {
+ it.data?.let { categoryList ->
+ adapter.submitList(categoryList.map { category ->
+ BaseCategory(
+ category.id,
+ category.category_thumbnail,
+ category.category_name
+ )
+ }
+ ) {
+ rvCategory.show()
+
+ shimmer.hide()
+ errorView.hide()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ fun newInstance(superCategoryId: String) = ShopFragment2(superCategoryId)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/woka/shop/views/fragments/ShopFragment3.kt b/app/src/main/java/com/woka/shop/views/fragments/ShopFragment3.kt
new file mode 100644
index 0000000..b98d998
--- /dev/null
+++ b/app/src/main/java/com/woka/shop/views/fragments/ShopFragment3.kt
@@ -0,0 +1,110 @@
+package com.woka.shop.views.fragments
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.woka.databinding.FragmentShop3Binding
+import com.woka.networking.ApiResult
+import com.woka.shop.adapters.CategoryAdapter
+import com.woka.shop.models.BaseCategory
+import com.woka.shop.viewmodels.ShopViewModel
+import com.woka.utils.hide
+import com.woka.utils.show
+
+class ShopFragment3 private constructor(private val categoryId: String): Fragment() {
+
+ private lateinit var binding: FragmentShop3Binding
+ private lateinit var viewModel: ShopViewModel
+ private lateinit var adapter: CategoryAdapter
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentShop3Binding.inflate(inflater, container, false)
+ viewModel = ViewModelProvider(requireActivity())[ShopViewModel::class.java]
+ adapter = CategoryAdapter()
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ initViews()
+
+ clickEvents()
+
+ setObservers()
+
+ viewModel.loadSubCategories(categoryId)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ viewModel.clearSubCategoryLiveData()
+ }
+
+ private fun initViews() {
+ binding.apply {
+ rvCategory.adapter = adapter
+ }
+ }
+
+ private fun clickEvents() {
+ binding.apply {
+ retryButton.setOnClickListener {
+ viewModel.loadSubCategories(categoryId)
+ }
+
+ adapter.onCategoryClickListener = {
+
+ }
+ }
+ }
+
+ private fun setObservers() {
+ with(binding) {
+ viewModel.subcategoryLiveData.observe(viewLifecycleOwner) {
+ when (it) {
+ is ApiResult.Error -> {
+ rvCategory.hide()
+ shimmer.hide()
+ errorView.show()
+ }
+
+ is ApiResult.Loading -> {
+ rvCategory.hide()
+ shimmer.show()
+ errorView.hide()
+ }
+
+ is ApiResult.Success -> {
+ it.data?.let { categoryList ->
+ adapter.submitList(categoryList.map { category ->
+ BaseCategory(
+ category.id,
+ category.sub_category_thumbnail,
+ category.sub_category_name
+ )
+ }
+ ) {
+ rvCategory.show()
+
+ shimmer.hide()
+ errorView.hide()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ fun newInstance(categoryId: String) = ShopFragment3(categoryId)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_shop.xml b/app/src/main/res/layout/activity_shop.xml
new file mode 100644
index 0000000..0055282
--- /dev/null
+++ b/app/src/main/res/layout/activity_shop.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/category_viwe_holder.xml b/app/src/main/res/layout/category_viwe_holder.xml
new file mode 100644
index 0000000..65375c3
--- /dev/null
+++ b/app/src/main/res/layout/category_viwe_holder.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_shop1.xml b/app/src/main/res/layout/fragment_shop1.xml
new file mode 100644
index 0000000..343090e
--- /dev/null
+++ b/app/src/main/res/layout/fragment_shop1.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_shop2.xml b/app/src/main/res/layout/fragment_shop2.xml
new file mode 100644
index 0000000..22a1b16
--- /dev/null
+++ b/app/src/main/res/layout/fragment_shop2.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_shop3.xml b/app/src/main/res/layout/fragment_shop3.xml
new file mode 100644
index 0000000..22a1b16
--- /dev/null
+++ b/app/src/main/res/layout/fragment_shop3.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file