diff --git a/app/src/main/java/com/example/egobook_frontent/MainActivity.kt b/app/src/main/java/com/example/egobook_frontent/MainActivity.kt index 80a4a852..ff5491cb 100644 --- a/app/src/main/java/com/example/egobook_frontent/MainActivity.kt +++ b/app/src/main/java/com/example/egobook_frontent/MainActivity.kt @@ -40,7 +40,8 @@ class MainActivity : AppCompatActivity(), BlurController { when (destination.id) { R.id.onboardingContainerFragment, // 온보딩 화면 R.id.diaryWriteFragment, // 일기 작성 화면 - R.id.candlerFragment // 달력 화면 + R.id.candlerFragment, // 달력 화면 + R.id.storeFragment, -> { binding.bottomNavigation.visibility = View.GONE } diff --git a/app/src/main/java/com/example/egobook_frontent/ui/shop/.gitkeep b/app/src/main/java/com/example/egobook_frontent/ui/shop/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/src/main/java/com/example/egobook_frontent/ui/shop/CustomItem.kt b/app/src/main/java/com/example/egobook_frontent/ui/shop/CustomItem.kt new file mode 100644 index 00000000..a1c804d9 --- /dev/null +++ b/app/src/main/java/com/example/egobook_frontent/ui/shop/CustomItem.kt @@ -0,0 +1,3 @@ +package com.example.egobook_frontent.ui.shop + +data class CustomItem(val id: String, val type: ItemType, val price: Price, val itemStatus: ItemStatus) diff --git a/app/src/main/java/com/example/egobook_frontent/ui/shop/ItemAdapter.kt b/app/src/main/java/com/example/egobook_frontent/ui/shop/ItemAdapter.kt new file mode 100644 index 00000000..b756556c --- /dev/null +++ b/app/src/main/java/com/example/egobook_frontent/ui/shop/ItemAdapter.kt @@ -0,0 +1,62 @@ +package com.example.egobook_frontent.ui.shop + +import android.R.attr.left +import android.view.LayoutInflater +import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.view.updatePadding +import androidx.recyclerview.widget.RecyclerView +import com.example.egobook_frontent.R + +class ItemAdapter(private val items: List) : + RecyclerView.Adapter() { + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): ItemViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.view_holder_store_item, parent, false) + + return ItemViewHolder(view) + } + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + holder.binding(items[position]) + } + + override fun getItemCount() = items.size + + class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + val itemStatus: TextView = view.findViewById(R.id.tv_item_status) + val itemPriceIcon: ImageView = view.findViewById(R.id.iv_store_item_ink) + val itemInfoLayout: LinearLayout = view.findViewById(R.id.ll_item_info) + val root: View = view.rootView + + fun binding(item: CustomItem) { + when (item.itemStatus) { + ItemStatus.PURCHASED -> { + itemStatus.text = "보유중" + itemInfoLayout.setPadding(24,6,24,6) + itemPriceIcon.visibility = GONE + } + ItemStatus.SUBSCRIBE_ONLY -> { + itemStatus.text = "구독전용" + itemInfoLayout.setPadding(24,6,24,6) + itemPriceIcon.visibility = GONE + root.background = null + } + ItemStatus.PURCHASABLE -> { + itemStatus.text = item.price.toString() + itemInfoLayout.updatePadding(left=12, right=16) + itemPriceIcon.visibility = VISIBLE + root.background = null + } + } + } + } +} diff --git a/app/src/main/java/com/example/egobook_frontent/ui/shop/ItemStatus.kt b/app/src/main/java/com/example/egobook_frontent/ui/shop/ItemStatus.kt new file mode 100644 index 00000000..c3946864 --- /dev/null +++ b/app/src/main/java/com/example/egobook_frontent/ui/shop/ItemStatus.kt @@ -0,0 +1,7 @@ +package com.example.egobook_frontent.ui.shop + +enum class ItemStatus { + PURCHASABLE, + PURCHASED, + SUBSCRIBE_ONLY +} diff --git a/app/src/main/java/com/example/egobook_frontent/ui/shop/Price.kt b/app/src/main/java/com/example/egobook_frontent/ui/shop/Price.kt new file mode 100644 index 00000000..2d4f5ac7 --- /dev/null +++ b/app/src/main/java/com/example/egobook_frontent/ui/shop/Price.kt @@ -0,0 +1,9 @@ +package com.example.egobook_frontent.ui.shop + +@JvmInline +value class Price(val value: Int) { + init { + require(value >= 0) { "가격은 음수일 수 없습니다" } + } + override fun toString() = value.toString() +} diff --git a/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreCollectionFragment.kt b/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreCollectionFragment.kt index 3f40ba06..48d88a87 100644 --- a/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreCollectionFragment.kt +++ b/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreCollectionFragment.kt @@ -6,7 +6,10 @@ import android.view.View import android.view.ViewGroup import androidx.core.os.BundleCompat import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.GridLayoutManager import com.example.egobook_frontent.databinding.FragmentStoreCollectionBinding +import kotlin.getValue class StoreCollectionFragment(): Fragment() { private var _binding: FragmentStoreCollectionBinding? = null @@ -22,11 +25,16 @@ class StoreCollectionFragment(): Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + val viewModel: StoreViewModel by viewModels() val targetBundle = checkNotNull(arguments) { "구현 오류: 올바른 탭을 표시하기 위해 번들은 필수입니다"} val tabItem = checkNotNull(BundleCompat.getParcelable(targetBundle, ItemTab.BUNDLE_KEY, ItemTab::class.java)) { "구현 오류: 올바른 탭을 표시하기 위해 tabItem을 번들을 통해 넘겨야 합니다." } - binding.test.text = tabItem.text + + binding.rvItems.apply { + adapter = ItemAdapter(viewModel.loadItems(tabItem.type)) + layoutManager = GridLayoutManager(context, 3) + } } override fun onDestroyView() { diff --git a/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreFragment.kt b/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreFragment.kt index c58a8b3d..4d7cfb64 100644 --- a/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreFragment.kt +++ b/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreFragment.kt @@ -4,7 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.viewpager2.widget.ViewPager2 import com.example.egobook_frontent.R @@ -27,6 +30,12 @@ class StoreFragment: Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets -> + val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + v.setPadding(0, 0, 0, systemBars.bottom) + insets + } + viewPager = binding.vp2StoreCollectionContainer viewPager.adapter = StoreCollectionAdapter(this) val tabLayout = binding.tlTabs @@ -37,6 +46,7 @@ class StoreFragment: Fragment() { binding.ivBack.setOnClickListener { findNavController().navigate(R.id.action_storeFragment_to_homeFragment) } + } override fun onDestroyView() { diff --git a/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreViewModel.kt b/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreViewModel.kt new file mode 100644 index 00000000..1aede4b4 --- /dev/null +++ b/app/src/main/java/com/example/egobook_frontent/ui/shop/StoreViewModel.kt @@ -0,0 +1,27 @@ +package com.example.egobook_frontent.ui.shop + +import androidx.lifecycle.ViewModel + +class StoreViewModel: ViewModel() { + val temporalData = listOf( + CustomItem("1", ItemType.BACK, Price(100), ItemStatus.PURCHASABLE), + CustomItem("2", ItemType.BACK, Price(50), ItemStatus.PURCHASED), + CustomItem("3", ItemType.BACK, Price(40), ItemStatus.PURCHASABLE), + CustomItem("4", ItemType.BACK, Price(150), ItemStatus.SUBSCRIBE_ONLY), + CustomItem("5", ItemType.BACK, Price(30), ItemStatus.PURCHASABLE), + CustomItem("6", ItemType.BACK, Price(10), ItemStatus.PURCHASED), + CustomItem("7", ItemType.BACK, Price(190), ItemStatus.SUBSCRIBE_ONLY), + CustomItem("8", ItemType.BACK, Price(200), ItemStatus.PURCHASED), + CustomItem("9", ItemType.BACK, Price(300), ItemStatus.SUBSCRIBE_ONLY), + CustomItem("10", ItemType.DECO_1, Price(590), ItemStatus.SUBSCRIBE_ONLY), + CustomItem("11", ItemType.DECO_2, Price(600), ItemStatus.PURCHASED), + CustomItem("12", ItemType.SKIN, Price(700), ItemStatus.SUBSCRIBE_ONLY), + CustomItem("13", ItemType.BACKGROUND, Price(222), ItemStatus.PURCHASABLE), + CustomItem("14", ItemType.BACKGROUND, Price(444), ItemStatus.PURCHASABLE), + ) + fun loadItems(type: ItemType): List { + return temporalData.filter { customItem -> + customItem.type == type + } + } +} diff --git a/app/src/main/res/drawable/reset_icon.xml b/app/src/main/res/drawable/reset_icon.xml new file mode 100644 index 00000000..71d1cd1b --- /dev/null +++ b/app/src/main/res/drawable/reset_icon.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/src/main/res/drawable/store_item_selection_border.xml b/app/src/main/res/drawable/store_item_selection_border.xml new file mode 100644 index 00000000..434250d8 --- /dev/null +++ b/app/src/main/res/drawable/store_item_selection_border.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/src/main/res/drawable/store_item_status_border.xml b/app/src/main/res/drawable/store_item_status_border.xml new file mode 100644 index 00000000..96c9846c --- /dev/null +++ b/app/src/main/res/drawable/store_item_status_border.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/store_purchase_button.xml b/app/src/main/res/drawable/store_purchase_button.xml new file mode 100644 index 00000000..08e676da --- /dev/null +++ b/app/src/main/res/drawable/store_purchase_button.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/fragment_store.xml b/app/src/main/res/layout/fragment_store.xml index eaa738ba..4f453329 100644 --- a/app/src/main/res/layout/fragment_store.xml +++ b/app/src/main/res/layout/fragment_store.xml @@ -3,7 +3,17 @@ android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" - android:background="@drawable/default_background"> + android:background="@color/layer_white"> + + + + + + + + diff --git a/app/src/main/res/layout/fragment_store_collection.xml b/app/src/main/res/layout/fragment_store_collection.xml index 6ff6aa2e..725600b2 100644 --- a/app/src/main/res/layout/fragment_store_collection.xml +++ b/app/src/main/res/layout/fragment_store_collection.xml @@ -4,14 +4,16 @@ android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="@color/white"> - - + app:layout_constraintEnd_toEndOf="parent" + android:layout_marginStart="12dp" + android:layout_marginEnd="12dp"/> diff --git a/app/src/main/res/layout/view_holder_store_item.xml b/app/src/main/res/layout/view_holder_store_item.xml new file mode 100644 index 00000000..ccea4d2a --- /dev/null +++ b/app/src/main/res/layout/view_holder_store_item.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/test/java/com/example/egobook_frontent/StoreTest.kt b/app/src/test/java/com/example/egobook_frontent/StoreTest.kt new file mode 100644 index 00000000..a13e9480 --- /dev/null +++ b/app/src/test/java/com/example/egobook_frontent/StoreTest.kt @@ -0,0 +1,13 @@ +package com.example.egobook_frontent + +import com.example.egobook_frontent.ui.shop.Price +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.Test + +class StoreTest { + @Test + fun `아이템 가격은 음수가 될 수 없다`() { + assertThatThrownBy { Price(-1) } + .isInstanceOf(IllegalArgumentException::class.java) + } +}