diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f3f0a1f..c52060b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -68,6 +68,8 @@ dependencies { implementation(libs.room.runtime) implementation(libs.room.ktx) implementation(libs.fragment.ktx) + implementation(libs.activity.ktx) + implementation(libs.viewpager2) implementation(libs.androidx.core.ktx) implementation(libs.androidx.appcompat) diff --git a/app/src/main/java/com/flab/deepsleep/MainActivity.kt b/app/src/main/java/com/flab/deepsleep/MainActivity.kt index 02ed439..a0d34c5 100644 --- a/app/src/main/java/com/flab/deepsleep/MainActivity.kt +++ b/app/src/main/java/com/flab/deepsleep/MainActivity.kt @@ -5,22 +5,29 @@ import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.core.widget.doOnTextChanged +import androidx.viewpager2.widget.ViewPager2 import com.flab.deepsleep.databinding.ActivityMainBinding -import com.flab.deepsleep.ui.home.HomeFragment +import com.flab.deepsleep.ui.adapter.ViewPagerAdapter import com.flab.deepsleep.ui.photo.PhotoViewModel +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class MainActivity : AppCompatActivity() { private val photoViewModel: PhotoViewModel by viewModels() private val binding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) } + private val tabLayout: TabLayout by lazy { binding.tabLayout } + private val viewPager: ViewPager2 by lazy { binding.viewPager } + private val viewPagerAdapter: ViewPagerAdapter by lazy { ViewPagerAdapter(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(binding.root) - setHomeFragment(); + setViewPager() /* 검색어 입력시 자동 호출 */ binding.editText.doOnTextChanged { text, start, before, count -> @@ -29,16 +36,21 @@ class MainActivity : AppCompatActivity() { /* 에러 관찰 */ photoViewModel.errorMessage.observe(/* owner = */ this) { it -> - it?.let { - showErrorDialog(it) - } + it?.let { showErrorDialog(it) } } } - private fun setHomeFragment(){ - supportFragmentManager.beginTransaction() - .replace(binding.mainFragment.id, HomeFragment()) - .commit() + private fun setViewPager() { + viewPager.adapter = viewPagerAdapter + val tabIcons = listOf(R.drawable.ic_home, R.drawable.ic_bookmark) + TabLayoutMediator(tabLayout, viewPager) { tab, position -> + tab.icon = ContextCompat.getDrawable(this, tabIcons[position]) + tab.text = when (position) { + 0 -> "홈" + 1 -> "북마크" + else -> "탭 ${position + 1}" + } + }.attach() } private fun showErrorDialog(message: String) { diff --git a/app/src/main/java/com/flab/deepsleep/ui/photo/PhotoAdapter.kt b/app/src/main/java/com/flab/deepsleep/ui/adapter/PagingAdapter.kt similarity index 91% rename from app/src/main/java/com/flab/deepsleep/ui/photo/PhotoAdapter.kt rename to app/src/main/java/com/flab/deepsleep/ui/adapter/PagingAdapter.kt index 737f3c7..a9222bb 100644 --- a/app/src/main/java/com/flab/deepsleep/ui/photo/PhotoAdapter.kt +++ b/app/src/main/java/com/flab/deepsleep/ui/adapter/PagingAdapter.kt @@ -1,3 +1,5 @@ +package com.flab.deepsleep.ui.adapter + import android.view.LayoutInflater import android.view.ViewGroup import android.widget.ImageView @@ -10,8 +12,8 @@ import com.flab.deepsleep.data.entity.photos.SinglePhoto import com.flab.deepsleep.databinding.ItemPhotoBinding import com.flab.deepsleep.ui.photo.OnButtonClick -class PhotoAdapter(private val buttonClick: OnButtonClick) : - PagingDataAdapter(ARTICLE_DIFF_CALLBACK) { +class PagingAdapter(private val buttonClick: OnButtonClick) : + PagingDataAdapter(ARTICLE_DIFF_CALLBACK) { inner class ImageViewHolder( private val binding: ItemPhotoBinding, diff --git a/app/src/main/java/com/flab/deepsleep/ui/adapter/ViewPagerAdapter.kt b/app/src/main/java/com/flab/deepsleep/ui/adapter/ViewPagerAdapter.kt new file mode 100644 index 0000000..02b2798 --- /dev/null +++ b/app/src/main/java/com/flab/deepsleep/ui/adapter/ViewPagerAdapter.kt @@ -0,0 +1,20 @@ +package com.flab.deepsleep.ui.adapter + +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.flab.deepsleep.MainActivity +import com.flab.deepsleep.ui.fragment.BookmarkFragment +import com.flab.deepsleep.ui.fragment.HomeFragment + +class ViewPagerAdapter(mainActivity: MainActivity) : FragmentStateAdapter(mainActivity) { + override fun getItemCount(): Int = 2 + + override fun createFragment(position: Int): Fragment { + return when (position) { + 0 -> HomeFragment() + 1 -> BookmarkFragment() + else -> HomeFragment() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/flab/deepsleep/ui/fragment/BookmarkFragment.kt b/app/src/main/java/com/flab/deepsleep/ui/fragment/BookmarkFragment.kt new file mode 100644 index 0000000..7921f72 --- /dev/null +++ b/app/src/main/java/com/flab/deepsleep/ui/fragment/BookmarkFragment.kt @@ -0,0 +1,23 @@ +package com.flab.deepsleep.ui.fragment + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.flab.deepsleep.databinding.FragmentBookmarkBinding +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class BookmarkFragment : Fragment() { + + private val binding: FragmentBookmarkBinding by lazy { FragmentBookmarkBinding.inflate(layoutInflater) } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View { + return binding.root + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/flab/deepsleep/ui/home/HomeFragment.kt b/app/src/main/java/com/flab/deepsleep/ui/fragment/HomeFragment.kt similarity index 59% rename from app/src/main/java/com/flab/deepsleep/ui/home/HomeFragment.kt rename to app/src/main/java/com/flab/deepsleep/ui/fragment/HomeFragment.kt index 82bd691..f4a0f5b 100644 --- a/app/src/main/java/com/flab/deepsleep/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/flab/deepsleep/ui/fragment/HomeFragment.kt @@ -1,15 +1,13 @@ -package com.flab.deepsleep.ui.home +package com.flab.deepsleep.ui.fragment -import PhotoAdapter +import com.flab.deepsleep.ui.adapter.PagingAdapter import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.viewModels import androidx.fragment.app.Fragment -import androidx.lifecycle.Lifecycle +import androidx.fragment.app.activityViewModels import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.flab.deepsleep.databinding.FragmentHomeBinding @@ -17,15 +15,14 @@ import com.flab.deepsleep.ui.photo.PhotoViewModel import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -import timber.log.Timber @AndroidEntryPoint class HomeFragment : Fragment() { - private val photoViewModel: PhotoViewModel by viewModels() - val binding: FragmentHomeBinding by lazy { FragmentHomeBinding.inflate(layoutInflater) } + private val binding: FragmentHomeBinding by lazy { FragmentHomeBinding.inflate(layoutInflater) } + private val photoViewModel: PhotoViewModel by activityViewModels() private val photoRecyclerView: RecyclerView by lazy { binding.photosRecyclerView } - private val photoAdapter: PhotoAdapter by lazy { - PhotoAdapter { singlePhoto -> + private val pagingAdapter: PagingAdapter by lazy { + PagingAdapter { singlePhoto -> photoViewModel.insertPhoto(singlePhoto) } } @@ -40,21 +37,16 @@ class HomeFragment : Fragment() { super.onViewCreated(view, savedInstanceState) setRecyclerView() - viewLifecycleOwner.lifecycleScope.launch { - Timber.d("HomeFragment Coroutine 시작됨 (onViewCreated)") // 로그 추가 - viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { - photoViewModel.items.collectLatest { - photoAdapter.submitData(it) - - Timber.d("HomeFragment $it") - } + photoViewModel.items.collectLatest { pagingData -> + pagingAdapter.submitData(pagingData) } } } + private fun setRecyclerView() { photoRecyclerView.layoutManager = GridLayoutManager(context, 2) - photoRecyclerView.adapter = photoAdapter + photoRecyclerView.adapter = pagingAdapter } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bookmark.xml b/app/src/main/res/drawable/ic_bookmark.xml new file mode 100644 index 0000000..2989e8d --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_home.xml b/app/src/main/res/drawable/ic_home.xml new file mode 100644 index 0000000..5f0e5bf --- /dev/null +++ b/app/src/main/res/drawable/ic_home.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index cec8169..8a1e3dd 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,70 +5,67 @@ android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" tools:context=".MainActivity"> + app:layout_constraintTop_toTopOf="parent"> + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - + app:layout_constraintStart_toEndOf="@+id/editText" + app:layout_constraintTop_toTopOf="@+id/editText" /> - - - - - - - - - - - + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/search_bar" /> - + app:tabMode="fixed" /> - + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_bookmark.xml b/app/src/main/res/layout/fragment_bookmark.xml new file mode 100644 index 0000000..bdaab61 --- /dev/null +++ b/app/src/main/res/layout/fragment_bookmark.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 0750c2b..0142a56 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -1,7 +1,6 @@ @@ -9,7 +8,6 @@ android:id="@+id/photosRecyclerView" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/black" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index c8524cd..f5b12e0 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -2,4 +2,7 @@ #FF000000 #FFFFFFFF + + #F2F2F2 + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 476f59e..3dc8d5a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,6 +28,8 @@ okhttp-profiler = "1.0.8" room = "2.6.1" ksp = "2.0.21-1.0.27" fragment-ktx = "1.8.5" +activity-ktx = "1.10.0" +viewpager2 = "1.1.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -59,7 +61,9 @@ okhttp-profiler = { module = "com.localebro:okhttpprofiler", version.ref = "okht room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } -fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragment-ktx"} +fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragment-ktx" } +activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activity-ktx" } +viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "viewpager2" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }