diff --git a/week2/.idea/deviceManager.xml b/week2/.idea/deviceManager.xml new file mode 100644 index 0000000..91f9558 --- /dev/null +++ b/week2/.idea/deviceManager.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/week2/.idea/misc.xml b/week2/.idea/misc.xml index 74dd639..34e8f59 100644 --- a/week2/.idea/misc.xml +++ b/week2/.idea/misc.xml @@ -7,4 +7,11 @@ + + + \ No newline at end of file diff --git a/week2/app/build.gradle.kts b/week2/app/build.gradle.kts index 4d5cf39..6a859c7 100644 --- a/week2/app/build.gradle.kts +++ b/week2/app/build.gradle.kts @@ -2,6 +2,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.compose.compiler) + id("kotlin-parcelize") } android { diff --git a/week2/app/src/main/java/com/example/week2/HomeFragment.kt b/week2/app/src/main/java/com/example/week2/HomeFragment.kt index 316bc0b..6905b6a 100644 --- a/week2/app/src/main/java/com/example/week2/HomeFragment.kt +++ b/week2/app/src/main/java/com/example/week2/HomeFragment.kt @@ -5,6 +5,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager import com.example.week2.databinding.FragmentHomeBinding class HomeFragment : Fragment() { @@ -19,6 +21,41 @@ class HomeFragment : Fragment() { return binding.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupRecyclerView() + } + + private fun setupRecyclerView() { + val dummyProducts = listOf( + Product(1, "Air Jordan XXXVI", "Basketball Shoes", "US$185", R.drawable.img_air_jordan_xxxvi, category = "Basketball Shoes"), + Product(2, "Nike Air Force 1 '07", "Men's Shoes", "US$115", R.drawable.img_nike_air_force, category = "Men's Shoes"), + Product(3, "Nike Everyday Plus Cushioned", "Training Socks", "US$20", R.drawable.img_nike_everyday_plus_cushioned, category = "Training Socks") + ) + + val adapter = ProductAdapter( + dummyProducts, + onItemClick = { product -> + navigateToDetail(product) + }, + onWishlistClick = { product, position -> + product.isWishlisted = !product.isWishlisted + binding.rvHomeProducts.adapter?.notifyItemChanged(position) + } + ) + + binding.rvHomeProducts.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + binding.rvHomeProducts.adapter = adapter + } + + private fun navigateToDetail(product: Product) { + // Navigation Component를 사용하여 상세 화면으로 이동 + val bundle = Bundle().apply { + putParcelable("product", product) + } + findNavController().navigate(R.id.action_homeFragment_to_productDetailFragment, bundle) + } + override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/week2/app/src/main/java/com/example/week2/Product.kt b/week2/app/src/main/java/com/example/week2/Product.kt new file mode 100644 index 0000000..3a45829 --- /dev/null +++ b/week2/app/src/main/java/com/example/week2/Product.kt @@ -0,0 +1,15 @@ +package com.example.week2 + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class Product( + val id: Int, + val name: String, + val description: String, + val price: String, + val imageResId: Int, + var isWishlisted: Boolean = false, + val category: String = "" +) : Parcelable diff --git a/week2/app/src/main/java/com/example/week2/ProductAdapter.kt b/week2/app/src/main/java/com/example/week2/ProductAdapter.kt new file mode 100644 index 0000000..9761741 --- /dev/null +++ b/week2/app/src/main/java/com/example/week2/ProductAdapter.kt @@ -0,0 +1,45 @@ +package com.example.week2 + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.example.week2.databinding.ItemProductBinding + +class ProductAdapter( + private val products: List, + private val onItemClick: (Product) -> Unit, + private val onWishlistClick: (Product, Int) -> Unit +) : RecyclerView.Adapter() { + + inner class ProductViewHolder(private val binding: ItemProductBinding) : + RecyclerView.ViewHolder(binding.root) { + + fun bind(product: Product) { + binding.tvProductName.text = product.name + binding.tvProductDesc.text = product.description + binding.tvProductPrice.text = product.price + binding.ivProductImage.setImageResource(product.imageResId) + + val heartRes = if (product.isWishlisted) { + R.drawable.ic_heart_fill + } else { + R.drawable.ic_heart_empty + } + binding.ibWishlist.setImageResource(heartRes) + + binding.root.setOnClickListener { onItemClick(product) } + binding.ibWishlist.setOnClickListener { onWishlistClick(product, adapterPosition) } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder { + val binding = ItemProductBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ProductViewHolder(binding) + } + + override fun onBindViewHolder(holder: ProductViewHolder, position: Int) { + holder.bind(products[position]) + } + + override fun getItemCount(): Int = products.size +} diff --git a/week2/app/src/main/java/com/example/week2/ProductDetailFragment.kt b/week2/app/src/main/java/com/example/week2/ProductDetailFragment.kt new file mode 100644 index 0000000..ffd72c3 --- /dev/null +++ b/week2/app/src/main/java/com/example/week2/ProductDetailFragment.kt @@ -0,0 +1,58 @@ +package com.example.week2 + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import com.example.week2.databinding.FragmentProductDetailBinding + +class ProductDetailFragment : Fragment() { + private var _binding: FragmentProductDetailBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentProductDetailBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val product = arguments?.getParcelable("product") + + product?.let { + binding.tvHeaderTitle.text = it.name + binding.ivDetailImage.setImageResource(it.imageResId) + binding.tvDetailCategory.text = it.category + binding.tvDetailName.text = it.name + binding.tvDetailPrice.text = it.price + + updateWishlistButton(it.isWishlisted) + } + + binding.ibBack.setOnClickListener { + findNavController().popBackStack() + } + + binding.btnWishlist.setOnClickListener { + product?.let { + it.isWishlisted = !it.isWishlisted + updateWishlistButton(it.isWishlisted) + } + } + } + + private fun updateWishlistButton(isWishlisted: Boolean) { + binding.ivWishlistHeart.isSelected = isWishlisted + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/week2/app/src/main/java/com/example/week2/PurchaseFragment.kt b/week2/app/src/main/java/com/example/week2/PurchaseFragment.kt index 6e9ae28..fec46e5 100644 --- a/week2/app/src/main/java/com/example/week2/PurchaseFragment.kt +++ b/week2/app/src/main/java/com/example/week2/PurchaseFragment.kt @@ -5,6 +5,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.GridLayoutManager import com.example.week2.databinding.FragmentPurchaseBinding class PurchaseFragment : Fragment() { @@ -19,6 +21,42 @@ class PurchaseFragment : Fragment() { return binding.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupRecyclerView() + } + + private fun setupRecyclerView() { + val dummyProducts = listOf( + Product(1, "Nike Everyday Plus Cushioned", "Training Crew Socks (6 Pairs)", "US$10", R.drawable.img_nike_everyday_plus_cushioned, category = "Training Crew Socks"), + Product(2, "Nike Elite Crew", "Basketball Socks", "US$16", R.drawable.img_training_ankle_socks, category = "Basketball Socks"), + Product(3, "Nike Air Force 1 '07", "Women's Shoes", "US$115", R.drawable.img_nike_air_force, category = "Women's Shoes"), + Product(4, "Jordan Nike Air Force 1 '07 Essentials", "Men's Shoes", "US$115", R.drawable.img_air_jordan_xxxvi, category = "Men's Shoes") + ) + + val adapter = ProductAdapter( + dummyProducts, + onItemClick = { product -> + navigateToDetail(product) + }, + onWishlistClick = { product, position -> + product.isWishlisted = !product.isWishlisted + binding.rvPurchaseProducts.adapter?.notifyItemChanged(position) + } + ) + + binding.rvPurchaseProducts.layoutManager = GridLayoutManager(context, 2) + binding.rvPurchaseProducts.adapter = adapter + } + + private fun navigateToDetail(product: Product) { + // Navigation Component를 사용하여 상세 화면으로 이동 + val bundle = Bundle().apply { + putParcelable("product", product) + } + findNavController().navigate(R.id.action_purchaseFragment_to_productDetailFragment, bundle) + } + override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/week2/app/src/main/java/com/example/week2/WishlistFragment.kt b/week2/app/src/main/java/com/example/week2/WishlistFragment.kt index 44f97db..000b4a4 100644 --- a/week2/app/src/main/java/com/example/week2/WishlistFragment.kt +++ b/week2/app/src/main/java/com/example/week2/WishlistFragment.kt @@ -4,7 +4,9 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.GridLayoutManager import com.example.week2.databinding.FragmentWishlistBinding class WishlistFragment : Fragment() { @@ -19,6 +21,39 @@ class WishlistFragment : Fragment() { return binding.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupRecyclerView() + } + + private fun setupRecyclerView() { + // Dummy wishlist data + val dummyWishlist = mutableListOf( + Product(1, "Nike Everyday Plus Cushioned", "Training Ankle Socks (6 Pairs)", "US$16", R.drawable.img_training_ankle_socks, true), + Product(2, "Air Jordan XXXVI", "Basketball Shoes", "US$185", R.drawable.img_air_jordan_xxxvi, true) + ) + + val adapter = ProductAdapter( + dummyWishlist, + onItemClick = { product -> + Toast.makeText(context, "${product.name} clicked", Toast.LENGTH_SHORT).show() + }, + onWishlistClick = { product, position -> + product.isWishlisted = !product.isWishlisted + // In wishlist fragment, usually removing from wishlist means removing from the list + if (!product.isWishlisted) { + dummyWishlist.removeAt(position) + binding.rvWishlistProducts.adapter?.notifyItemRemoved(position) + } else { + binding.rvWishlistProducts.adapter?.notifyItemChanged(position) + } + } + ) + + binding.rvWishlistProducts.layoutManager = GridLayoutManager(context, 2) + binding.rvWishlistProducts.adapter = adapter + } + override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/week2/app/src/main/res/drawable/bg_black_round.xml b/week2/app/src/main/res/drawable/bg_black_round.xml new file mode 100644 index 0000000..fcc2357 --- /dev/null +++ b/week2/app/src/main/res/drawable/bg_black_round.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/week2/app/src/main/res/drawable/bg_white_stroke.xml b/week2/app/src/main/res/drawable/bg_white_stroke.xml new file mode 100644 index 0000000..4f8e667 --- /dev/null +++ b/week2/app/src/main/res/drawable/bg_white_stroke.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/week2/app/src/main/res/drawable/ic_caretleft.xml b/week2/app/src/main/res/drawable/ic_caretleft.xml new file mode 100644 index 0000000..1912c2d --- /dev/null +++ b/week2/app/src/main/res/drawable/ic_caretleft.xml @@ -0,0 +1,17 @@ + + + + + + diff --git a/week2/app/src/main/res/drawable/ic_heart_empty.xml b/week2/app/src/main/res/drawable/ic_heart_empty.xml new file mode 100644 index 0000000..a7904b5 --- /dev/null +++ b/week2/app/src/main/res/drawable/ic_heart_empty.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/week2/app/src/main/res/drawable/ic_heart_fill.xml b/week2/app/src/main/res/drawable/ic_heart_fill.xml new file mode 100644 index 0000000..91664d4 --- /dev/null +++ b/week2/app/src/main/res/drawable/ic_heart_fill.xml @@ -0,0 +1,23 @@ + + + + + + + + diff --git a/week2/app/src/main/res/drawable/ic_heart_filled.xml b/week2/app/src/main/res/drawable/ic_heart_filled.xml new file mode 100644 index 0000000..67df58b --- /dev/null +++ b/week2/app/src/main/res/drawable/ic_heart_filled.xml @@ -0,0 +1,17 @@ + + + + + + diff --git a/week2/app/src/main/res/drawable/ic_magnifyingglass.xml b/week2/app/src/main/res/drawable/ic_magnifyingglass.xml new file mode 100644 index 0000000..9077a42 --- /dev/null +++ b/week2/app/src/main/res/drawable/ic_magnifyingglass.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/week2/app/src/main/res/drawable/img_air_jordan_xxxvi.png b/week2/app/src/main/res/drawable/img_air_jordan_xxxvi.png new file mode 100644 index 0000000..19129df Binary files /dev/null and b/week2/app/src/main/res/drawable/img_air_jordan_xxxvi.png differ diff --git a/week2/app/src/main/res/drawable/img_nike_air_force.png b/week2/app/src/main/res/drawable/img_nike_air_force.png new file mode 100644 index 0000000..1fc5039 Binary files /dev/null and b/week2/app/src/main/res/drawable/img_nike_air_force.png differ diff --git a/week2/app/src/main/res/drawable/img_nike_everyday_plus_cushioned.png b/week2/app/src/main/res/drawable/img_nike_everyday_plus_cushioned.png new file mode 100644 index 0000000..9a23c22 Binary files /dev/null and b/week2/app/src/main/res/drawable/img_nike_everyday_plus_cushioned.png differ diff --git a/week2/app/src/main/res/drawable/img_training_ankle_socks.png b/week2/app/src/main/res/drawable/img_training_ankle_socks.png new file mode 100644 index 0000000..04a81da Binary files /dev/null and b/week2/app/src/main/res/drawable/img_training_ankle_socks.png differ diff --git a/week2/app/src/main/res/drawable/sl_item_wishlist_icon.xml b/week2/app/src/main/res/drawable/sl_item_wishlist_icon.xml new file mode 100644 index 0000000..7ca06ad --- /dev/null +++ b/week2/app/src/main/res/drawable/sl_item_wishlist_icon.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/week2/app/src/main/res/drawable/sl_wishlist_icon.xml b/week2/app/src/main/res/drawable/sl_wishlist_icon.xml new file mode 100644 index 0000000..3e176b9 --- /dev/null +++ b/week2/app/src/main/res/drawable/sl_wishlist_icon.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/week2/app/src/main/res/drawable/sl_wishlist_tint.xml b/week2/app/src/main/res/drawable/sl_wishlist_tint.xml new file mode 100644 index 0000000..78fdb7c --- /dev/null +++ b/week2/app/src/main/res/drawable/sl_wishlist_tint.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/week2/app/src/main/res/layout/activity_main.xml b/week2/app/src/main/res/layout/activity_main.xml index 7570451..376288c 100644 --- a/week2/app/src/main/res/layout/activity_main.xml +++ b/week2/app/src/main/res/layout/activity_main.xml @@ -30,4 +30,4 @@ app:layout_constraintStart_toStartOf="parent" app:menu="@menu/bottom_nav_menu" /> - + \ No newline at end of file diff --git a/week2/app/src/main/res/layout/fragment_cart.xml b/week2/app/src/main/res/layout/fragment_cart.xml index 4ad1697..2c8bfbd 100644 --- a/week2/app/src/main/res/layout/fragment_cart.xml +++ b/week2/app/src/main/res/layout/fragment_cart.xml @@ -23,7 +23,7 @@ android:layout_marginTop="20dp" android:gravity="center" android:text="@string/cart_empty_msg" - android:textColor="@android:color/black" + android:textColor="@color/text_main" app:layout_constraintBottom_toTopOf="@+id/btn_order" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -34,9 +34,9 @@ android:layout_width="match_parent" android:layout_height="60dp" android:layout_marginBottom="20dp" - android:backgroundTint="@android:color/black" + android:backgroundTint="@color/primary_black" android:text="@string/cart_order" - android:textColor="@android:color/white" + android:textColor="@color/primary_white" app:cornerRadius="30dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/week2/app/src/main/res/layout/fragment_home.xml b/week2/app/src/main/res/layout/fragment_home.xml index 34e9993..ec2cee4 100644 --- a/week2/app/src/main/res/layout/fragment_home.xml +++ b/week2/app/src/main/res/layout/fragment_home.xml @@ -1,41 +1,83 @@ - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/week2/app/src/main/res/layout/fragment_product_detail.xml b/week2/app/src/main/res/layout/fragment_product_detail.xml new file mode 100644 index 0000000..8449634 --- /dev/null +++ b/week2/app/src/main/res/layout/fragment_product_detail.xml @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/week2/app/src/main/res/layout/fragment_purchase.xml b/week2/app/src/main/res/layout/fragment_purchase.xml index 9f448ec..6b9f054 100644 --- a/week2/app/src/main/res/layout/fragment_purchase.xml +++ b/week2/app/src/main/res/layout/fragment_purchase.xml @@ -1,20 +1,23 @@ - + android:layout_height="match_parent"> + app:tabRippleColor="@android:color/transparent" + app:tabIndicatorFullWidth="false" + app:tabIndicatorHeight="2dp" + app:layout_constraintTop_toTopOf="parent"> - + + + diff --git a/week2/app/src/main/res/layout/fragment_wishlist.xml b/week2/app/src/main/res/layout/fragment_wishlist.xml index 86902d3..85b569c 100644 --- a/week2/app/src/main/res/layout/fragment_wishlist.xml +++ b/week2/app/src/main/res/layout/fragment_wishlist.xml @@ -1,16 +1,32 @@ - + android:layout_height="match_parent"> + android:textStyle="bold" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - + + + diff --git a/week2/app/src/main/res/layout/item_product.xml b/week2/app/src/main/res/layout/item_product.xml new file mode 100644 index 0000000..e31b2f5 --- /dev/null +++ b/week2/app/src/main/res/layout/item_product.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + diff --git a/week2/app/src/main/res/navigation/nav_graph.xml b/week2/app/src/main/res/navigation/nav_graph.xml index 1bf08d3..348654c 100644 --- a/week2/app/src/main/res/navigation/nav_graph.xml +++ b/week2/app/src/main/res/navigation/nav_graph.xml @@ -9,12 +9,20 @@ android:id="@+id/nav_home" android:name="com.example.week2.HomeFragment" android:label="HomeFragment" - tools:layout="@layout/fragment_home" /> + tools:layout="@layout/fragment_home"> + + + tools:layout="@layout/fragment_purchase"> + + + + + diff --git a/week2/app/src/main/res/values/colors.xml b/week2/app/src/main/res/values/colors.xml index f8c6127..5af3ead 100644 --- a/week2/app/src/main/res/values/colors.xml +++ b/week2/app/src/main/res/values/colors.xml @@ -1,10 +1,26 @@ - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 + #FF000000 #FFFFFFFF - \ No newline at end of file + + + #111111 + #FFFFFF + #E2112C + #111111 + #757575 + #BDBDBD + #F6F6F6 + #E0E0E0 + #444444 + #757575 + #F6F6F6 + + + #111111 + #757575 + + + #E2112C + diff --git a/week2/app/src/main/res/values/strings.xml b/week2/app/src/main/res/values/strings.xml index 29a13de..f28f503 100644 --- a/week2/app/src/main/res/values/strings.xml +++ b/week2/app/src/main/res/values/strings.xml @@ -26,4 +26,12 @@ 위시리스트 + + + The Nike Everyday Plus Cushioned Socks bring comfort to your workout with extra cushioning under the heel and forefoot and a snug, supportive arch band. Sweat-wicking power and breathability up top help keep your feet dry and cool to help push you through that extra set. + 위시리스트 + • Shown: Multi-Color\n• Style: SX6897-965 + View Product Details + 사이즈 선택 + 장바구니에 추가