diff --git a/week6/.gitignore b/week6/.gitignore
new file mode 100644
index 0000000..6b7cf56
--- /dev/null
+++ b/week6/.gitignore
@@ -0,0 +1,19 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
+week1/
+week2 - 복사본/
+./week1/
+"../week2 - \353\263\265\354\202\254\353\263\270/"
\ No newline at end of file
diff --git a/week6/.idea/.gitignore b/week6/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/week6/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/week6/.idea/.name b/week6/.idea/.name
new file mode 100644
index 0000000..d3b792f
--- /dev/null
+++ b/week6/.idea/.name
@@ -0,0 +1 @@
+week4
\ No newline at end of file
diff --git a/week6/.idea/AndroidProjectSystem.xml b/week6/.idea/AndroidProjectSystem.xml
new file mode 100644
index 0000000..4a53bee
--- /dev/null
+++ b/week6/.idea/AndroidProjectSystem.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/.idea/compiler.xml b/week6/.idea/compiler.xml
new file mode 100644
index 0000000..b86273d
--- /dev/null
+++ b/week6/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/.idea/deploymentTargetSelector.xml b/week6/.idea/deploymentTargetSelector.xml
new file mode 100644
index 0000000..b268ef3
--- /dev/null
+++ b/week6/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/.idea/gradle.xml b/week6/.idea/gradle.xml
new file mode 100644
index 0000000..cdbc250
--- /dev/null
+++ b/week6/.idea/gradle.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/.idea/misc.xml b/week6/.idea/misc.xml
new file mode 100644
index 0000000..b46c05e
--- /dev/null
+++ b/week6/.idea/misc.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/.idea/runConfigurations.xml b/week6/.idea/runConfigurations.xml
new file mode 100644
index 0000000..16660f1
--- /dev/null
+++ b/week6/.idea/runConfigurations.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/.idea/vcs.xml b/week6/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/week6/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/app/.gitignore b/week6/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/week6/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/week6/app/build.gradle.kts b/week6/app/build.gradle.kts
new file mode 100644
index 0000000..1851807
--- /dev/null
+++ b/week6/app/build.gradle.kts
@@ -0,0 +1,102 @@
+import java.util.Properties
+
+plugins {
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.compose.compiler)
+ alias(libs.plugins.hilt)
+ alias(libs.plugins.ksp)
+ id("kotlin-parcelize")
+}
+
+val localProperties = Properties()
+val localPropertiesFile = rootProject.file("local.properties")
+if (localPropertiesFile.exists()) {
+ localProperties.load(localPropertiesFile.inputStream())
+}
+
+android {
+ namespace = "com.example.week2"
+ compileSdk = 35
+
+ defaultConfig {
+ applicationId = "com.example.week2"
+ minSdk = 24
+ targetSdk = 35
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+
+ // local.properties에서 키를 가져와서 쌍따옴표 제거 후 buildConfigField에 추가
+ val rawApiKey = localProperties.getProperty("REQRES_API_KEY") ?: ""
+ val apiKey = rawApiKey.trim().replace("\"", "").replace("'", "")
+ buildConfigField("String", "REQRES_API_KEY", "\"$apiKey\"")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+ kotlinOptions {
+ jvmTarget = "11"
+ }
+ buildFeatures {
+ viewBinding = true
+ compose = true
+ buildConfig = true
+ }
+}
+
+dependencies {
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.androidx.collection)
+ implementation(libs.androidx.appcompat)
+ implementation(libs.material)
+ implementation(libs.androidx.activity)
+ implementation(libs.androidx.constraintlayout)
+ implementation(libs.androidx.fragment.ktx)
+ implementation(libs.androidx.navigation.fragment.ktx)
+ implementation(libs.androidx.navigation.ui.ktx)
+
+ // Hilt
+ implementation(libs.hilt.android)
+ ksp(libs.hilt.compiler)
+
+ // DataStore & Gson
+ implementation(libs.androidx.datastore.preferences)
+ implementation(libs.gson)
+
+ // Retrofit & OkHttp
+ implementation(libs.retrofit)
+ implementation(libs.retrofit.gson)
+ implementation(libs.okhttp.logging)
+
+ // Glide
+ implementation(libs.glide)
+
+ // Compose
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.androidx.ui)
+ implementation(libs.androidx.ui.graphics)
+ implementation(libs.androidx.ui.tooling.preview)
+ implementation(libs.androidx.material3)
+ implementation(libs.androidx.activity.compose)
+
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+ androidTestImplementation(platform(libs.androidx.compose.bom))
+ androidTestImplementation(libs.androidx.ui.test.junit4)
+ debugImplementation(libs.androidx.ui.tooling)
+ debugImplementation(libs.androidx.ui.test.manifest)
+}
diff --git a/week6/app/proguard-rules.pro b/week6/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/week6/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/week6/app/src/androidTest/java/com/example/week2/ExampleInstrumentedTest.kt b/week6/app/src/androidTest/java/com/example/week2/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..e20abc4
--- /dev/null
+++ b/week6/app/src/androidTest/java/com/example/week2/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.example.week2
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.example.week2", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/week6/app/src/main/AndroidManifest.xml b/week6/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29e7c50
--- /dev/null
+++ b/week6/app/src/main/AndroidManifest.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/app/src/main/java/com/example/week2/AllProductsFragment.kt b/week6/app/src/main/java/com/example/week2/AllProductsFragment.kt
new file mode 100644
index 0000000..27fde5b
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/AllProductsFragment.kt
@@ -0,0 +1,78 @@
+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.fragment.app.viewModels
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.GridLayoutManager
+import com.example.week2.databinding.FragmentAllProductsBinding
+import com.example.week2.viewmodel.AllProductsViewModel
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
+
+@AndroidEntryPoint
+class AllProductsFragment : Fragment() {
+ private var _binding: FragmentAllProductsBinding? = null
+ private val binding get() = _binding!!
+ private val viewModel: AllProductsViewModel by viewModels()
+ private var productAdapter: ProductAdapter? = null
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentAllProductsBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupRecyclerView()
+ observeViewModel()
+ }
+
+ private fun setupRecyclerView() {
+ productAdapter = ProductAdapter(
+ emptyList(),
+ onItemClick = { product ->
+ navigateToDetail(product)
+ },
+ onWishlistClick = { product, _ ->
+ viewModel.toggleWishlist(product)
+ }
+ )
+
+ binding.rvAllProducts.layoutManager = GridLayoutManager(context, 2)
+ binding.rvAllProducts.adapter = productAdapter
+ }
+
+ private fun observeViewModel() {
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.allProducts.collect { products ->
+ productAdapter?.updateList(products)
+ }
+ }
+ }
+ }
+
+ private fun navigateToDetail(product: Product) {
+ val bundle = Bundle().apply {
+ putParcelable("product", product)
+ }
+
+ findNavController().navigate(R.id.action_purchaseFragment_to_productDetailFragment, bundle)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ productAdapter = null
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/ApiClient.kt b/week6/app/src/main/java/com/example/week2/ApiClient.kt
new file mode 100644
index 0000000..a4f3c2a
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/ApiClient.kt
@@ -0,0 +1,19 @@
+package com.example.week2
+
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+
+object ApiClient {
+ private const val BASE_URL = "https://reqres.in/"
+
+ private val retrofit: Retrofit by lazy {
+ Retrofit.Builder()
+ .baseUrl(BASE_URL)
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ }
+
+ val service: ReqResService by lazy {
+ retrofit.create(ReqResService::class.java)
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/CartFragment.kt b/week6/app/src/main/java/com/example/week2/CartFragment.kt
new file mode 100644
index 0000000..682e2e0
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/CartFragment.kt
@@ -0,0 +1,38 @@
+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.FragmentCartBinding
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class CartFragment : Fragment() {
+ private var _binding: FragmentCartBinding? = null
+ private val binding get() = _binding!!
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentCartBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ binding.btnOrder.setOnClickListener {
+ // Navigation Component를 사용하여 구매하기 화면으로 이동
+ findNavController().navigate(R.id.nav_purchase)
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/DataStoreManager.kt b/week6/app/src/main/java/com/example/week2/DataStoreManager.kt
new file mode 100644
index 0000000..e26c60e
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/DataStoreManager.kt
@@ -0,0 +1,68 @@
+package com.example.week2
+
+import android.content.Context
+import androidx.datastore.core.DataStore
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.core.edit
+import androidx.datastore.preferences.core.stringPreferencesKey
+import androidx.datastore.preferences.preferencesDataStore
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.map
+
+val Context.dataStore: DataStore by preferencesDataStore(name = "product_preferences")
+
+class DataStoreManager(private val context: Context) {
+ private val gson = Gson()
+
+ companion object {
+ private val PRODUCTS_KEY = stringPreferencesKey("products")
+ }
+
+ suspend fun saveProducts(products: List) {
+ val jsonString = gson.toJson(products)
+ context.dataStore.edit { preferences ->
+ preferences[PRODUCTS_KEY] = jsonString
+ }
+ }
+
+ // 리소스 ID 꼬임 방지를 위해, 저장된 데이터가 있더라도 리소스 ID는 초기 데이터에서 가져와 매핑.
+ val productsFlow: Flow> = context.dataStore.data.map { preferences ->
+ val jsonString = preferences[PRODUCTS_KEY] ?: ""
+ val initialProducts = getInitialProducts()
+
+ if (jsonString.isEmpty()) {
+ initialProducts
+ } else {
+ val type = object : TypeToken>() {}.type
+ val savedProducts: List = gson.fromJson(jsonString, type)
+
+ // 저장된 데이터의 위시리스트 상태는 유지하되, 이미지 리소스 ID는 현재 프로젝트의 ID로 갱신
+ savedProducts.map { saved ->
+ val initial = initialProducts.find { it.id == saved.id }
+ saved.copy(imageResId = initial?.imageResId ?: saved.imageResId)
+ }
+ }
+ }
+
+ private fun getInitialProducts(): List {
+ return 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"),
+ Product(4, "Nike Elite Crew", "Basketball Socks", "US$16", R.drawable.img_training_ankle_socks, category = "Basketball Socks"),
+ Product(5, "Jordan Nike Air Force 1 '07 Essentials", "Men's Shoes", "US$115", R.drawable.img_air_jordan_xxxvi, category = "Men's Shoes")
+ )
+ }
+
+ suspend fun updateWishlistStatus(productId: Int, isWishlisted: Boolean) {
+ val products = productsFlow.first().toMutableList()
+ val index = products.indexOfFirst { it.id == productId }
+ if (index != -1) {
+ products[index] = products[index].copy(isWishlisted = isWishlisted)
+ saveProducts(products)
+ }
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/FollowingAdapter.kt b/week6/app/src/main/java/com/example/week2/FollowingAdapter.kt
new file mode 100644
index 0000000..5486041
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/FollowingAdapter.kt
@@ -0,0 +1,42 @@
+package com.example.week2
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.example.week2.databinding.ItemFollowingBinding
+
+class FollowingAdapter : ListAdapter(DiffCallback) {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FollowingViewHolder {
+ val binding = ItemFollowingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+ return FollowingViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(holder: FollowingViewHolder, position: Int) {
+ holder.bind(getItem(position))
+ }
+
+ class FollowingViewHolder(private val binding: ItemFollowingBinding) : RecyclerView.ViewHolder(binding.root) {
+ fun bind(user: UserData) {
+ Glide.with(binding.root.context)
+ .load(user.avatar)
+ .circleCrop()
+ .into(binding.ivFollowingProfile)
+ }
+ }
+
+ companion object {
+ private val DiffCallback = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: UserData, newItem: UserData): Boolean {
+ return oldItem.id == newItem.id
+ }
+
+ override fun areContentsTheSame(oldItem: UserData, newItem: UserData): Boolean {
+ return oldItem == newItem
+ }
+ }
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/HomeFragment.kt b/week6/app/src/main/java/com/example/week2/HomeFragment.kt
new file mode 100644
index 0000000..f7818ca
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/HomeFragment.kt
@@ -0,0 +1,79 @@
+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.fragment.app.viewModels
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.example.week2.databinding.FragmentHomeBinding
+import com.example.week2.viewmodel.HomeViewModel
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
+
+@AndroidEntryPoint
+class HomeFragment : Fragment() {
+ private var _binding: FragmentHomeBinding? = null
+ private val binding get() = _binding!!
+ private val viewModel: HomeViewModel by viewModels()
+ private var productAdapter: ProductAdapter? = 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)
+ setupRecyclerView()
+ observeViewModel()
+ }
+
+ private fun setupRecyclerView() {
+ productAdapter = ProductAdapter(
+ emptyList(),
+ onItemClick = { product ->
+ navigateToDetail(product)
+ },
+ onWishlistClick = { product, _ ->
+ viewModel.toggleWishlist(product)
+ }
+ )
+
+ binding.rvHomeProducts.apply {
+ layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
+ adapter = productAdapter
+ }
+ }
+
+ private fun observeViewModel() {
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.homeProducts.collect { products ->
+ productAdapter?.updateList(products)
+ }
+ }
+ }
+ }
+
+ private fun navigateToDetail(product: Product) {
+ val bundle = Bundle().apply {
+ putParcelable("product", product)
+ }
+ findNavController().navigate(R.id.action_homeFragment_to_productDetailFragment, bundle)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ productAdapter = null
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/MainActivity.kt b/week6/app/src/main/java/com/example/week2/MainActivity.kt
new file mode 100644
index 0000000..b586711
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/MainActivity.kt
@@ -0,0 +1,65 @@
+package com.example.week2
+
+import android.os.Bundle
+import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
+import androidx.navigation.fragment.NavHostFragment
+import androidx.navigation.ui.setupWithNavController
+import com.example.week2.databinding.ActivityMainBinding
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class MainActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityMainBinding
+ private val TAG = "LIFE_QUIZ"
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ // ViewBinding 초기화
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ Log.d(TAG, "onCreate")
+
+ initNavigation()
+ }
+
+ private fun initNavigation() {
+ val navHostFragment = supportFragmentManager
+ .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
+ val navController = navHostFragment.navController
+
+ // BottomNavigationView와 NavController 연결
+ binding.bottomNav.setupWithNavController(navController)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ Log.d(TAG, "onStart")
+ }
+
+ override fun onResume() {
+ super.onResume()
+ Log.d(TAG, "onResume")
+ }
+
+ override fun onPause() {
+ super.onPause()
+ Log.d(TAG, "onPause")
+ }
+
+ override fun onStop() {
+ super.onStop()
+ Log.d(TAG, "onStop")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ Log.d(TAG, "onDestroy")
+ }
+
+ override fun onRestart() {
+ super.onRestart()
+ Log.d(TAG, "onRestart")
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/Models.kt b/week6/app/src/main/java/com/example/week2/Models.kt
new file mode 100644
index 0000000..4e9dcf0
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/Models.kt
@@ -0,0 +1,19 @@
+package com.example.week2
+
+import com.google.gson.annotations.SerializedName
+
+data class UserResponse(
+ val data: UserData
+)
+
+data class UserListResponse(
+ val data: List
+)
+
+data class UserData(
+ val id: Int,
+ val email: String,
+ @SerializedName("first_name") val firstName: String,
+ @SerializedName("last_name") val lastName: String,
+ val avatar: String
+)
diff --git a/week6/app/src/main/java/com/example/week2/Product.kt b/week6/app/src/main/java/com/example/week2/Product.kt
new file mode 100644
index 0000000..3a45829
--- /dev/null
+++ b/week6/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/week6/app/src/main/java/com/example/week2/ProductAdapter.kt b/week6/app/src/main/java/com/example/week2/ProductAdapter.kt
new file mode 100644
index 0000000..7a7825f
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/ProductAdapter.kt
@@ -0,0 +1,50 @@
+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 var products: List,
+ private val onItemClick: (Product) -> Unit,
+ private val onWishlistClick: (Product, Int) -> Unit
+) : RecyclerView.Adapter() {
+
+ fun updateList(newProducts: List) {
+ this.products = newProducts
+ notifyDataSetChanged()
+ }
+
+ 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/week6/app/src/main/java/com/example/week2/ProductDetailFragment.kt b/week6/app/src/main/java/com/example/week2/ProductDetailFragment.kt
new file mode 100644
index 0000000..a2ec7a0
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/ProductDetailFragment.kt
@@ -0,0 +1,91 @@
+package com.example.week2
+
+import android.os.Build
+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 androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.navigation.fragment.findNavController
+import com.example.week2.databinding.FragmentProductDetailBinding
+import com.example.week2.viewmodel.ProductDetailViewModel
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
+
+@AndroidEntryPoint
+class ProductDetailFragment : Fragment() {
+ private var _binding: FragmentProductDetailBinding? = null
+ private val binding get() = _binding!!
+ private val viewModel: ProductDetailViewModel by viewModels()
+
+ 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 initialProduct = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ arguments?.getParcelable("product", Product::class.java)
+ } else {
+ @Suppress("DEPRECATION")
+ arguments?.getParcelable("product")
+ }
+
+ initialProduct?.let {
+ viewModel.setProductId(it.id)
+ // 초기 UI 설정 (로딩 전 빈 화면 방지)
+ setupInitialUI(it)
+ }
+
+ observeViewModel()
+
+ binding.ibBack.setOnClickListener {
+ findNavController().popBackStack()
+ }
+
+ binding.btnWishlist.setOnClickListener {
+ viewModel.toggleWishlist()
+ }
+ }
+
+ private fun setupInitialUI(product: Product) {
+ binding.tvHeaderTitle.text = product.name
+ binding.ivDetailImage.setImageResource(product.imageResId)
+ binding.tvDetailCategory.text = product.category
+ binding.tvDetailName.text = product.name
+ binding.tvDetailPrice.text = product.price
+ updateWishlistButton(product.isWishlisted)
+ }
+
+ private fun observeViewModel() {
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.product.collect { product ->
+ product?.let {
+ binding.tvHeaderTitle.text = it.name
+ binding.tvDetailName.text = it.name
+ updateWishlistButton(it.isWishlisted)
+ }
+ }
+ }
+ }
+ }
+
+ private fun updateWishlistButton(isWishlisted: Boolean) {
+ binding.ivWishlistHeart.isSelected = isWishlisted
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/ProfileFragment.kt b/week6/app/src/main/java/com/example/week2/ProfileFragment.kt
new file mode 100644
index 0000000..58d7095
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/ProfileFragment.kt
@@ -0,0 +1,82 @@
+package com.example.week2
+
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.bumptech.glide.Glide
+import com.example.week2.databinding.FragmentProfileBinding
+import com.example.week2.viewmodel.ProfileViewModel
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class ProfileFragment : Fragment() {
+ private var _binding: FragmentProfileBinding? = null
+ private val binding get() = _binding!!
+
+ private val viewModel: ProfileViewModel by viewModels()
+ private lateinit var followingAdapter: FollowingAdapter
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentProfileBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ setupRecyclerView()
+ observeViewModel()
+
+ if (viewModel.userProfile.value == null) {
+ viewModel.fetchUserProfile(1)
+ }
+ if (viewModel.followingList.value == null) {
+ viewModel.fetchFollowingList()
+ }
+ }
+
+ private fun setupRecyclerView() {
+ followingAdapter = FollowingAdapter()
+ binding.rvFollowing.apply {
+ adapter = followingAdapter
+ layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
+ }
+ }
+
+ private fun observeViewModel() {
+ viewModel.userProfile.observe(viewLifecycleOwner) { user ->
+ user?.let {
+ val fullName = "${it.firstName} ${it.lastName}"
+ binding.tvProfileNickname.text = fullName
+
+ Glide.with(this@ProfileFragment)
+ .load(it.avatar)
+ .circleCrop()
+ .into(binding.ivProfileImg)
+ }
+ }
+
+ viewModel.followingList.observe(viewLifecycleOwner) { users ->
+ followingAdapter.submitList(users)
+ binding.tvFollowingTitle.text = "팔로잉 (${users.size})"
+ }
+
+ viewModel.error.observe(viewLifecycleOwner) { message ->
+ Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/PurchaseFragment.kt b/week6/app/src/main/java/com/example/week2/PurchaseFragment.kt
new file mode 100644
index 0000000..765036b
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/PurchaseFragment.kt
@@ -0,0 +1,48 @@
+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 com.example.week2.databinding.FragmentPurchaseBinding
+import com.google.android.material.tabs.TabLayoutMediator
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class PurchaseFragment : Fragment() {
+ private var _binding: FragmentPurchaseBinding? = null
+ private val binding get() = _binding!!
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentPurchaseBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupViewPager()
+ }
+
+ private fun setupViewPager() {
+ val adapter = PurchasePagerAdapter(this)
+ binding.viewPagerPurchase.adapter = adapter
+
+ TabLayoutMediator(binding.tabLayoutPurchase, binding.viewPagerPurchase) { tab, position ->
+ tab.text = when (position) {
+ 0 -> "All"
+ 1 -> "Top & T-shirts"
+ 2 -> "Sale"
+ else -> null
+ }
+ }.attach()
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/PurchasePagerAdapter.kt b/week6/app/src/main/java/com/example/week2/PurchasePagerAdapter.kt
new file mode 100644
index 0000000..c429682
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/PurchasePagerAdapter.kt
@@ -0,0 +1,17 @@
+package com.example.week2
+
+import androidx.fragment.app.Fragment
+import androidx.viewpager2.adapter.FragmentStateAdapter
+
+class PurchasePagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
+ override fun getItemCount(): Int = 3
+
+ override fun createFragment(position: Int): Fragment {
+ return when (position) {
+ 0 -> AllProductsFragment()
+ 1 -> TopsTshirtsFragment()
+ 2 -> SaleFragment()
+ else -> AllProductsFragment()
+ }
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/ReqResService.kt b/week6/app/src/main/java/com/example/week2/ReqResService.kt
new file mode 100644
index 0000000..c6ed1c5
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/ReqResService.kt
@@ -0,0 +1,21 @@
+package com.example.week2
+
+import retrofit2.Response
+import retrofit2.http.GET
+import retrofit2.http.Header
+import retrofit2.http.Path
+import retrofit2.http.Query
+
+interface ReqResService {
+ @GET("api/users/{id}")
+ suspend fun getUser(
+ @Path("id") id: Int,
+ @Header("x-api-key") apiKey: String = BuildConfig.REQRES_API_KEY
+ ): Response
+
+ @GET("api/users")
+ suspend fun getUsers(
+ @Query("page") page: Int = 1,
+ @Header("x-api-key") apiKey: String = BuildConfig.REQRES_API_KEY
+ ): Response
+}
diff --git a/week6/app/src/main/java/com/example/week2/SaleFragment.kt b/week6/app/src/main/java/com/example/week2/SaleFragment.kt
new file mode 100644
index 0000000..c307e51
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/SaleFragment.kt
@@ -0,0 +1,31 @@
+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 com.example.week2.databinding.FragmentEmptyTabBinding
+
+class SaleFragment : Fragment() {
+ private var _binding: FragmentEmptyTabBinding? = null
+ private val binding get() = _binding!!
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentEmptyTabBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.tvMessage.text = getString(R.string.purchase_sale)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/TopsTshirtsFragment.kt b/week6/app/src/main/java/com/example/week2/TopsTshirtsFragment.kt
new file mode 100644
index 0000000..a0eb6f9
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/TopsTshirtsFragment.kt
@@ -0,0 +1,31 @@
+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 com.example.week2.databinding.FragmentEmptyTabBinding
+
+class TopsTshirtsFragment : Fragment() {
+ private var _binding: FragmentEmptyTabBinding? = null
+ private val binding get() = _binding!!
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentEmptyTabBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.tvMessage.text = getString(R.string.purchase_tops_tshirts)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/Week2Application.kt b/week6/app/src/main/java/com/example/week2/Week2Application.kt
new file mode 100644
index 0000000..6ad0dcf
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/Week2Application.kt
@@ -0,0 +1,7 @@
+package com.example.week2
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class Week2Application : Application()
diff --git a/week6/app/src/main/java/com/example/week2/WishlistFragment.kt b/week6/app/src/main/java/com/example/week2/WishlistFragment.kt
new file mode 100644
index 0000000..d42e9f3
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/WishlistFragment.kt
@@ -0,0 +1,79 @@
+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.fragment.app.viewModels
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.navigation.fragment.findNavController
+import androidx.recyclerview.widget.GridLayoutManager
+import com.example.week2.databinding.FragmentWishlistBinding
+import com.example.week2.viewmodel.WishlistViewModel
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
+
+@AndroidEntryPoint
+class WishlistFragment : Fragment() {
+ private var _binding: FragmentWishlistBinding? = null
+ private val binding get() = _binding!!
+ private val viewModel: WishlistViewModel by viewModels()
+ private var productAdapter: ProductAdapter? = null
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = FragmentWishlistBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupRecyclerView()
+ observeViewModel()
+ }
+
+ private fun setupRecyclerView() {
+ productAdapter = ProductAdapter(
+ emptyList(),
+ onItemClick = { product ->
+ navigateToDetail(product)
+ },
+ onWishlistClick = { product, _ ->
+ viewModel.toggleWishlist(product)
+ }
+ )
+
+ binding.rvWishlistProducts.apply {
+ layoutManager = GridLayoutManager(context, 2)
+ adapter = productAdapter
+ }
+ }
+
+ private fun observeViewModel() {
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.wishlistProducts.collect { products ->
+ productAdapter?.updateList(products)
+ }
+ }
+ }
+ }
+
+ private fun navigateToDetail(product: Product) {
+ val bundle = Bundle().apply {
+ putParcelable("product", product)
+ }
+ findNavController().navigate(R.id.action_wishlistFragment_to_productDetailFragment, bundle)
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ productAdapter = null
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/di/DataModule.kt b/week6/app/src/main/java/com/example/week2/di/DataModule.kt
new file mode 100644
index 0000000..6b84b9c
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/di/DataModule.kt
@@ -0,0 +1,21 @@
+package com.example.week2.di
+
+import android.content.Context
+import com.example.week2.DataStoreManager
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object DataModule {
+
+ @Provides
+ @Singleton
+ fun provideDataStoreManager(@ApplicationContext context: Context): DataStoreManager {
+ return DataStoreManager(context)
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/di/NetworkModule.kt b/week6/app/src/main/java/com/example/week2/di/NetworkModule.kt
new file mode 100644
index 0000000..81bbefc
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/di/NetworkModule.kt
@@ -0,0 +1,31 @@
+package com.example.week2.di
+
+import com.example.week2.ReqResService
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object NetworkModule {
+ private const val BASE_URL = "https://reqres.in/"
+
+ @Provides
+ @Singleton
+ fun provideRetrofit(): Retrofit {
+ return Retrofit.Builder()
+ .baseUrl(BASE_URL)
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ }
+
+ @Provides
+ @Singleton
+ fun provideReqResService(retrofit: Retrofit): ReqResService {
+ return retrofit.create(ReqResService::class.java)
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/repository/ProductRepository.kt b/week6/app/src/main/java/com/example/week2/repository/ProductRepository.kt
new file mode 100644
index 0000000..59940ef
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/repository/ProductRepository.kt
@@ -0,0 +1,22 @@
+package com.example.week2.repository
+
+import com.example.week2.DataStoreManager
+import com.example.week2.Product
+import kotlinx.coroutines.flow.Flow
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ProductRepository @Inject constructor(
+ private val dataStoreManager: DataStoreManager
+) {
+ val products: Flow> = dataStoreManager.productsFlow
+
+ suspend fun updateWishlistStatus(productId: Int, isWishlisted: Boolean) {
+ dataStoreManager.updateWishlistStatus(productId, isWishlisted)
+ }
+
+ suspend fun saveProducts(products: List) {
+ dataStoreManager.saveProducts(products)
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/repository/UserRepository.kt b/week6/app/src/main/java/com/example/week2/repository/UserRepository.kt
new file mode 100644
index 0000000..e295828
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/repository/UserRepository.kt
@@ -0,0 +1,21 @@
+package com.example.week2.repository
+
+import com.example.week2.ReqResService
+import com.example.week2.UserResponse
+import com.example.week2.UserListResponse
+import retrofit2.Response
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class UserRepository @Inject constructor(
+ private val reqResService: ReqResService
+) {
+ suspend fun getUser(id: Int): Response {
+ return reqResService.getUser(id)
+ }
+
+ suspend fun getUsers(page: Int): Response {
+ return reqResService.getUsers(page)
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/ui/theme/Color.kt b/week6/app/src/main/java/com/example/week2/ui/theme/Color.kt
new file mode 100644
index 0000000..de069ca
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/ui/theme/Color.kt
@@ -0,0 +1,11 @@
+package com.example.week2.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val Purple80 = Color(0xFFD0BCFF)
+val PurpleGrey80 = Color(0xFFCCC2DC)
+val Pink80 = Color(0xFFEFB8C8)
+
+val Purple40 = Color(0xFF6650a4)
+val PurpleGrey40 = Color(0xFF625b71)
+val Pink40 = Color(0xFF7D5260)
\ No newline at end of file
diff --git a/week6/app/src/main/java/com/example/week2/ui/theme/Theme.kt b/week6/app/src/main/java/com/example/week2/ui/theme/Theme.kt
new file mode 100644
index 0000000..9168083
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/ui/theme/Theme.kt
@@ -0,0 +1,58 @@
+package com.example.week2.ui.theme
+
+import android.app.Activity
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+
+private val DarkColorScheme = darkColorScheme(
+ primary = Purple80,
+ secondary = PurpleGrey80,
+ tertiary = Pink80
+)
+
+private val LightColorScheme = lightColorScheme(
+ primary = Purple40,
+ secondary = PurpleGrey40,
+ tertiary = Pink40
+
+ /* Other default colors to override
+ background = Color(0xFFFFFBFE),
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+ */
+)
+
+@Composable
+fun Week2Theme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ // Dynamic color is available on Android 12+
+ dynamicColor: Boolean = true,
+ content: @Composable () -> Unit
+) {
+ val colorScheme = when {
+ dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ val context = LocalContext.current
+ if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
+ }
+
+ darkTheme -> DarkColorScheme
+ else -> LightColorScheme
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography,
+ content = content
+ )
+}
\ No newline at end of file
diff --git a/week6/app/src/main/java/com/example/week2/ui/theme/Type.kt b/week6/app/src/main/java/com/example/week2/ui/theme/Type.kt
new file mode 100644
index 0000000..d0bf0ca
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/ui/theme/Type.kt
@@ -0,0 +1,34 @@
+package com.example.week2.ui.theme
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ bodyLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
+ */
+)
\ No newline at end of file
diff --git a/week6/app/src/main/java/com/example/week2/viewmodel/AllProductsViewModel.kt b/week6/app/src/main/java/com/example/week2/viewmodel/AllProductsViewModel.kt
new file mode 100644
index 0000000..6502992
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/viewmodel/AllProductsViewModel.kt
@@ -0,0 +1,31 @@
+package com.example.week2.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.week2.Product
+import com.example.week2.repository.ProductRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class AllProductsViewModel @Inject constructor(
+ private val productRepository: ProductRepository
+) : ViewModel() {
+
+ val allProducts: StateFlow> = productRepository.products
+ .stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5000),
+ initialValue = emptyList()
+ )
+
+ fun toggleWishlist(product: Product) {
+ viewModelScope.launch {
+ productRepository.updateWishlistStatus(product.id, !product.isWishlisted)
+ }
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/viewmodel/HomeViewModel.kt b/week6/app/src/main/java/com/example/week2/viewmodel/HomeViewModel.kt
new file mode 100644
index 0000000..f53564f
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/viewmodel/HomeViewModel.kt
@@ -0,0 +1,33 @@
+package com.example.week2.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.week2.Product
+import com.example.week2.repository.ProductRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class HomeViewModel @Inject constructor(
+ private val productRepository: ProductRepository
+) : ViewModel() {
+
+ val homeProducts: StateFlow> = productRepository.products
+ .map { it.take(3) }
+ .stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5000),
+ initialValue = emptyList()
+ )
+
+ fun toggleWishlist(product: Product) {
+ viewModelScope.launch {
+ productRepository.updateWishlistStatus(product.id, !product.isWishlisted)
+ }
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/viewmodel/ProductDetailViewModel.kt b/week6/app/src/main/java/com/example/week2/viewmodel/ProductDetailViewModel.kt
new file mode 100644
index 0000000..4156fd4
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/viewmodel/ProductDetailViewModel.kt
@@ -0,0 +1,41 @@
+package com.example.week2.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.week2.Product
+import com.example.week2.repository.ProductRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class ProductDetailViewModel @Inject constructor(
+ private val productRepository: ProductRepository
+) : ViewModel() {
+
+ private val _productId = MutableStateFlow(null)
+
+ val product: StateFlow = combine(_productId, productRepository.products) { id, products ->
+ products.find { it.id == id }
+ }.stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5000),
+ initialValue = null
+ )
+
+ fun setProductId(id: Int) {
+ _productId.value = id
+ }
+
+ fun toggleWishlist() {
+ val currentProduct = product.value ?: return
+ viewModelScope.launch {
+ productRepository.updateWishlistStatus(currentProduct.id, !currentProduct.isWishlisted)
+ }
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/viewmodel/ProfileViewModel.kt b/week6/app/src/main/java/com/example/week2/viewmodel/ProfileViewModel.kt
new file mode 100644
index 0000000..a264fd1
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/viewmodel/ProfileViewModel.kt
@@ -0,0 +1,56 @@
+package com.example.week2.viewmodel
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.week2.UserData
+import com.example.week2.repository.UserRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class ProfileViewModel @Inject constructor(
+ private val userRepository: UserRepository
+) : ViewModel() {
+
+ private val _userProfile = MutableLiveData()
+ val userProfile: LiveData = _userProfile
+
+ private val _followingList = MutableLiveData>()
+ val followingList: LiveData> = _followingList
+
+ private val _error = MutableLiveData()
+ val error: LiveData = _error
+
+ fun fetchUserProfile(userId: Int) {
+ viewModelScope.launch {
+ try {
+ val response = userRepository.getUser(userId)
+ if (response.isSuccessful) {
+ _userProfile.value = response.body()?.data
+ } else {
+ _error.value = "Failed to fetch user profile"
+ }
+ } catch (e: Exception) {
+ _error.value = e.message ?: "Unknown error"
+ }
+ }
+ }
+
+ fun fetchFollowingList() {
+ viewModelScope.launch {
+ try {
+ val response = userRepository.getUsers(page = 1)
+ if (response.isSuccessful) {
+ _followingList.value = response.body()?.data ?: emptyList()
+ } else {
+ _error.value = "Failed to fetch following list"
+ }
+ } catch (e: Exception) {
+ _error.value = e.message ?: "Unknown error"
+ }
+ }
+ }
+}
diff --git a/week6/app/src/main/java/com/example/week2/viewmodel/WishlistViewModel.kt b/week6/app/src/main/java/com/example/week2/viewmodel/WishlistViewModel.kt
new file mode 100644
index 0000000..da2aea2
--- /dev/null
+++ b/week6/app/src/main/java/com/example/week2/viewmodel/WishlistViewModel.kt
@@ -0,0 +1,33 @@
+package com.example.week2.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.week2.Product
+import com.example.week2.repository.ProductRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class WishlistViewModel @Inject constructor(
+ private val productRepository: ProductRepository
+) : ViewModel() {
+
+ val wishlistProducts: StateFlow> = productRepository.products
+ .map { products -> products.filter { it.isWishlisted } }
+ .stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5000),
+ initialValue = emptyList()
+ )
+
+ fun toggleWishlist(product: Product) {
+ viewModelScope.launch {
+ productRepository.updateWishlistStatus(product.id, !product.isWishlisted)
+ }
+ }
+}
diff --git a/week6/app/src/main/res/drawable/bg_black_round.xml b/week6/app/src/main/res/drawable/bg_black_round.xml
new file mode 100644
index 0000000..fcc2357
--- /dev/null
+++ b/week6/app/src/main/res/drawable/bg_black_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/bg_white_stroke.xml b/week6/app/src/main/res/drawable/bg_white_stroke.xml
new file mode 100644
index 0000000..4f8e667
--- /dev/null
+++ b/week6/app/src/main/res/drawable/bg_white_stroke.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_bagcircle.xml b/week6/app/src/main/res/drawable/ic_bagcircle.xml
new file mode 100644
index 0000000..1af2ce6
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_bagcircle.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_bagsimple.xml b/week6/app/src/main/res/drawable/ic_bagsimple.xml
new file mode 100644
index 0000000..3b6e816
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_bagsimple.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_caretleft.xml b/week6/app/src/main/res/drawable/ic_caretleft.xml
new file mode 100644
index 0000000..1912c2d
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_caretleft.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_event.xml b/week6/app/src/main/res/drawable/ic_event.xml
new file mode 100644
index 0000000..87b9732
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_event.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_heart_empty.xml b/week6/app/src/main/res/drawable/ic_heart_empty.xml
new file mode 100644
index 0000000..a7904b5
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_heart_empty.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_heart_fill.xml b/week6/app/src/main/res/drawable/ic_heart_fill.xml
new file mode 100644
index 0000000..91664d4
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_heart_fill.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_heart_filled.xml b/week6/app/src/main/res/drawable/ic_heart_filled.xml
new file mode 100644
index 0000000..67df58b
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_heart_filled.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_heartstraight.xml b/week6/app/src/main/res/drawable/ic_heartstraight.xml
new file mode 100644
index 0000000..6597a4a
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_heartstraight.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_homeimg.png b/week6/app/src/main/res/drawable/ic_homeimg.png
new file mode 100644
index 0000000..f42aa9d
Binary files /dev/null and b/week6/app/src/main/res/drawable/ic_homeimg.png differ
diff --git a/week6/app/src/main/res/drawable/ic_housesimple.xml b/week6/app/src/main/res/drawable/ic_housesimple.xml
new file mode 100644
index 0000000..a0d86b9
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_housesimple.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_identificationcard.xml b/week6/app/src/main/res/drawable/ic_identificationcard.xml
new file mode 100644
index 0000000..8512c20
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_identificationcard.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_launcher_background.xml b/week6/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_launcher_foreground.xml b/week6/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/app/src/main/res/drawable/ic_listmagnifyingglass.xml b/week6/app/src/main/res/drawable/ic_listmagnifyingglass.xml
new file mode 100644
index 0000000..483d117
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_listmagnifyingglass.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_magnifyingglass.xml b/week6/app/src/main/res/drawable/ic_magnifyingglass.xml
new file mode 100644
index 0000000..9077a42
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_magnifyingglass.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_order.xml b/week6/app/src/main/res/drawable/ic_order.xml
new file mode 100644
index 0000000..bec2bbf
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_order.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_setting.xml b/week6/app/src/main/res/drawable/ic_setting.xml
new file mode 100644
index 0000000..befb75a
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_setting.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/ic_user.xml b/week6/app/src/main/res/drawable/ic_user.xml
new file mode 100644
index 0000000..1fc97b8
--- /dev/null
+++ b/week6/app/src/main/res/drawable/ic_user.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/img_air_jordan_xxxvi.png b/week6/app/src/main/res/drawable/img_air_jordan_xxxvi.png
new file mode 100644
index 0000000..19129df
Binary files /dev/null and b/week6/app/src/main/res/drawable/img_air_jordan_xxxvi.png differ
diff --git a/week6/app/src/main/res/drawable/img_nike_air_force.png b/week6/app/src/main/res/drawable/img_nike_air_force.png
new file mode 100644
index 0000000..1fc5039
Binary files /dev/null and b/week6/app/src/main/res/drawable/img_nike_air_force.png differ
diff --git a/week6/app/src/main/res/drawable/img_nike_everyday_plus_cushioned.png b/week6/app/src/main/res/drawable/img_nike_everyday_plus_cushioned.png
new file mode 100644
index 0000000..9a23c22
Binary files /dev/null and b/week6/app/src/main/res/drawable/img_nike_everyday_plus_cushioned.png differ
diff --git a/week6/app/src/main/res/drawable/img_training_ankle_socks.png b/week6/app/src/main/res/drawable/img_training_ankle_socks.png
new file mode 100644
index 0000000..04a81da
Binary files /dev/null and b/week6/app/src/main/res/drawable/img_training_ankle_socks.png differ
diff --git a/week6/app/src/main/res/drawable/sl_item_wishlist_icon.xml b/week6/app/src/main/res/drawable/sl_item_wishlist_icon.xml
new file mode 100644
index 0000000..7ca06ad
--- /dev/null
+++ b/week6/app/src/main/res/drawable/sl_item_wishlist_icon.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/sl_wishlist_icon.xml b/week6/app/src/main/res/drawable/sl_wishlist_icon.xml
new file mode 100644
index 0000000..3e176b9
--- /dev/null
+++ b/week6/app/src/main/res/drawable/sl_wishlist_icon.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/drawable/sl_wishlist_tint.xml b/week6/app/src/main/res/drawable/sl_wishlist_tint.xml
new file mode 100644
index 0000000..78fdb7c
--- /dev/null
+++ b/week6/app/src/main/res/drawable/sl_wishlist_tint.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/week6/app/src/main/res/layout/activity_main.xml b/week6/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..376288c
--- /dev/null
+++ b/week6/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/app/src/main/res/layout/fragment_all_products.xml b/week6/app/src/main/res/layout/fragment_all_products.xml
new file mode 100644
index 0000000..f1c431f
--- /dev/null
+++ b/week6/app/src/main/res/layout/fragment_all_products.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/layout/fragment_cart.xml b/week6/app/src/main/res/layout/fragment_cart.xml
new file mode 100644
index 0000000..2c8bfbd
--- /dev/null
+++ b/week6/app/src/main/res/layout/fragment_cart.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/layout/fragment_empty_tab.xml b/week6/app/src/main/res/layout/fragment_empty_tab.xml
new file mode 100644
index 0000000..4d4cf42
--- /dev/null
+++ b/week6/app/src/main/res/layout/fragment_empty_tab.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/layout/fragment_home.xml b/week6/app/src/main/res/layout/fragment_home.xml
new file mode 100644
index 0000000..ec2cee4
--- /dev/null
+++ b/week6/app/src/main/res/layout/fragment_home.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/layout/fragment_product_detail.xml b/week6/app/src/main/res/layout/fragment_product_detail.xml
new file mode 100644
index 0000000..8449634
--- /dev/null
+++ b/week6/app/src/main/res/layout/fragment_product_detail.xml
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/layout/fragment_profile.xml b/week6/app/src/main/res/layout/fragment_profile.xml
new file mode 100644
index 0000000..d7a6624
--- /dev/null
+++ b/week6/app/src/main/res/layout/fragment_profile.xml
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/layout/fragment_purchase.xml b/week6/app/src/main/res/layout/fragment_purchase.xml
new file mode 100644
index 0000000..983fd63
--- /dev/null
+++ b/week6/app/src/main/res/layout/fragment_purchase.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/layout/fragment_wishlist.xml b/week6/app/src/main/res/layout/fragment_wishlist.xml
new file mode 100644
index 0000000..85b569c
--- /dev/null
+++ b/week6/app/src/main/res/layout/fragment_wishlist.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/layout/item_following.xml b/week6/app/src/main/res/layout/item_following.xml
new file mode 100644
index 0000000..f4f20d1
--- /dev/null
+++ b/week6/app/src/main/res/layout/item_following.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/layout/item_product.xml b/week6/app/src/main/res/layout/item_product.xml
new file mode 100644
index 0000000..e31b2f5
--- /dev/null
+++ b/week6/app/src/main/res/layout/item_product.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/menu/bottom_nav_menu.xml b/week6/app/src/main/res/menu/bottom_nav_menu.xml
new file mode 100644
index 0000000..22ec5d7
--- /dev/null
+++ b/week6/app/src/main/res/menu/bottom_nav_menu.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/week6/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/week6/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/week6/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/week6/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/week6/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/week6/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/week6/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/week6/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/week6/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/week6/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/week6/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/week6/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/week6/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/week6/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/week6/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/week6/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/week6/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/week6/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/week6/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/week6/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/week6/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/week6/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/week6/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/week6/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/week6/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/week6/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/week6/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/week6/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/week6/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/week6/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/week6/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/week6/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/week6/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/week6/app/src/main/res/navigation/nav_graph.xml b/week6/app/src/main/res/navigation/nav_graph.xml
new file mode 100644
index 0000000..ff0ff38
--- /dev/null
+++ b/week6/app/src/main/res/navigation/nav_graph.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/week6/app/src/main/res/values/colors.xml b/week6/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..5af3ead
--- /dev/null
+++ b/week6/app/src/main/res/values/colors.xml
@@ -0,0 +1,26 @@
+
+
+
+ #FF000000
+ #FFFFFFFF
+
+
+ #111111
+ #FFFFFF
+ #E2112C
+ #111111
+ #757575
+ #BDBDBD
+ #F6F6F6
+ #E0E0E0
+ #444444
+ #757575
+ #F6F6F6
+
+
+ #111111
+ #757575
+
+
+ #E2112C
+
diff --git a/week6/app/src/main/res/values/strings.xml b/week6/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..1d222d0
--- /dev/null
+++ b/week6/app/src/main/res/values/strings.xml
@@ -0,0 +1,38 @@
+
+ week2
+
+
+ 홈
+ 구매하기
+ 위시리스트
+ 장바구니
+ 프로필
+
+
+ Discover
+ 03월 31일 화요일
+
+
+ 장바구니가 비어 있습니다.\n제품을 추가하면 여기에 표시됩니다.
+ 주문하기
+
+
+ Profile Fragment
+
+
+ 전체
+ Top & T-shirts
+ Shoes
+ Sale
+
+
+ 위시리스트
+
+
+ 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
+ 사이즈 선택
+ 장바구니에 추가
+
diff --git a/week6/app/src/main/res/values/themes.xml b/week6/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..30004e5
--- /dev/null
+++ b/week6/app/src/main/res/values/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/week6/app/src/main/res/xml/backup_rules.xml b/week6/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..4df9255
--- /dev/null
+++ b/week6/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/week6/app/src/main/res/xml/data_extraction_rules.xml b/week6/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/week6/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week6/app/src/test/java/com/example/week2/ExampleUnitTest.kt b/week6/app/src/test/java/com/example/week2/ExampleUnitTest.kt
new file mode 100644
index 0000000..c0fd58e
--- /dev/null
+++ b/week6/app/src/test/java/com/example/week2/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.example.week2
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/week6/build.gradle.kts b/week6/build.gradle.kts
new file mode 100644
index 0000000..24e1736
--- /dev/null
+++ b/week6/build.gradle.kts
@@ -0,0 +1,8 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.kotlin.android) apply false
+ alias(libs.plugins.compose.compiler) apply false
+ alias(libs.plugins.hilt) apply false
+ alias(libs.plugins.ksp) apply false
+}
diff --git a/week6/gradle.properties b/week6/gradle.properties
new file mode 100644
index 0000000..7c68ae8
--- /dev/null
+++ b/week6/gradle.properties
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# org.gradle.parallel=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/week6/gradle/gradle-daemon-jvm.properties b/week6/gradle/gradle-daemon-jvm.properties
new file mode 100644
index 0000000..6c1139e
--- /dev/null
+++ b/week6/gradle/gradle-daemon-jvm.properties
@@ -0,0 +1,12 @@
+#This file is generated by updateDaemonJvm
+toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
+toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
+toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
+toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
+toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73bcfb608d1fde9fb62e462f834a3299/redirect
+toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/846ee0d876d26a26f37aa1ce8de73224/redirect
+toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
+toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
+toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9482ddec596298c84656d31d16652665/redirect
+toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/39701d92e1756bb2f141eb67cd4c660e/redirect
+toolchainVersion=21
diff --git a/week6/gradle/libs.versions.toml b/week6/gradle/libs.versions.toml
new file mode 100644
index 0000000..20e2681
--- /dev/null
+++ b/week6/gradle/libs.versions.toml
@@ -0,0 +1,59 @@
+[versions]
+agp = "8.7.3"
+kotlin = "2.0.21"
+coreKtx = "1.13.1"
+junit = "4.13.2"
+junitVersion = "1.2.1"
+espressoCore = "3.6.1"
+appcompat = "1.7.1"
+material = "1.12.0"
+activity = "1.9.3"
+constraintlayout = "2.2.0"
+fragmentKtx = "1.8.5"
+composeBom = "2024.10.01"
+collection = "1.4.5"
+navigation = "2.8.5"
+datastore = "1.1.1"
+gson = "2.10.1"
+retrofit = "2.9.0"
+okhttp = "4.12.0"
+glide = "4.16.0"
+hilt = "2.51.1"
+
+[libraries]
+androidx-collection = { group = "androidx.collection", name = "collection", version.ref = "collection" }
+androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+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" }
+androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+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-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragmentKtx" }
+androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
+androidx-ui = { group = "androidx.compose.ui", name = "ui" }
+androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
+androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
+androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
+androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
+androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
+androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
+androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity" }
+androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigation" }
+androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigation" }
+androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore" }
+gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
+retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
+retrofit-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
+okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }
+glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" }
+hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
+hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
+hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
+ksp = { id = "com.google.devtools.ksp", version = "2.0.21-1.0.27" }
diff --git a/week6/gradle/wrapper/gradle-wrapper.jar b/week6/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8bdaf60
Binary files /dev/null and b/week6/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/week6/gradle/wrapper/gradle-wrapper.properties b/week6/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..ac5327e
--- /dev/null
+++ b/week6/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#Tue Mar 31 22:15:41 KST 2026
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionSha256Sum=b266d5ff6b90eada6dc3b20cb090e3731302e553a27c5d3e4df1f0d76beaff06
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/week6/gradlew b/week6/gradlew
new file mode 100644
index 0000000..ef07e01
--- /dev/null
+++ b/week6/gradlew
@@ -0,0 +1,251 @@
+#!/bin/sh
+
+#
+# Copyright © 2015 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH="\\\"\\\""
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/week6/gradlew.bat b/week6/gradlew.bat
new file mode 100644
index 0000000..db3a6ac
--- /dev/null
+++ b/week6/gradlew.bat
@@ -0,0 +1,94 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/week6/settings.gradle.kts b/week6/settings.gradle.kts
new file mode 100644
index 0000000..eaaca42
--- /dev/null
+++ b/week6/settings.gradle.kts
@@ -0,0 +1,27 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+plugins {
+ id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "week4"
+include(":app")
+
\ No newline at end of file
diff --git a/week7/.gitignore b/week7/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/week7/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/week7/.idea/.gitignore b/week7/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/week7/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/week7/.idea/AndroidProjectSystem.xml b/week7/.idea/AndroidProjectSystem.xml
new file mode 100644
index 0000000..4a53bee
--- /dev/null
+++ b/week7/.idea/AndroidProjectSystem.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/.idea/compiler.xml b/week7/.idea/compiler.xml
new file mode 100644
index 0000000..b86273d
--- /dev/null
+++ b/week7/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/.idea/deploymentTargetSelector.xml b/week7/.idea/deploymentTargetSelector.xml
new file mode 100644
index 0000000..b268ef3
--- /dev/null
+++ b/week7/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/.idea/deviceManager.xml b/week7/.idea/deviceManager.xml
new file mode 100644
index 0000000..91f9558
--- /dev/null
+++ b/week7/.idea/deviceManager.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/.idea/gradle.xml b/week7/.idea/gradle.xml
new file mode 100644
index 0000000..cdbc250
--- /dev/null
+++ b/week7/.idea/gradle.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/.idea/inspectionProfiles/Project_Default.xml b/week7/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..7061a0d
--- /dev/null
+++ b/week7/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/.idea/migrations.xml b/week7/.idea/migrations.xml
new file mode 100644
index 0000000..f8051a6
--- /dev/null
+++ b/week7/.idea/migrations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/.idea/misc.xml b/week7/.idea/misc.xml
new file mode 100644
index 0000000..74dd639
--- /dev/null
+++ b/week7/.idea/misc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/.idea/runConfigurations.xml b/week7/.idea/runConfigurations.xml
new file mode 100644
index 0000000..16660f1
--- /dev/null
+++ b/week7/.idea/runConfigurations.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/.idea/vcs.xml b/week7/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/week7/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/README.md b/week7/README.md
new file mode 100644
index 0000000..8e85bab
--- /dev/null
+++ b/week7/README.md
@@ -0,0 +1 @@
+# 10th_Android
\ No newline at end of file
diff --git a/week7/app/.gitignore b/week7/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/week7/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/week7/app/.idea/.gitignore b/week7/app/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/week7/app/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/week7/app/.idea/caches/deviceStreaming.xml b/week7/app/.idea/caches/deviceStreaming.xml
new file mode 100644
index 0000000..f9eb024
--- /dev/null
+++ b/week7/app/.idea/caches/deviceStreaming.xml
@@ -0,0 +1,1808 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/.idea/libraries/R.xml b/week7/app/.idea/libraries/R.xml
new file mode 100644
index 0000000..3df2e7e
--- /dev/null
+++ b/week7/app/.idea/libraries/R.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/.idea/libraries/R2.xml b/week7/app/.idea/libraries/R2.xml
new file mode 100644
index 0000000..6a668bd
--- /dev/null
+++ b/week7/app/.idea/libraries/R2.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/.idea/libraries/base.xml b/week7/app/.idea/libraries/base.xml
new file mode 100644
index 0000000..1c23381
--- /dev/null
+++ b/week7/app/.idea/libraries/base.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/.idea/libraries/out.xml b/week7/app/.idea/libraries/out.xml
new file mode 100644
index 0000000..d7d72ee
--- /dev/null
+++ b/week7/app/.idea/libraries/out.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/.idea/misc.xml b/week7/app/.idea/misc.xml
new file mode 100644
index 0000000..1945ce5
--- /dev/null
+++ b/week7/app/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/.idea/modules.xml b/week7/app/.idea/modules.xml
new file mode 100644
index 0000000..8c4259d
--- /dev/null
+++ b/week7/app/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/.idea/vcs.xml b/week7/app/.idea/vcs.xml
new file mode 100644
index 0000000..b2bdec2
--- /dev/null
+++ b/week7/app/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/build.gradle.kts b/week7/app/build.gradle.kts
new file mode 100644
index 0000000..222c2b9
--- /dev/null
+++ b/week7/app/build.gradle.kts
@@ -0,0 +1,57 @@
+plugins {
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.kotlin.compose)
+ alias(libs.plugins.kotlin.serialization)
+}
+
+android {
+ namespace = "com.example.week7"
+ compileSdk = 36
+
+ defaultConfig {
+ applicationId = "com.example.week7"
+ minSdk = 24
+ targetSdk = 36
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+ buildFeatures {
+ compose = true
+ }
+}
+
+dependencies {
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.androidx.lifecycle.runtime.ktx)
+ implementation(libs.androidx.activity.compose)
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.androidx.compose.ui)
+ implementation(libs.androidx.compose.ui.graphics)
+ implementation(libs.androidx.compose.ui.tooling.preview)
+ implementation(libs.androidx.compose.material3)
+ implementation(libs.androidx.navigation.compose)
+ implementation(libs.kotlinx.serialization.json)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+ androidTestImplementation(platform(libs.androidx.compose.bom))
+ androidTestImplementation(libs.androidx.compose.ui.test.junit4)
+ debugImplementation(libs.androidx.compose.ui.tooling)
+ debugImplementation(libs.androidx.compose.ui.test.manifest)
+}
\ No newline at end of file
diff --git a/week7/app/proguard-rules.pro b/week7/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/week7/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/week7/app/src/androidTest/java/com/example/week7/ExampleInstrumentedTest.kt b/week7/app/src/androidTest/java/com/example/week7/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..ae243af
--- /dev/null
+++ b/week7/app/src/androidTest/java/com/example/week7/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.example.week7
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.example.week7", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/week7/app/src/main/AndroidManifest.xml b/week7/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..925b9c1
--- /dev/null
+++ b/week7/app/src/main/AndroidManifest.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/src/main/java/com/example/week7/MainActivity.kt b/week7/app/src/main/java/com/example/week7/MainActivity.kt
new file mode 100644
index 0000000..e830520
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/MainActivity.kt
@@ -0,0 +1,157 @@
+package com.example.week7
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Icon
+import androidx.compose.material3.NavigationBar
+import androidx.compose.material3.NavigationBarItem
+import androidx.compose.material3.NavigationBarItemDefaults
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Paint
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.graphics.nativeCanvas
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.navigation.NavDestination.Companion.hasRoute
+import androidx.navigation.NavDestination.Companion.hierarchy
+import androidx.navigation.NavGraph.Companion.findStartDestination
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.currentBackStackEntryAsState
+import androidx.navigation.compose.rememberNavController
+import com.example.week7.ui.*
+import com.example.week7.ui.cart.CartScreen
+import com.example.week7.ui.home.HomeScreen
+import com.example.week7.ui.profile.ProfileScreen
+import com.example.week7.ui.shop.ShopScreen
+import com.example.week7.ui.theme.Week7Theme
+import com.example.week7.ui.wishlist.WishlistScreen
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContent {
+ Week7Theme(dynamicColor = false) {
+ MainScreen()
+ }
+ }
+ }
+}
+
+@Composable
+fun MainScreen() {
+ val navController = rememberNavController()
+ Scaffold(
+ containerColor = Color.White,
+ bottomBar = { BottomNavigation(navController = navController) }
+ ) { innerPadding ->
+ Box(modifier = Modifier.padding(innerPadding)) {
+ NavigationGraph(navController = navController)
+ }
+ }
+}
+
+@Composable
+fun BottomNavigation(navController: NavHostController) {
+ val items = listOf(
+ BottomNavItem.Home,
+ BottomNavItem.Shop,
+ BottomNavItem.Wishlist,
+ BottomNavItem.Cart,
+ BottomNavItem.Profile
+ )
+ NavigationBar(
+ containerColor = Color.White,
+ contentColor = Color.Black,
+ tonalElevation = 0.dp,
+ modifier = Modifier.drawBehind {
+ drawIntoCanvas { canvas ->
+ val paint = Paint().asFrameworkPaint()
+ paint.setShadowLayer(
+ 20f,
+ 0f,
+ -4f,
+ android.graphics.Color.argb(8, 0, 0, 0)
+ )
+ canvas.nativeCanvas.drawRect(
+ 0f,
+ 0f,
+ size.width,
+ size.height,
+ paint
+ )
+ }
+ }
+ ) {
+ val navBackStackEntry by navController.currentBackStackEntryAsState()
+ val currentDestination = navBackStackEntry?.destination
+
+ items.forEach { item ->
+ val selected = currentDestination?.hierarchy?.any { it.hasRoute(item.route::class) } == true
+
+ NavigationBarItem(
+ icon = { Icon(painterResource(id = item.icon), contentDescription = item.title) },
+ label = { Text(text = item.title, fontSize = 10.sp) },
+ selected = selected,
+ onClick = {
+ navController.navigate(item.route) {
+ popUpTo(navController.graph.findStartDestination().id) {
+ saveState = true
+ }
+ launchSingleTop = true
+ restoreState = true
+ }
+ },
+ colors = NavigationBarItemDefaults.colors(
+ selectedIconColor = Color.Black,
+ unselectedIconColor = Color.Gray,
+ selectedTextColor = Color.Black,
+ unselectedTextColor = Color.Gray,
+ indicatorColor = Color.Transparent
+ )
+ )
+ }
+ }
+}
+
+@Composable
+fun NavigationGraph(navController: NavHostController) {
+ NavHost(navController, startDestination = Screen.Home) {
+ composable {
+ HomeScreen()
+ }
+ composable {
+ ShopScreen()
+ }
+ composable {
+ WishlistScreen()
+ }
+ composable {
+ CartScreen(onOrderClick = {
+ navController.navigate(Screen.Shop) {
+ popUpTo(navController.graph.findStartDestination().id) {
+ saveState = true
+ }
+ launchSingleTop = true
+ restoreState = true
+ }
+ })
+ }
+ composable {
+ ProfileScreen()
+ }
+ }
+}
diff --git a/week7/app/src/main/java/com/example/week7/ui/BottomNavItem.kt b/week7/app/src/main/java/com/example/week7/ui/BottomNavItem.kt
new file mode 100644
index 0000000..583fa76
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/ui/BottomNavItem.kt
@@ -0,0 +1,15 @@
+package com.example.week7.ui
+
+import com.example.week7.R
+
+sealed class BottomNavItem(
+ val title: String,
+ val icon: Int,
+ val route: Any
+) {
+ data object Home : BottomNavItem("홈", R.drawable.ic_housesimple, Screen.Home)
+ data object Shop : BottomNavItem("구매하기", R.drawable.ic_listmagnifyingglass, Screen.Shop)
+ data object Wishlist : BottomNavItem("위시리스트", R.drawable.ic_heartstraight, Screen.Wishlist)
+ data object Cart : BottomNavItem("장바구니", R.drawable.ic_bagsimple, Screen.Cart)
+ data object Profile : BottomNavItem("프로필", R.drawable.ic_user, Screen.Profile)
+}
diff --git a/week7/app/src/main/java/com/example/week7/ui/Screen.kt b/week7/app/src/main/java/com/example/week7/ui/Screen.kt
new file mode 100644
index 0000000..54db7ab
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/ui/Screen.kt
@@ -0,0 +1,21 @@
+package com.example.week7.ui
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+sealed interface Screen {
+ @Serializable
+ data object Home : Screen
+
+ @Serializable
+ data object Shop : Screen
+
+ @Serializable
+ data object Wishlist : Screen
+
+ @Serializable
+ data object Cart : Screen
+
+ @Serializable
+ data object Profile : Screen
+}
diff --git a/week7/app/src/main/java/com/example/week7/ui/cart/CartScreen.kt b/week7/app/src/main/java/com/example/week7/ui/cart/CartScreen.kt
new file mode 100644
index 0000000..4c88817
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/ui/cart/CartScreen.kt
@@ -0,0 +1,51 @@
+package com.example.week7.ui.cart
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.example.week7.R
+
+@Composable
+fun CartScreen(onOrderClick: () -> Unit) {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Alignment.Center
+ ) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.ic_bagcircle),
+ contentDescription = null,
+ modifier = Modifier.size(80.dp)
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(text = "장바구니가 비어 있습니다.", fontWeight = FontWeight.Bold)
+ Text(text = "제품을 추가하면 여기에 표시됩니다.", color = Color.Gray, fontSize = 12.sp)
+ }
+
+ Button(
+ onClick = onOrderClick,
+ modifier = Modifier
+ .align(Alignment.BottomCenter)
+ .padding(bottom = 32.dp)
+ .fillMaxWidth(0.8f)
+ .height(56.dp),
+ colors = ButtonDefaults.buttonColors(containerColor = Color.Black),
+ shape = RoundedCornerShape(28.dp)
+ ) {
+ Text(text = "주문하기", color = Color.White)
+ }
+ }
+}
diff --git a/week7/app/src/main/java/com/example/week7/ui/home/HomeScreen.kt b/week7/app/src/main/java/com/example/week7/ui/home/HomeScreen.kt
new file mode 100644
index 0000000..43a0a03
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/ui/home/HomeScreen.kt
@@ -0,0 +1,35 @@
+package com.example.week7.ui.home
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.example.week7.R
+
+@Composable
+fun HomeScreen() {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(16.dp)
+ ) {
+ Text(text = "Discover", fontSize = 24.sp, fontWeight = FontWeight.Bold)
+ Text(text = "10월 31일 화요일", color = Color.Gray, fontSize = 14.sp)
+ Spacer(modifier = Modifier.height(16.dp))
+ Image(
+ painter = painterResource(id = R.drawable.ic_homeimg),
+ contentDescription = null,
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(400.dp),
+ contentScale = ContentScale.Crop
+ )
+ }
+}
diff --git a/week7/app/src/main/java/com/example/week7/ui/profile/ProfileScreen.kt b/week7/app/src/main/java/com/example/week7/ui/profile/ProfileScreen.kt
new file mode 100644
index 0000000..80b5355
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/ui/profile/ProfileScreen.kt
@@ -0,0 +1,19 @@
+package com.example.week7.ui.profile
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+
+@Composable
+fun ProfileScreen() {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Alignment.Center
+ ) {
+ Text(text = "Profile Fragment", color = Color.Gray)
+ }
+}
diff --git a/week7/app/src/main/java/com/example/week7/ui/shop/ShopScreen.kt b/week7/app/src/main/java/com/example/week7/ui/shop/ShopScreen.kt
new file mode 100644
index 0000000..8f60ac7
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/ui/shop/ShopScreen.kt
@@ -0,0 +1,32 @@
+package com.example.week7.ui.shop
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun ShopScreen() {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(16.dp)
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+ Column(horizontalAlignment = Alignment.CenterHorizontally) {
+ Text(text = "전체", fontWeight = FontWeight.Bold)
+ Box(modifier = Modifier.width(40.dp).height(2.dp).background(Color.Black))
+ }
+ Text(text = "TOPS & T-SHIRTS", color = Color.Gray)
+ Text(text = "SHOES", color = Color.Gray)
+ }
+ }
+}
diff --git a/week7/app/src/main/java/com/example/week7/ui/theme/Color.kt b/week7/app/src/main/java/com/example/week7/ui/theme/Color.kt
new file mode 100644
index 0000000..1c90c81
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/ui/theme/Color.kt
@@ -0,0 +1,11 @@
+package com.example.week7.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val Purple80 = Color(0xFFD0BCFF)
+val PurpleGrey80 = Color(0xFFCCC2DC)
+val Pink80 = Color(0xFFEFB8C8)
+
+val Purple40 = Color(0xFF6650a4)
+val PurpleGrey40 = Color(0xFF625b71)
+val Pink40 = Color(0xFF7D5260)
\ No newline at end of file
diff --git a/week7/app/src/main/java/com/example/week7/ui/theme/Theme.kt b/week7/app/src/main/java/com/example/week7/ui/theme/Theme.kt
new file mode 100644
index 0000000..c284fcb
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/ui/theme/Theme.kt
@@ -0,0 +1,58 @@
+package com.example.week7.ui.theme
+
+import android.app.Activity
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+
+private val DarkColorScheme = darkColorScheme(
+ primary = Purple80,
+ secondary = PurpleGrey80,
+ tertiary = Pink80
+)
+
+private val LightColorScheme = lightColorScheme(
+ primary = Purple40,
+ secondary = PurpleGrey40,
+ tertiary = Pink40
+
+ /* Other default colors to override
+ background = Color(0xFFFFFBFE),
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+ */
+)
+
+@Composable
+fun Week7Theme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ // Dynamic color is available on Android 12+
+ dynamicColor: Boolean = true,
+ content: @Composable () -> Unit
+) {
+ val colorScheme = when {
+ dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ val context = LocalContext.current
+ if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
+ }
+
+ darkTheme -> DarkColorScheme
+ else -> LightColorScheme
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography,
+ content = content
+ )
+}
\ No newline at end of file
diff --git a/week7/app/src/main/java/com/example/week7/ui/theme/Type.kt b/week7/app/src/main/java/com/example/week7/ui/theme/Type.kt
new file mode 100644
index 0000000..f8b10c9
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/ui/theme/Type.kt
@@ -0,0 +1,34 @@
+package com.example.week7.ui.theme
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ bodyLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
+ */
+)
\ No newline at end of file
diff --git a/week7/app/src/main/java/com/example/week7/ui/wishlist/WishlistScreen.kt b/week7/app/src/main/java/com/example/week7/ui/wishlist/WishlistScreen.kt
new file mode 100644
index 0000000..e33559e
--- /dev/null
+++ b/week7/app/src/main/java/com/example/week7/ui/wishlist/WishlistScreen.kt
@@ -0,0 +1,20 @@
+package com.example.week7.ui.wishlist
+
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+
+@Composable
+fun WishlistScreen() {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(16.dp)
+ ) {
+ Text(text = "위시리스트", fontSize = 24.sp, fontWeight = FontWeight.Bold)
+ }
+}
diff --git a/week7/app/src/main/res/drawable/bg_black_round.xml b/week7/app/src/main/res/drawable/bg_black_round.xml
new file mode 100644
index 0000000..fcc2357
--- /dev/null
+++ b/week7/app/src/main/res/drawable/bg_black_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/bg_white_stroke.xml b/week7/app/src/main/res/drawable/bg_white_stroke.xml
new file mode 100644
index 0000000..4f8e667
--- /dev/null
+++ b/week7/app/src/main/res/drawable/bg_white_stroke.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_bagcircle.xml b/week7/app/src/main/res/drawable/ic_bagcircle.xml
new file mode 100644
index 0000000..1af2ce6
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_bagcircle.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_bagsimple.xml b/week7/app/src/main/res/drawable/ic_bagsimple.xml
new file mode 100644
index 0000000..3b6e816
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_bagsimple.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_caretleft.xml b/week7/app/src/main/res/drawable/ic_caretleft.xml
new file mode 100644
index 0000000..1912c2d
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_caretleft.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_heart_empty.xml b/week7/app/src/main/res/drawable/ic_heart_empty.xml
new file mode 100644
index 0000000..a7904b5
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_heart_empty.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_heart_fill.xml b/week7/app/src/main/res/drawable/ic_heart_fill.xml
new file mode 100644
index 0000000..91664d4
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_heart_fill.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_heart_filled.xml b/week7/app/src/main/res/drawable/ic_heart_filled.xml
new file mode 100644
index 0000000..67df58b
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_heart_filled.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_heartstraight.xml b/week7/app/src/main/res/drawable/ic_heartstraight.xml
new file mode 100644
index 0000000..6597a4a
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_heartstraight.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_homeimg.png b/week7/app/src/main/res/drawable/ic_homeimg.png
new file mode 100644
index 0000000..f42aa9d
Binary files /dev/null and b/week7/app/src/main/res/drawable/ic_homeimg.png differ
diff --git a/week7/app/src/main/res/drawable/ic_housesimple.xml b/week7/app/src/main/res/drawable/ic_housesimple.xml
new file mode 100644
index 0000000..a0d86b9
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_housesimple.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_launcher_background.xml b/week7/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_launcher_foreground.xml b/week7/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/src/main/res/drawable/ic_listmagnifyingglass.xml b/week7/app/src/main/res/drawable/ic_listmagnifyingglass.xml
new file mode 100644
index 0000000..483d117
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_listmagnifyingglass.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_magnifyingglass.xml b/week7/app/src/main/res/drawable/ic_magnifyingglass.xml
new file mode 100644
index 0000000..9077a42
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_magnifyingglass.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/ic_user.xml b/week7/app/src/main/res/drawable/ic_user.xml
new file mode 100644
index 0000000..1fc97b8
--- /dev/null
+++ b/week7/app/src/main/res/drawable/ic_user.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/img_air_jordan_xxxvi.png b/week7/app/src/main/res/drawable/img_air_jordan_xxxvi.png
new file mode 100644
index 0000000..19129df
Binary files /dev/null and b/week7/app/src/main/res/drawable/img_air_jordan_xxxvi.png differ
diff --git a/week7/app/src/main/res/drawable/img_nike_air_force.png b/week7/app/src/main/res/drawable/img_nike_air_force.png
new file mode 100644
index 0000000..1fc5039
Binary files /dev/null and b/week7/app/src/main/res/drawable/img_nike_air_force.png differ
diff --git a/week7/app/src/main/res/drawable/img_nike_everyday_plus_cushioned.png b/week7/app/src/main/res/drawable/img_nike_everyday_plus_cushioned.png
new file mode 100644
index 0000000..9a23c22
Binary files /dev/null and b/week7/app/src/main/res/drawable/img_nike_everyday_plus_cushioned.png differ
diff --git a/week7/app/src/main/res/drawable/img_training_ankle_socks.png b/week7/app/src/main/res/drawable/img_training_ankle_socks.png
new file mode 100644
index 0000000..04a81da
Binary files /dev/null and b/week7/app/src/main/res/drawable/img_training_ankle_socks.png differ
diff --git a/week7/app/src/main/res/drawable/sl_item_wishlist_icon.xml b/week7/app/src/main/res/drawable/sl_item_wishlist_icon.xml
new file mode 100644
index 0000000..7ca06ad
--- /dev/null
+++ b/week7/app/src/main/res/drawable/sl_item_wishlist_icon.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/sl_wishlist_icon.xml b/week7/app/src/main/res/drawable/sl_wishlist_icon.xml
new file mode 100644
index 0000000..3e176b9
--- /dev/null
+++ b/week7/app/src/main/res/drawable/sl_wishlist_icon.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/week7/app/src/main/res/drawable/sl_wishlist_tint.xml b/week7/app/src/main/res/drawable/sl_wishlist_tint.xml
new file mode 100644
index 0000000..78fdb7c
--- /dev/null
+++ b/week7/app/src/main/res/drawable/sl_wishlist_tint.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/week7/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/week7/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/week7/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/week7/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/week7/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/week7/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/week7/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/week7/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/week7/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/week7/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/week7/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/week7/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/week7/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/week7/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/week7/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/week7/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/week7/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/week7/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/week7/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/week7/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/week7/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/week7/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/week7/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/week7/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/week7/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/week7/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/week7/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/week7/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/week7/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/week7/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/week7/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/week7/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/week7/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/week7/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/week7/app/src/main/res/values/colors.xml b/week7/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..db3d209
--- /dev/null
+++ b/week7/app/src/main/res/values/colors.xml
@@ -0,0 +1,14 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
+
+ #999999
+ #000000
+
\ No newline at end of file
diff --git a/week7/app/src/main/res/values/strings.xml b/week7/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..c4a351a
--- /dev/null
+++ b/week7/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ week7
+
\ No newline at end of file
diff --git a/week7/app/src/main/res/values/themes.xml b/week7/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..e5a02b7
--- /dev/null
+++ b/week7/app/src/main/res/values/themes.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/src/main/res/xml/backup_rules.xml b/week7/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..4df9255
--- /dev/null
+++ b/week7/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/src/main/res/xml/data_extraction_rules.xml b/week7/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/week7/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/week7/app/src/test/java/com/example/week7/ExampleUnitTest.kt b/week7/app/src/test/java/com/example/week7/ExampleUnitTest.kt
new file mode 100644
index 0000000..45b6c58
--- /dev/null
+++ b/week7/app/src/test/java/com/example/week7/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.example.week7
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/week7/build.gradle.kts b/week7/build.gradle.kts
new file mode 100644
index 0000000..371e867
--- /dev/null
+++ b/week7/build.gradle.kts
@@ -0,0 +1,6 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.kotlin.compose) apply false
+ alias(libs.plugins.kotlin.serialization) apply false
+}
diff --git a/week7/gradle.properties b/week7/gradle.properties
new file mode 100644
index 0000000..34c5e9e
--- /dev/null
+++ b/week7/gradle.properties
@@ -0,0 +1,15 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# org.gradle.parallel=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
\ No newline at end of file
diff --git a/week7/gradle/gradle-daemon-jvm.properties b/week7/gradle/gradle-daemon-jvm.properties
new file mode 100644
index 0000000..6c1139e
--- /dev/null
+++ b/week7/gradle/gradle-daemon-jvm.properties
@@ -0,0 +1,12 @@
+#This file is generated by updateDaemonJvm
+toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
+toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
+toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
+toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
+toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73bcfb608d1fde9fb62e462f834a3299/redirect
+toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/846ee0d876d26a26f37aa1ce8de73224/redirect
+toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
+toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
+toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9482ddec596298c84656d31d16652665/redirect
+toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/39701d92e1756bb2f141eb67cd4c660e/redirect
+toolchainVersion=21
diff --git a/week7/gradle/libs.versions.toml b/week7/gradle/libs.versions.toml
new file mode 100644
index 0000000..e672c4d
--- /dev/null
+++ b/week7/gradle/libs.versions.toml
@@ -0,0 +1,35 @@
+[versions]
+agp = "9.1.1"
+coreKtx = "1.18.0"
+junit = "4.13.2"
+junitVersion = "1.3.0"
+espressoCore = "3.7.0"
+lifecycleRuntimeKtx = "2.10.0"
+activityCompose = "1.13.0"
+kotlin = "2.2.10"
+composeBom = "2024.09.00"
+navigationCompose = "2.9.8"
+kotlinxSerializationJson = "1.7.3"
+
+[libraries]
+androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+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" }
+androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
+androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
+androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
+androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
+androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
+androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
+androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
+androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
+androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
+androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
+androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
+kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
+kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
diff --git a/week7/gradle/wrapper/gradle-wrapper.jar b/week7/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8bdaf60
Binary files /dev/null and b/week7/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/week7/gradle/wrapper/gradle-wrapper.properties b/week7/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..30f6cbe
--- /dev/null
+++ b/week7/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,9 @@
+#Sun May 17 15:33:46 KST 2026
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionSha256Sum=b266d5ff6b90eada6dc3b20cb090e3731302e553a27c5d3e4df1f0d76beaff06
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/week7/gradlew b/week7/gradlew
new file mode 100644
index 0000000..ef07e01
--- /dev/null
+++ b/week7/gradlew
@@ -0,0 +1,251 @@
+#!/bin/sh
+
+#
+# Copyright © 2015 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH="\\\"\\\""
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/week7/gradlew.bat b/week7/gradlew.bat
new file mode 100644
index 0000000..db3a6ac
--- /dev/null
+++ b/week7/gradlew.bat
@@ -0,0 +1,94 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/week7/settings.gradle.kts b/week7/settings.gradle.kts
new file mode 100644
index 0000000..753967f
--- /dev/null
+++ b/week7/settings.gradle.kts
@@ -0,0 +1,26 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+plugins {
+ id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "week7"
+include(":app")