From 520a766c7a3fdbbea7add6b23742d90e147e9fbd Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Mon, 16 Oct 2023 22:12:24 +0900 Subject: [PATCH 01/24] =?UTF-8?q?feat:=20OpenLetter=20=EB=A7=A4=ED=8D=BC?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/now/naaga/data/mapper/OpenLetterMapper.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 android/app/src/main/java/com/now/naaga/data/mapper/OpenLetterMapper.kt diff --git a/android/app/src/main/java/com/now/naaga/data/mapper/OpenLetterMapper.kt b/android/app/src/main/java/com/now/naaga/data/mapper/OpenLetterMapper.kt new file mode 100644 index 000000000..f21120598 --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/data/mapper/OpenLetterMapper.kt @@ -0,0 +1,14 @@ +package com.now.naaga.data.mapper + +import com.now.domain.model.letter.OpenLetter +import com.now.naaga.data.remote.dto.OpenLetterDto + +fun OpenLetterDto.toDomain(): OpenLetter { + return OpenLetter( + id = id, + player = player.toDomain(), + coordinate = coordinateDto.toDomain(), + message = message, + registerDate = registerDate, + ) +} From a8912df8f9fcdb0ce5d7a782f37e034f94d7015b Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Mon, 16 Oct 2023 22:25:00 +0900 Subject: [PATCH 02/24] =?UTF-8?q?feat:=20AdventureDetailViewModel=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/DefaultLetterRepository.kt | 2 +- .../AdventureDetailViewModel.kt | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt diff --git a/android/app/src/main/java/com/now/naaga/data/repository/DefaultLetterRepository.kt b/android/app/src/main/java/com/now/naaga/data/repository/DefaultLetterRepository.kt index b11e8ee1b..558325544 100644 --- a/android/app/src/main/java/com/now/naaga/data/repository/DefaultLetterRepository.kt +++ b/android/app/src/main/java/com/now/naaga/data/repository/DefaultLetterRepository.kt @@ -25,6 +25,6 @@ class DefaultLetterRepository( } override suspend fun fetchLetterLogs(gameId: Long, logType: LogType): List<OpenLetter> { - TODO("Not yet implemented") + return letterService.getInGameLetters(gameId, logType.name).getValueOrThrow().map { it.toDomain() } } } diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt new file mode 100644 index 000000000..b52405f26 --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt @@ -0,0 +1,51 @@ +package com.now.naaga.presentation.adventuredetail + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.now.domain.model.letter.OpenLetter +import com.now.domain.model.type.LogType +import com.now.domain.repository.LetterRepository +import com.now.naaga.data.throwable.DataThrowable +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import java.io.IOException +import javax.inject.Inject + +@HiltViewModel +class AdventureDetailViewModel @Inject constructor(private val letterRepository: LetterRepository) : ViewModel() { + private val _readLetters = MutableLiveData<List<OpenLetter>>() + val readLetters: LiveData<List<OpenLetter>> = _readLetters + + private val _writeLetters = MutableLiveData<List<OpenLetter>>() + val writeLetters: LiveData<List<OpenLetter>> = _writeLetters + + private val _throwable = MutableLiveData<DataThrowable>() + val throwable: LiveData<DataThrowable> = _throwable + + fun fetchLetterLogs(gameId: Long, logType: LogType) { + viewModelScope.launch { + runCatching { + letterRepository.fetchLetterLogs(gameId, logType) + }.onSuccess { + setLetters(logType, it) + }.onFailure { + setThrowable(it) + } + } + } + + private fun setLetters(logType: LogType, letters: List<OpenLetter>) { + when (logType) { + LogType.READ -> _readLetters.value = letters + LogType.WRITE -> _writeLetters.value = letters + } + } + + private fun setThrowable(throwable: Throwable) { + when (throwable) { + is IOException -> { TODO("_throwable.value = DataThrowable.NetworkThrowable") } + } + } +} From 04cc1a9ae95c1db0bfb9c05cb977a70f5bc367c7 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Mon, 16 Oct 2023 22:25:11 +0900 Subject: [PATCH 03/24] =?UTF-8?q?test:=20AdventureDetailViewModel=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../now/naaga/AdventureDetailViewModelTest.kt | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 android/app/src/test/java/com/now/naaga/AdventureDetailViewModelTest.kt diff --git a/android/app/src/test/java/com/now/naaga/AdventureDetailViewModelTest.kt b/android/app/src/test/java/com/now/naaga/AdventureDetailViewModelTest.kt new file mode 100644 index 000000000..4ba7f38c4 --- /dev/null +++ b/android/app/src/test/java/com/now/naaga/AdventureDetailViewModelTest.kt @@ -0,0 +1,92 @@ +package com.now.naaga + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import com.now.domain.model.Coordinate +import com.now.domain.model.Player +import com.now.domain.model.letter.OpenLetter +import com.now.domain.model.type.LogType +import com.now.domain.repository.LetterRepository +import com.now.naaga.presentation.adventuredetail.AdventureDetailViewModel +import io.mockk.coEvery +import io.mockk.mockk +import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertTrue +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.setMain +import org.junit.Before +import org.junit.Rule +import org.junit.Test + +class AdventureDetailViewModelTest { + private lateinit var vm: AdventureDetailViewModel + private lateinit var letterRepository: LetterRepository + + @get:Rule + val instantExecutorRule = InstantTaskExecutorRule() + + @OptIn(ExperimentalCoroutinesApi::class) + @Before + fun setup() { + Dispatchers.setMain(UnconfinedTestDispatcher()) + letterRepository = mockk() + vm = AdventureDetailViewModel(letterRepository) + } + + @Test + fun `읽은 쪽지를 불러올 때 작성한 쪽지는 불러오지 않는다`() { + // given + coEvery { + letterRepository.fetchLetterLogs(1L, LogType.READ) + } coAnswers { + fakeReadLetterLogs + } + + // when + vm.fetchLetterLogs(1L, LogType.READ) + + // then + assertTrue(vm.readLetters.isInitialized) + assertEquals(vm.readLetters.getOrAwaitValue(), fakeReadLetterLogs) + assertEquals(vm.writeLetters.isInitialized, false) + } + + @Test + fun `작성한 쪽지를 불러올 때 읽은 쪽지는 불러오지 않는다`() { + // given + coEvery { + letterRepository.fetchLetterLogs(1L, LogType.WRITE) + } coAnswers { + fakeWriteLetterLogs + } + + // when + vm.fetchLetterLogs(1L, LogType.WRITE) + + // then + assertEquals(vm.readLetters.isInitialized, false) + assertTrue(vm.writeLetters.isInitialized) + assertEquals(vm.writeLetters.getOrAwaitValue(), fakeWriteLetterLogs) + } + + private val fakeReadLetterLogs = listOf( + OpenLetter( + id = 1L, + player = Player(1L, "krrong", 1234), + coordinate = Coordinate(123.0, 123.0), + message = "Hello im krrong", + registerDate = "now", + ), + ) + + private val fakeWriteLetterLogs = listOf( + OpenLetter( + id = 1L, + player = Player(1L, "notKrrong", 1212), + coordinate = Coordinate(123.0, 123.0), + message = "i was krrong", + registerDate = "now", + ), + ) +} From 82c3344e4770f0fa9349955faf14f7949033064d Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Mon, 16 Oct 2023 22:28:12 +0900 Subject: [PATCH 04/24] =?UTF-8?q?feat:=20LetterThrowable=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/now/naaga/data/throwable/DataThrowable.kt | 3 +++ .../presentation/adventuredetail/AdventureDetailViewModel.kt | 1 + .../src/main/java/com/now/naaga/util/extension/ResponseExt.kt | 1 + 3 files changed, 5 insertions(+) diff --git a/android/app/src/main/java/com/now/naaga/data/throwable/DataThrowable.kt b/android/app/src/main/java/com/now/naaga/data/throwable/DataThrowable.kt index 60172c5dd..dfec68f37 100644 --- a/android/app/src/main/java/com/now/naaga/data/throwable/DataThrowable.kt +++ b/android/app/src/main/java/com/now/naaga/data/throwable/DataThrowable.kt @@ -19,6 +19,9 @@ sealed class DataThrowable(val code: Int, message: String) : Throwable(message) // http 응답코드 500번대, body가 null일 때의 에러 class IllegalStateThrowable : DataThrowable(ILLEGAL_STATE_THROWABLE_CODE, ILLEGAL_STATE_THROWABLE_MESSAGE) + // 700번대 쪽지 관련 에러 + class LetterThrowable(code: Int, message: String) : DataThrowable(code, message) + companion object { const val ILLEGAL_STATE_THROWABLE_CODE = 900 const val ILLEGAL_STATE_THROWABLE_MESSAGE = "잘못된 값입니다." diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt index b52405f26..8654465d3 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt @@ -46,6 +46,7 @@ class AdventureDetailViewModel @Inject constructor(private val letterRepository: private fun setThrowable(throwable: Throwable) { when (throwable) { is IOException -> { TODO("_throwable.value = DataThrowable.NetworkThrowable") } + is DataThrowable.LetterThrowable -> { _throwable.value = throwable } } } } diff --git a/android/app/src/main/java/com/now/naaga/util/extension/ResponseExt.kt b/android/app/src/main/java/com/now/naaga/util/extension/ResponseExt.kt index 6a395d35b..ff848f9dd 100644 --- a/android/app/src/main/java/com/now/naaga/util/extension/ResponseExt.kt +++ b/android/app/src/main/java/com/now/naaga/util/extension/ResponseExt.kt @@ -39,6 +39,7 @@ fun <T> Response<T>.getValueOrThrow(): T { in 300..399 -> { throw DataThrowable.PlayerThrowable(code, message) } in 400..499 -> { throw DataThrowable.GameThrowable(code, message) } in 500..599 -> { throw DataThrowable.PlaceThrowable(code, message) } + in 700..799 -> { throw DataThrowable.LetterThrowable(code, message) } } } throw DataThrowable.IllegalStateThrowable() From 81c7c24b19d06526e15258287d76a21951f181d2 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 02:31:48 +0900 Subject: [PATCH 05/24] =?UTF-8?q?feat:=20=EC=9D=BD=EC=9D=80=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=80,=20=EB=93=B1=EB=A1=9D=ED=95=9C=20=ED=8E=B8=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20=EC=9D=BD=EC=9D=84=20=EC=88=98=20=EC=9E=88=EB=8A=94?= =?UTF-8?q?=20=EB=B7=B0=ED=8E=98=EC=9D=B4=EC=A0=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdventureDetailActivity.kt | 28 ++++++++ .../recyclerview/LetterAdapter.kt | 19 +++++ .../recyclerview/LetterViewHolder.kt | 20 ++++++ .../viewpager/ViewPagerAdapter.kt | 19 +++++ .../viewpager/ViewPagerHolder.kt | 19 +++++ .../uimodel/mapper/OpenLetterMapper.kt | 12 ++++ .../uimodel/model/OpenLetterUiModel.kt | 7 ++ .../res/layout/activity_adventure_detail.xml | 71 +++++++++++++++++++ .../app/src/main/res/layout/item_letter.xml | 58 +++++++++++++++ .../src/main/res/layout/item_view_pager.xml | 27 +++++++ 10 files changed, 280 insertions(+) create mode 100644 android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt create mode 100644 android/app/src/main/java/com/now/naaga/presentation/adventuredetail/recyclerview/LetterAdapter.kt create mode 100644 android/app/src/main/java/com/now/naaga/presentation/adventuredetail/recyclerview/LetterViewHolder.kt create mode 100644 android/app/src/main/java/com/now/naaga/presentation/adventuredetail/viewpager/ViewPagerAdapter.kt create mode 100644 android/app/src/main/java/com/now/naaga/presentation/adventuredetail/viewpager/ViewPagerHolder.kt create mode 100644 android/app/src/main/java/com/now/naaga/presentation/uimodel/mapper/OpenLetterMapper.kt create mode 100644 android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt create mode 100644 android/app/src/main/res/layout/activity_adventure_detail.xml create mode 100644 android/app/src/main/res/layout/item_letter.xml create mode 100644 android/app/src/main/res/layout/item_view_pager.xml diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt new file mode 100644 index 000000000..b5d9e2aac --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt @@ -0,0 +1,28 @@ +package com.now.naaga.presentation.adventuredetail + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.now.naaga.databinding.ActivityAdventureDetailBinding +import com.now.naaga.presentation.adventuredetail.viewpager.ViewPagerAdapter +import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel + +class AdventureDetailActivity : AppCompatActivity() { + private lateinit var binding: ActivityAdventureDetailBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityAdventureDetailBinding.inflate(layoutInflater) + setContentView(binding.root) + + initViewPager() + } + + private fun initViewPager() { + binding.vpAdventureDetail.adapter = ViewPagerAdapter( + listOf( + List(10) { OpenLetterUiModel("krrong", "today", "meesage") }, + List(10) { OpenLetterUiModel("krrong", "today", "meesage") }, + ), + ) + } +} diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/recyclerview/LetterAdapter.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/recyclerview/LetterAdapter.kt new file mode 100644 index 000000000..02c530369 --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/recyclerview/LetterAdapter.kt @@ -0,0 +1,19 @@ +package com.now.naaga.presentation.adventuredetail.recyclerview + +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel + +class LetterAdapter(private val letters: List<OpenLetterUiModel>) : RecyclerView.Adapter<LetterViewHolder>() { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LetterViewHolder { + return LetterViewHolder(parent) + } + + override fun onBindViewHolder(holder: LetterViewHolder, position: Int) { + holder.bind(letters[position]) + } + + override fun getItemCount(): Int { + return letters.size + } +} diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/recyclerview/LetterViewHolder.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/recyclerview/LetterViewHolder.kt new file mode 100644 index 000000000..59397c036 --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/recyclerview/LetterViewHolder.kt @@ -0,0 +1,20 @@ +package com.now.naaga.presentation.adventuredetail.recyclerview + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.now.naaga.R +import com.now.naaga.databinding.ItemLetterBinding +import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel + +class LetterViewHolder(parent: ViewGroup) : RecyclerView.ViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.item_letter, parent, false), +) { + private val binding: ItemLetterBinding = ItemLetterBinding.bind(itemView) + + fun bind(letter: OpenLetterUiModel) { + binding.tvItemLetterNickname.text = letter.nickname + binding.tvItemLetterRegisterDate.text = letter.registerDate + binding.tvItemLetter.text = letter.message + } +} diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/viewpager/ViewPagerAdapter.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/viewpager/ViewPagerAdapter.kt new file mode 100644 index 000000000..bc798a627 --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/viewpager/ViewPagerAdapter.kt @@ -0,0 +1,19 @@ +package com.now.naaga.presentation.adventuredetail.viewpager + +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel + +class ViewPagerAdapter(private val data: List<List<OpenLetterUiModel>>) : RecyclerView.Adapter<ViewPagerHolder>() { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerHolder { + return ViewPagerHolder(parent) + } + + override fun onBindViewHolder(holder: ViewPagerHolder, position: Int) { + holder.bind(data[position]) + } + + override fun getItemCount(): Int { + return data.size + } +} diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/viewpager/ViewPagerHolder.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/viewpager/ViewPagerHolder.kt new file mode 100644 index 000000000..32f82fd29 --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/viewpager/ViewPagerHolder.kt @@ -0,0 +1,19 @@ +package com.now.naaga.presentation.adventuredetail.viewpager + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.now.naaga.R +import com.now.naaga.databinding.ItemViewPagerBinding +import com.now.naaga.presentation.adventuredetail.recyclerview.LetterAdapter +import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel + +class ViewPagerHolder(parent: ViewGroup) : RecyclerView.ViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.item_view_pager, parent, false), +) { + private val binding: ItemViewPagerBinding = ItemViewPagerBinding.bind(itemView) + + fun bind(data: List<OpenLetterUiModel>) { + binding.rvItemViewPager.adapter = LetterAdapter(data) + } +} diff --git a/android/app/src/main/java/com/now/naaga/presentation/uimodel/mapper/OpenLetterMapper.kt b/android/app/src/main/java/com/now/naaga/presentation/uimodel/mapper/OpenLetterMapper.kt new file mode 100644 index 000000000..9ac140c3b --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/presentation/uimodel/mapper/OpenLetterMapper.kt @@ -0,0 +1,12 @@ +package com.now.naaga.presentation.uimodel.mapper + +import com.now.domain.model.letter.OpenLetter +import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel + +fun OpenLetter.toUiModel(): OpenLetterUiModel { + return OpenLetterUiModel( + nickname = player.nickname, + registerDate = registerDate, + message = message, + ) +} diff --git a/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt b/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt new file mode 100644 index 000000000..08a286b89 --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt @@ -0,0 +1,7 @@ +package com.now.naaga.presentation.uimodel.model + +data class OpenLetterUiModel( + val nickname: String, + val registerDate: String, + val message: String, +) diff --git a/android/app/src/main/res/layout/activity_adventure_detail.xml b/android/app/src/main/res/layout/activity_adventure_detail.xml new file mode 100644 index 000000000..56a425b8a --- /dev/null +++ b/android/app/src/main/res/layout/activity_adventure_detail.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".presentation.adventuredetail.AdventureDetailActivity"> + + <ImageView + android:id="@+id/iv_adventure_detail_back" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginTop="16dp" + android:paddingHorizontal="20dp" + android:paddingVertical="@dimen/space_default_medium" + android:src="@drawable/ic_arrow" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/tv_adventure_detail_place_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="루터회관" + android:textSize="28sp" + app:layout_constraintBottom_toBottomOf="@id/iv_adventure_detail_back" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@id/iv_adventure_detail_back" /> + + <ImageView + android:id="@+id/iv_adventure_detail_photo" + android:layout_width="250dp" + android:layout_height="250dp" + android:layout_marginTop="@dimen/space_default_large" + android:background="@drawable/rect_radius_small" + android:scaleType="centerCrop" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/tv_adventure_detail_place_title" + app:layout_constraintBottom_toTopOf="@id/vp_adventure_detail" + tools:srcCompat="@tools:sample/avatars" /> + +<!-- <com.google.android.material.tabs.TabLayout--> +<!-- android:id="@+id/tl_adventure_detail"--> +<!-- android:layout_width="0dp"--> +<!-- android:layout_height="wrap_content"--> +<!-- app:layout_constraintBottom_toTopOf="@id/vp_adventure_detail"--> +<!-- app:layout_constraintEnd_toEndOf="parent"--> +<!-- app:layout_constraintStart_toStartOf="parent"--> +<!-- app:layout_constraintTop_toBottomOf="@id/iv_adventure_detail_photo" />--> + + <androidx.viewpager2.widget.ViewPager2 + android:id="@+id/vp_adventure_detail" + android:layout_width="0dp" + android:layout_height="0dp" + android:orientation="horizontal" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/iv_adventure_detail_photo" /> + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> diff --git a/android/app/src/main/res/layout/item_letter.xml b/android/app/src/main/res/layout/item_letter.xml new file mode 100644 index 000000000..9fc2d81a5 --- /dev/null +++ b/android/app/src/main/res/layout/item_letter.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/space_default_large" + android:layout_marginTop="@dimen/space_default_medium" + android:background="@drawable/rect_red_white_radius_small"> + + <TextView + android:id="@+id/tv_item_letter_nickname" + android:layout_width="0dp" + android:layout_height="20dp" + android:layout_marginStart="@dimen/space_default_large" + android:layout_marginTop="@dimen/space_default_medium" + android:textColor="@color/main_dark_blue" + android:textSize="12sp" + app:layout_constraintEnd_toStartOf="@id/tv_item_letter_register_date" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="krrong" /> + + <TextView + android:id="@+id/tv_item_letter_register_date" + android:layout_width="0dp" + android:layout_height="20dp" + android:layout_marginTop="@dimen/space_default_medium" + android:layout_marginEnd="@dimen/space_default_large" + android:gravity="end" + android:textColor="@color/main_dark_blue" + android:textSize="12sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/tv_item_letter_nickname" + app:layout_constraintTop_toTopOf="parent" + tools:text="2023-07-03" /> + + <TextView + android:id="@+id/tv_item_letter" + android:layout_width="0dp" + android:layout_height="40dp" + android:layout_marginBottom="@dimen/space_default_large" + android:gravity="center" + android:textColor="@color/main_dark_blue" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@id/tv_item_letter_register_date" + app:layout_constraintStart_toStartOf="@id/tv_item_letter_nickname" + app:layout_constraintTop_toBottomOf="@id/tv_item_letter_nickname" + tools:text="여기 뷰 미쳤다!" /> + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> diff --git a/android/app/src/main/res/layout/item_view_pager.xml b/android/app/src/main/res/layout/item_view_pager.xml new file mode 100644 index 000000000..fc63578aa --- /dev/null +++ b/android/app/src/main/res/layout/item_view_pager.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <data> + + </data> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/rv_item_view_pager" + android:layout_width="0dp" + android:layout_height="match_parent" + app:layout_constraintEnd_toEndOf="parent" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + android:orientation="vertical" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:listitem="@layout/item_letter" /> + + </androidx.constraintlayout.widget.ConstraintLayout> +</layout> From 96c762f86ac64fd016e5dafca8c3df84d59939a8 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 02:36:56 +0900 Subject: [PATCH 06/24] =?UTF-8?q?feat:=20=EB=B7=B0=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A0=80,=20=ED=83=AD=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdventureDetailActivity.kt | 8 ++++++++ .../res/layout/activity_adventure_detail.xml | 20 +++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt index b5d9e2aac..1e74ab32c 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt @@ -2,6 +2,7 @@ package com.now.naaga.presentation.adventuredetail import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.tabs.TabLayoutMediator import com.now.naaga.databinding.ActivityAdventureDetailBinding import com.now.naaga.presentation.adventuredetail.viewpager.ViewPagerAdapter import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel @@ -24,5 +25,12 @@ class AdventureDetailActivity : AppCompatActivity() { List(10) { OpenLetterUiModel("krrong", "today", "meesage") }, ), ) + + TabLayoutMediator(binding.tlAdventureDetail, binding.vpAdventureDetail) { tab, position -> + when (position) { + 0 -> tab.text = "읽은 편지" + 1 -> tab.text = "등록한 편지" + } + }.attach() } } diff --git a/android/app/src/main/res/layout/activity_adventure_detail.xml b/android/app/src/main/res/layout/activity_adventure_detail.xml index 56a425b8a..c7e8b403a 100644 --- a/android/app/src/main/res/layout/activity_adventure_detail.xml +++ b/android/app/src/main/res/layout/activity_adventure_detail.xml @@ -45,17 +45,17 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_adventure_detail_place_title" - app:layout_constraintBottom_toTopOf="@id/vp_adventure_detail" + app:layout_constraintBottom_toTopOf="@id/tl_adventure_detail" tools:srcCompat="@tools:sample/avatars" /> -<!-- <com.google.android.material.tabs.TabLayout--> -<!-- android:id="@+id/tl_adventure_detail"--> -<!-- android:layout_width="0dp"--> -<!-- android:layout_height="wrap_content"--> -<!-- app:layout_constraintBottom_toTopOf="@id/vp_adventure_detail"--> -<!-- app:layout_constraintEnd_toEndOf="parent"--> -<!-- app:layout_constraintStart_toStartOf="parent"--> -<!-- app:layout_constraintTop_toBottomOf="@id/iv_adventure_detail_photo" />--> + <com.google.android.material.tabs.TabLayout + android:id="@+id/tl_adventure_detail" + android:layout_width="0dp" + android:layout_height="wrap_content" + app:layout_constraintBottom_toTopOf="@id/vp_adventure_detail" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/iv_adventure_detail_photo" /> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/vp_adventure_detail" @@ -65,7 +65,7 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/iv_adventure_detail_photo" /> + app:layout_constraintTop_toBottomOf="@id/tl_adventure_detail" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout> From f05ca63efb68d23736e1cbfa07ac04fed0c63652 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 02:39:25 +0900 Subject: [PATCH 07/24] =?UTF-8?q?feat:=20radius=EB=A5=BC=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EB=AA=85=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/main/res/drawable/rect_red_white_radius_small.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/src/main/res/drawable/rect_red_white_radius_small.xml b/android/app/src/main/res/drawable/rect_red_white_radius_small.xml index 779dcce22..959ac4a2c 100644 --- a/android/app/src/main/res/drawable/rect_red_white_radius_small.xml +++ b/android/app/src/main/res/drawable/rect_red_white_radius_small.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - <corners android:radius="@dimen/radius_medium" /> + <corners android:radius="@dimen/radius_small" /> <solid android:color="@color/red_white" /> </shape> From aa544f973fd1ae39934850c78f43de9c4281ded7 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 02:40:37 +0900 Subject: [PATCH 08/24] =?UTF-8?q?refactor:=20=EB=B7=B0=20=EB=A7=88?= =?UTF-8?q?=EC=A7=84,=20=EB=B0=B0=EA=B2=BD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/res/layout/activity_adventure_detail.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/res/layout/activity_adventure_detail.xml b/android/app/src/main/res/layout/activity_adventure_detail.xml index c7e8b403a..1696af176 100644 --- a/android/app/src/main/res/layout/activity_adventure_detail.xml +++ b/android/app/src/main/res/layout/activity_adventure_detail.xml @@ -42,16 +42,18 @@ android:layout_marginTop="@dimen/space_default_large" android:background="@drawable/rect_radius_small" android:scaleType="centerCrop" + app:layout_constraintBottom_toTopOf="@id/tl_adventure_detail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_adventure_detail_place_title" - app:layout_constraintBottom_toTopOf="@id/tl_adventure_detail" tools:srcCompat="@tools:sample/avatars" /> <com.google.android.material.tabs.TabLayout android:id="@+id/tl_adventure_detail" android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_marginHorizontal="4dp" + android:background="@drawable/rect_red_white_radius_small" app:layout_constraintBottom_toTopOf="@id/vp_adventure_detail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" From 3e30f2b0efae7e6d058e07937d594d1f25037f16 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 02:41:18 +0900 Subject: [PATCH 09/24] =?UTF-8?q?refactor:=20text=EB=A5=BC=20tools?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/res/layout/activity_adventure_detail.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/res/layout/activity_adventure_detail.xml b/android/app/src/main/res/layout/activity_adventure_detail.xml index 1696af176..d8c4f7ae5 100644 --- a/android/app/src/main/res/layout/activity_adventure_detail.xml +++ b/android/app/src/main/res/layout/activity_adventure_detail.xml @@ -28,12 +28,12 @@ android:id="@+id/tv_adventure_detail_place_title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="루터회관" android:textSize="28sp" app:layout_constraintBottom_toBottomOf="@id/iv_adventure_detail_back" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="@id/iv_adventure_detail_back" /> + app:layout_constraintTop_toTopOf="@id/iv_adventure_detail_back" + tools:text="루터회관" /> <ImageView android:id="@+id/iv_adventure_detail_photo" From 33f74259b862d5f9dbc859c7cbeb7cd908e00dac Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 02:57:20 +0900 Subject: [PATCH 10/24] =?UTF-8?q?refactor:=20=EB=A7=88=EC=A7=84=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/res/layout/activity_adventure_detail.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/android/app/src/main/res/layout/activity_adventure_detail.xml b/android/app/src/main/res/layout/activity_adventure_detail.xml index d8c4f7ae5..6eb8d23c2 100644 --- a/android/app/src/main/res/layout/activity_adventure_detail.xml +++ b/android/app/src/main/res/layout/activity_adventure_detail.xml @@ -53,6 +53,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginHorizontal="4dp" + android:layout_marginTop="@dimen/space_default_medium" android:background="@drawable/rect_red_white_radius_small" app:layout_constraintBottom_toTopOf="@id/vp_adventure_detail" app:layout_constraintEnd_toEndOf="parent" From 22781e54932360635df19a45520f217d057546d9 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 11:53:11 +0900 Subject: [PATCH 11/24] =?UTF-8?q?feat:=20=EC=9D=BD=EC=9D=80=20=EC=AA=BD?= =?UTF-8?q?=EC=A7=80,=20=EB=93=B1=EB=A1=9D=ED=95=9C=20=EC=AA=BD=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20flow=EB=A1=9C=20combine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdventureDetailActivity.kt | 52 ++++++++++++++-- .../adventuredetail/AdventureDetailUiState.kt | 14 +++++ .../AdventureDetailViewModel.kt | 59 ++++++++++++++----- 3 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailUiState.kt diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt index 1e74ab32c..ce70f90e6 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt @@ -1,28 +1,58 @@ package com.now.naaga.presentation.adventuredetail +import android.content.Context +import android.content.Intent import android.os.Bundle +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import com.google.android.material.tabs.TabLayoutMediator +import com.now.naaga.data.firebase.analytics.AnalyticsDelegate +import com.now.naaga.data.firebase.analytics.DefaultAnalyticsDelegate import com.now.naaga.databinding.ActivityAdventureDetailBinding import com.now.naaga.presentation.adventuredetail.viewpager.ViewPagerAdapter -import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch -class AdventureDetailActivity : AppCompatActivity() { +@AndroidEntryPoint +class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by DefaultAnalyticsDelegate() { private lateinit var binding: ActivityAdventureDetailBinding + private val viewModel: AdventureDetailViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityAdventureDetailBinding.inflate(layoutInflater) setContentView(binding.root) - initViewPager() + initView() + subscribe() } - private fun initViewPager() { + private fun initView() { + viewModel.fetchReadLetter(1L) + viewModel.fetchWriteLetter(1L) + } + + private fun subscribe() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.uiState.collect { adventureDetailUiState -> + when (adventureDetailUiState) { + is AdventureDetailUiState.Loading, is AdventureDetailUiState.Error -> Unit + is AdventureDetailUiState.Success -> initViewPager(adventureDetailUiState) + } + } + } + } + } + + private fun initViewPager(adventureDetailUiState: AdventureDetailUiState.Success) { binding.vpAdventureDetail.adapter = ViewPagerAdapter( listOf( - List(10) { OpenLetterUiModel("krrong", "today", "meesage") }, - List(10) { OpenLetterUiModel("krrong", "today", "meesage") }, + adventureDetailUiState.readLetters, + adventureDetailUiState.writeLetters, ), ) @@ -33,4 +63,14 @@ class AdventureDetailActivity : AppCompatActivity() { } }.attach() } + + companion object { + private const val GAME_ID = "GAME_ID" + + fun getIntentWithId(context: Context, gameId: Long): Intent { + return Intent(context, AdventureDetailActivity::class.java).apply { + putExtra(GAME_ID, gameId) + } + } + } } diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailUiState.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailUiState.kt new file mode 100644 index 000000000..496ccff37 --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailUiState.kt @@ -0,0 +1,14 @@ +package com.now.naaga.presentation.adventuredetail + +import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel + +sealed interface AdventureDetailUiState { + object Loading : AdventureDetailUiState + + data class Success( + val readLetters: List<OpenLetterUiModel>, + val writeLetters: List<OpenLetterUiModel>, + ) : AdventureDetailUiState + + object Error : AdventureDetailUiState +} diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt index 8654465d3..c0dd90a13 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt @@ -8,45 +8,72 @@ import com.now.domain.model.letter.OpenLetter import com.now.domain.model.type.LogType import com.now.domain.repository.LetterRepository import com.now.naaga.data.throwable.DataThrowable +import com.now.naaga.presentation.uimodel.mapper.toUiModel import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import java.io.IOException import javax.inject.Inject @HiltViewModel -class AdventureDetailViewModel @Inject constructor(private val letterRepository: LetterRepository) : ViewModel() { - private val _readLetters = MutableLiveData<List<OpenLetter>>() - val readLetters: LiveData<List<OpenLetter>> = _readLetters +class AdventureDetailViewModel @Inject constructor( + private val letterRepository: LetterRepository, +) : ViewModel() { + private val readLettersFlow = MutableSharedFlow<List<OpenLetter>>() - private val _writeLetters = MutableLiveData<List<OpenLetter>>() - val writeLetters: LiveData<List<OpenLetter>> = _writeLetters + private val writeLettersFlow = MutableSharedFlow<List<OpenLetter>>() + + private val _uiState: MutableStateFlow<AdventureDetailUiState> = MutableStateFlow(AdventureDetailUiState.Loading) + val uiState: StateFlow<AdventureDetailUiState> = _uiState.asStateFlow() private val _throwable = MutableLiveData<DataThrowable>() val throwable: LiveData<DataThrowable> = _throwable - fun fetchLetterLogs(gameId: Long, logType: LogType) { + init { + viewModelScope.launch { + combine(readLettersFlow, writeLettersFlow) { readLetters, writeLetters -> + AdventureDetailUiState.Success( + readLetters = readLetters.map { it.toUiModel() }, + writeLetters = writeLetters.map { it.toUiModel() }, + ) + }.collectLatest { _uiState.value = it } + } + } + + fun fetchReadLetter(gameId: Long) { viewModelScope.launch { runCatching { - letterRepository.fetchLetterLogs(gameId, logType) + letterRepository.fetchLetterLogs(gameId, LogType.READ) }.onSuccess { - setLetters(logType, it) - }.onFailure { - setThrowable(it) + readLettersFlow.emit(it) } } } - private fun setLetters(logType: LogType, letters: List<OpenLetter>) { - when (logType) { - LogType.READ -> _readLetters.value = letters - LogType.WRITE -> _writeLetters.value = letters + fun fetchWriteLetter(gameId: Long) { + viewModelScope.launch { + runCatching { + letterRepository.fetchLetterLogs(gameId, LogType.WRITE) + }.onSuccess { + writeLettersFlow.emit(it) + } } } private fun setThrowable(throwable: Throwable) { when (throwable) { - is IOException -> { TODO("_throwable.value = DataThrowable.NetworkThrowable") } - is DataThrowable.LetterThrowable -> { _throwable.value = throwable } + is IOException -> { + TODO("_throwable.value = DataThrowable.NetworkThrowable") + } + + is DataThrowable.LetterThrowable -> { + _throwable.value = throwable + } } } } From 97e847847520e30a2540adbfbd652c268d91874f Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 12:19:16 +0900 Subject: [PATCH 12/24] =?UTF-8?q?feat:=20=EB=AA=A8=ED=97=98=20=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=20=EC=83=81=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99=ED=95=98=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdventureHistoryActivity.kt | 8 +++++++- .../recyclerview/AdventureHistoryAdapter.kt | 8 ++++++-- .../AdventureHistoryViewHolder.kt | 19 +++++++++++++------ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/AdventureHistoryActivity.kt b/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/AdventureHistoryActivity.kt index 20ed236f9..f9c4a48ca 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/AdventureHistoryActivity.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/AdventureHistoryActivity.kt @@ -7,6 +7,7 @@ import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import com.now.domain.model.AdventureResult import com.now.naaga.databinding.ActivityAdventureHistoryBinding +import com.now.naaga.presentation.adventuredetail.AdventureDetailActivity import com.now.naaga.presentation.adventurehistory.recyclerview.AdventureHistoryAdapter import dagger.hilt.android.AndroidEntryPoint @@ -14,7 +15,7 @@ import dagger.hilt.android.AndroidEntryPoint class AdventureHistoryActivity : AppCompatActivity() { private lateinit var binding: ActivityAdventureHistoryBinding private val viewModel: AdventureHistoryViewModel by viewModels() - private val historyAdapter = AdventureHistoryAdapter() + private val historyAdapter = AdventureHistoryAdapter(::navigateDetail) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -50,6 +51,11 @@ class AdventureHistoryActivity : AppCompatActivity() { historyAdapter.submitList(adventureResults) } + private fun navigateDetail(gameId: Long) { + val intent = AdventureDetailActivity.getIntentWithId(this, gameId) + startActivity(intent) + } + companion object { fun getIntent(context: Context): Intent { return Intent(context, AdventureHistoryActivity::class.java) diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/recyclerview/AdventureHistoryAdapter.kt b/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/recyclerview/AdventureHistoryAdapter.kt index 4a4647d46..0cdfc5b85 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/recyclerview/AdventureHistoryAdapter.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/recyclerview/AdventureHistoryAdapter.kt @@ -5,9 +5,13 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import com.now.domain.model.AdventureResult -class AdventureHistoryAdapter : ListAdapter<AdventureResult, AdventureHistoryViewHolder>(historyDiff) { +class AdventureHistoryAdapter( + private val onClick: (Long) -> Unit, +) : ListAdapter<AdventureResult, AdventureHistoryViewHolder>(historyDiff) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AdventureHistoryViewHolder { - return AdventureHistoryViewHolder(AdventureHistoryViewHolder.getView(parent)) + return AdventureHistoryViewHolder(parent) { position -> + onClick(getItem(position).gameId) + } } override fun onBindViewHolder(holder: AdventureHistoryViewHolder, position: Int) { diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/recyclerview/AdventureHistoryViewHolder.kt b/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/recyclerview/AdventureHistoryViewHolder.kt index 3f4b0768b..9d75ae055 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/recyclerview/AdventureHistoryViewHolder.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventurehistory/recyclerview/AdventureHistoryViewHolder.kt @@ -9,7 +9,19 @@ import com.now.domain.model.type.AdventureResultType import com.now.naaga.R import com.now.naaga.databinding.ItemHistoryBinding -class AdventureHistoryViewHolder(private val binding: ItemHistoryBinding) : RecyclerView.ViewHolder(binding.root) { +class AdventureHistoryViewHolder( + parent: ViewGroup, + onClick: (Int) -> Unit, +) : RecyclerView.ViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.item_history, parent, false), +) { + + private val binding: ItemHistoryBinding = ItemHistoryBinding.bind(itemView) + + init { + binding.root.setOnClickListener { onClick(adapterPosition) } + } + fun bind(adventureResult: AdventureResult) { binding.adventureResult = adventureResult Glide.with(binding.ivAdventureHistoryPhoto) @@ -38,10 +50,5 @@ class AdventureHistoryViewHolder(private val binding: ItemHistoryBinding) : Recy companion object { private const val DESTINATION_NAME_IN_FAILURE_CASE = "????" - - fun getView(parent: ViewGroup): ItemHistoryBinding { - val layoutInflater = LayoutInflater.from(parent.context) - return ItemHistoryBinding.inflate(layoutInflater, parent, false) - } } } From f81a799195eeed4d25878aef308e3b03039e1efe Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 12:21:18 +0900 Subject: [PATCH 13/24] =?UTF-8?q?feat:=20=EB=92=A4=EB=A1=9C=EA=B0=80?= =?UTF-8?q?=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/adventuredetail/AdventureDetailActivity.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt index ce70f90e6..158a2da3f 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt @@ -27,6 +27,7 @@ class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by Defaul setContentView(binding.root) initView() + setClickListeners() subscribe() } @@ -35,6 +36,10 @@ class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by Defaul viewModel.fetchWriteLetter(1L) } + private fun setClickListeners() { + binding.ivAdventureDetailBack.setOnClickListener { finish() } + } + private fun subscribe() { lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { From 4c5d6964f9041038e916c40509b4e4ba5a8f304c Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 12:26:50 +0900 Subject: [PATCH 14/24] =?UTF-8?q?feat:=20=EB=84=98=EA=B2=A8=EC=A4=80=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=20id=EB=A5=BC=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adventuredetail/AdventureDetailActivity.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt index 158a2da3f..3bbf52905 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt @@ -26,14 +26,16 @@ class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by Defaul binding = ActivityAdventureDetailBinding.inflate(layoutInflater) setContentView(binding.root) - initView() + val gameId = intent.getLongExtra(KET_GAME_ID, 0L) + + initView(gameId) setClickListeners() subscribe() } - private fun initView() { - viewModel.fetchReadLetter(1L) - viewModel.fetchWriteLetter(1L) + private fun initView(gameId: Long) { + viewModel.fetchReadLetter(gameId) + viewModel.fetchWriteLetter(gameId) } private fun setClickListeners() { @@ -70,11 +72,11 @@ class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by Defaul } companion object { - private const val GAME_ID = "GAME_ID" + private const val KET_GAME_ID = "GAME_ID" fun getIntentWithId(context: Context, gameId: Long): Intent { return Intent(context, AdventureDetailActivity::class.java).apply { - putExtra(GAME_ID, gameId) + putExtra(KET_GAME_ID, gameId) } } } From 01c0d09fd73ed69ba65dbcc80d2fd1c30e0fc840 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 12:46:15 +0900 Subject: [PATCH 15/24] =?UTF-8?q?feat:=20=EA=B2=8C=EC=9E=84=20id=EB=A1=9C?= =?UTF-8?q?=20=EA=B2=8C=EC=9E=84=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=99=80=20=EB=B3=B4=EC=97=AC=EC=A3=BC=EB=8A=94=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdventureDetailActivity.kt | 28 +++++++++++++------ .../adventuredetail/AdventureDetailUiState.kt | 2 ++ .../AdventureDetailViewModel.kt | 18 +++++++++++- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt index 3bbf52905..9f54d0e3a 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt @@ -8,11 +8,15 @@ import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import com.bumptech.glide.Glide import com.google.android.material.tabs.TabLayoutMediator +import com.now.domain.model.AdventureResult +import com.now.naaga.R import com.now.naaga.data.firebase.analytics.AnalyticsDelegate import com.now.naaga.data.firebase.analytics.DefaultAnalyticsDelegate import com.now.naaga.databinding.ActivityAdventureDetailBinding import com.now.naaga.presentation.adventuredetail.viewpager.ViewPagerAdapter +import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @@ -36,6 +40,7 @@ class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by Defaul private fun initView(gameId: Long) { viewModel.fetchReadLetter(gameId) viewModel.fetchWriteLetter(gameId) + viewModel.fetchAdventureResult(gameId) } private fun setClickListeners() { @@ -48,20 +53,20 @@ class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by Defaul viewModel.uiState.collect { adventureDetailUiState -> when (adventureDetailUiState) { is AdventureDetailUiState.Loading, is AdventureDetailUiState.Error -> Unit - is AdventureDetailUiState.Success -> initViewPager(adventureDetailUiState) + is AdventureDetailUiState.Success -> initView(adventureDetailUiState) } } } } } - private fun initViewPager(adventureDetailUiState: AdventureDetailUiState.Success) { - binding.vpAdventureDetail.adapter = ViewPagerAdapter( - listOf( - adventureDetailUiState.readLetters, - adventureDetailUiState.writeLetters, - ), - ) + private fun initView(adventureDetailUiState: AdventureDetailUiState.Success) { + initViewPager(adventureDetailUiState.readLetters, adventureDetailUiState.writeLetters) + initImage(adventureDetailUiState.adventureResult) + } + + private fun initViewPager(readLetters: List<OpenLetterUiModel>, writeLetters: List<OpenLetterUiModel>) { + binding.vpAdventureDetail.adapter = ViewPagerAdapter(listOf(readLetters, writeLetters)) TabLayoutMediator(binding.tlAdventureDetail, binding.vpAdventureDetail) { tab, position -> when (position) { @@ -71,6 +76,13 @@ class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by Defaul }.attach() } + private fun initImage(adventureResult: AdventureResult) { + Glide.with(binding.ivAdventureDetailPhoto) + .load(adventureResult.destination.image) + .error(R.drawable.ic_none_photo) + .into(binding.ivAdventureDetailPhoto) + } + companion object { private const val KET_GAME_ID = "GAME_ID" diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailUiState.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailUiState.kt index 496ccff37..722897e00 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailUiState.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailUiState.kt @@ -1,5 +1,6 @@ package com.now.naaga.presentation.adventuredetail +import com.now.domain.model.AdventureResult import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel sealed interface AdventureDetailUiState { @@ -8,6 +9,7 @@ sealed interface AdventureDetailUiState { data class Success( val readLetters: List<OpenLetterUiModel>, val writeLetters: List<OpenLetterUiModel>, + val adventureResult: AdventureResult, ) : AdventureDetailUiState object Error : AdventureDetailUiState diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt index c0dd90a13..fbf937229 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt @@ -4,8 +4,10 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.now.domain.model.AdventureResult import com.now.domain.model.letter.OpenLetter import com.now.domain.model.type.LogType +import com.now.domain.repository.AdventureRepository import com.now.domain.repository.LetterRepository import com.now.naaga.data.throwable.DataThrowable import com.now.naaga.presentation.uimodel.mapper.toUiModel @@ -23,11 +25,14 @@ import javax.inject.Inject @HiltViewModel class AdventureDetailViewModel @Inject constructor( private val letterRepository: LetterRepository, + private val adventureRepository: AdventureRepository, ) : ViewModel() { private val readLettersFlow = MutableSharedFlow<List<OpenLetter>>() private val writeLettersFlow = MutableSharedFlow<List<OpenLetter>>() + private val adventureFlow = MutableSharedFlow<AdventureResult>() + private val _uiState: MutableStateFlow<AdventureDetailUiState> = MutableStateFlow(AdventureDetailUiState.Loading) val uiState: StateFlow<AdventureDetailUiState> = _uiState.asStateFlow() @@ -36,10 +41,11 @@ class AdventureDetailViewModel @Inject constructor( init { viewModelScope.launch { - combine(readLettersFlow, writeLettersFlow) { readLetters, writeLetters -> + combine(readLettersFlow, writeLettersFlow, adventureFlow) { readLetters, writeLetters, adventureResult -> AdventureDetailUiState.Success( readLetters = readLetters.map { it.toUiModel() }, writeLetters = writeLetters.map { it.toUiModel() }, + adventureResult = adventureResult, ) }.collectLatest { _uiState.value = it } } @@ -65,6 +71,16 @@ class AdventureDetailViewModel @Inject constructor( } } + fun fetchAdventureResult(gameId: Long) { + viewModelScope.launch { + runCatching { + adventureRepository.fetchAdventureResult(gameId) + }.onSuccess { + adventureFlow.emit(it) + } + } + } + private fun setThrowable(throwable: Throwable) { when (throwable) { is IOException -> { From 4df847175a8f4304271d9ee35939ef7383a18f31 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 12:49:01 +0900 Subject: [PATCH 16/24] =?UTF-8?q?refactor:=20string=20resource=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/adventuredetail/AdventureDetailActivity.kt | 4 ++-- android/app/src/main/res/values/strings.xml | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt index 9f54d0e3a..448e2e575 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt @@ -70,8 +70,8 @@ class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by Defaul TabLayoutMediator(binding.tlAdventureDetail, binding.vpAdventureDetail) { tab, position -> when (position) { - 0 -> tab.text = "읽은 편지" - 1 -> tab.text = "등록한 편지" + 0 -> tab.text = getString(R.string.adventure_detail_read_letter) + 1 -> tab.text = getString(R.string.adventure_detail_write_letter) } }.attach() } diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index fcf8cdddc..00d7de1ac 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -114,6 +114,10 @@ <string name="setting_question_email">naaganow@gmail.com</string> <string name="setting_question_email_title">[나아가에게 문의하기]</string> + <!-- AdventureDetailActivity --> + <string name="adventure_detail_read_letter">읽은 편지</string> + <string name="adventure_detail_write_letter">등록한 편지</string> + <!-- WithdrawalDialog --> <string name="withdrawal_dialog_title">정말 회원 탈퇴를 하시겠습니까?</string> <string name="withdrawal_dialog_description">나아가와 함께 즐거운 모험을 계속해보세요!</string> From 94fced68f79c4a2b48de4af39c4697a447ad931f Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 14:48:46 +0900 Subject: [PATCH 17/24] =?UTF-8?q?refactor:=20string=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 00d7de1ac..c3c27b0bb 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -115,8 +115,8 @@ <string name="setting_question_email_title">[나아가에게 문의하기]</string> <!-- AdventureDetailActivity --> - <string name="adventure_detail_read_letter">읽은 편지</string> - <string name="adventure_detail_write_letter">등록한 편지</string> + <string name="adventure_detail_read_letter">읽은 쪽지</string> + <string name="adventure_detail_write_letter">등록한 쪽지</string> <!-- WithdrawalDialog --> <string name="withdrawal_dialog_title">정말 회원 탈퇴를 하시겠습니까?</string> From 0c29e97bc1b809589335e4647e57675d02a64c87 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 15:11:14 +0900 Subject: [PATCH 18/24] =?UTF-8?q?feat:=20=EB=93=B1=EB=A1=9D=EB=90=9C=20?= =?UTF-8?q?=EC=AA=BD=EC=A7=80=EA=B0=80=20=EC=97=86=EB=8A=94=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EC=AA=BD=EC=A7=80=EA=B0=80=20=EC=97=86=EB=8B=A4?= =?UTF-8?q?=EB=8A=94=20=EB=82=B4=EC=9A=A9=EC=9D=84=20=EB=B3=B4=EC=97=AC?= =?UTF-8?q?=EC=A3=BC=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adventuredetail/AdventureDetailViewModel.kt | 10 ++++++++-- .../presentation/uimodel/model/OpenLetterUiModel.kt | 10 +++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt index fbf937229..c7b678665 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt @@ -11,6 +11,7 @@ import com.now.domain.repository.AdventureRepository import com.now.domain.repository.LetterRepository import com.now.naaga.data.throwable.DataThrowable import com.now.naaga.presentation.uimodel.mapper.toUiModel +import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -43,14 +44,19 @@ class AdventureDetailViewModel @Inject constructor( viewModelScope.launch { combine(readLettersFlow, writeLettersFlow, adventureFlow) { readLetters, writeLetters, adventureResult -> AdventureDetailUiState.Success( - readLetters = readLetters.map { it.toUiModel() }, - writeLetters = writeLetters.map { it.toUiModel() }, + readLetters = getOpenLetterUiModels(readLetters), + writeLetters = getOpenLetterUiModels(writeLetters), adventureResult = adventureResult, ) }.collectLatest { _uiState.value = it } } } + private fun getOpenLetterUiModels(letters: List<OpenLetter>): List<OpenLetterUiModel> { + if (letters.isEmpty()) return listOf(OpenLetterUiModel.getDefault()) + return letters.map { it.toUiModel() } + } + fun fetchReadLetter(gameId: Long) { viewModelScope.launch { runCatching { diff --git a/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt b/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt index 08a286b89..e8df08386 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt @@ -4,4 +4,12 @@ data class OpenLetterUiModel( val nickname: String, val registerDate: String, val message: String, -) +) { + companion object { + private const val DEFAULT_MESSAGE = "쪽지가 없습니다." + + fun getDefault(): OpenLetterUiModel { + return OpenLetterUiModel("", "", DEFAULT_MESSAGE) + } + } +} From 9b2c5fddb14beeddc74b3bb1264ed16ae0b20c15 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 15:40:19 +0900 Subject: [PATCH 19/24] =?UTF-8?q?feat:=20=EC=9D=B4=EB=B2=A4=ED=8A=B8?= =?UTF-8?q?=EA=B0=80=20=EC=97=86=EB=8A=94=20=EC=8A=A4=EB=82=B5=EB=B0=94=20?= =?UTF-8?q?=ED=99=95=EC=9E=A5=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/src/main/java/com/now/naaga/util/extension/ViewExt.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/app/src/main/java/com/now/naaga/util/extension/ViewExt.kt b/android/app/src/main/java/com/now/naaga/util/extension/ViewExt.kt index 13ba67de4..a39c872bf 100644 --- a/android/app/src/main/java/com/now/naaga/util/extension/ViewExt.kt +++ b/android/app/src/main/java/com/now/naaga/util/extension/ViewExt.kt @@ -10,3 +10,7 @@ fun View.showSnackbarWithEvent(message: String, actionTitle: String, action: () action() }.setAnimationMode(ANIMATION_MODE_SLIDE).show() } + +fun View.showSnackbar(message: String) { + Snackbar.make(this, message, Snackbar.LENGTH_SHORT).setAnimationMode(ANIMATION_MODE_SLIDE).show() +} From c7e75894fe28cad56df73e45b5e011bf83f8cf62 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 15:47:59 +0900 Subject: [PATCH 20/24] =?UTF-8?q?feat:=20=EC=98=88=EC=83=81=20=EA=B0=80?= =?UTF-8?q?=EB=8A=A5=ED=95=9C=20=EC=98=88=EC=99=B8=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdventureDetailActivity.kt | 19 +++++++++++ .../AdventureDetailViewModel.kt | 34 +++++++++++++------ android/app/src/main/res/values/strings.xml | 2 ++ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt index 448e2e575..1f1b21554 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt @@ -17,6 +17,7 @@ import com.now.naaga.data.firebase.analytics.DefaultAnalyticsDelegate import com.now.naaga.databinding.ActivityAdventureDetailBinding import com.now.naaga.presentation.adventuredetail.viewpager.ViewPagerAdapter import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel +import com.now.naaga.util.extension.showSnackbarWithEvent import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @@ -58,6 +59,24 @@ class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by Defaul } } } + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.throwableFlow.collect { event -> + when (event) { + is AdventureDetailViewModel.Event.NetworkExceptionEvent -> showReRequestSnackbar() + is AdventureDetailViewModel.Event.LetterExceptionEvent -> showReRequestSnackbar() + is AdventureDetailViewModel.Event.GameExceptionEvent -> showReRequestSnackbar() + } + } + } + } + } + + private fun showReRequestSnackbar() { + binding.root.showSnackbarWithEvent( + message = getString(R.string.snackbar_action_re_request_message), + actionTitle = getString(R.string.snackbar_action__re_request_title), + ) { finish() } } private fun initView(adventureDetailUiState: AdventureDetailUiState.Success) { diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt index c7b678665..84efa37c2 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt @@ -1,7 +1,5 @@ package com.now.naaga.presentation.adventuredetail -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.now.domain.model.AdventureResult @@ -15,7 +13,9 @@ import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine @@ -37,8 +37,8 @@ class AdventureDetailViewModel @Inject constructor( private val _uiState: MutableStateFlow<AdventureDetailUiState> = MutableStateFlow(AdventureDetailUiState.Loading) val uiState: StateFlow<AdventureDetailUiState> = _uiState.asStateFlow() - private val _throwable = MutableLiveData<DataThrowable>() - val throwable: LiveData<DataThrowable> = _throwable + private val _throwableFlow = MutableSharedFlow<Event>() + val throwableFlow: SharedFlow<Event> = _throwableFlow.asSharedFlow() init { viewModelScope.launch { @@ -63,6 +63,8 @@ class AdventureDetailViewModel @Inject constructor( letterRepository.fetchLetterLogs(gameId, LogType.READ) }.onSuccess { readLettersFlow.emit(it) + }.onFailure { + setThrowable(it) } } } @@ -73,6 +75,8 @@ class AdventureDetailViewModel @Inject constructor( letterRepository.fetchLetterLogs(gameId, LogType.WRITE) }.onSuccess { writeLettersFlow.emit(it) + }.onFailure { + setThrowable(it) } } } @@ -83,19 +87,29 @@ class AdventureDetailViewModel @Inject constructor( adventureRepository.fetchAdventureResult(gameId) }.onSuccess { adventureFlow.emit(it) + }.onFailure { + setThrowable(it) } } } private fun setThrowable(throwable: Throwable) { when (throwable) { - is IOException -> { - TODO("_throwable.value = DataThrowable.NetworkThrowable") - } + is IOException -> throwable(Event.NetworkExceptionEvent(throwable)) + is DataThrowable.LetterThrowable -> throwable(Event.LetterExceptionEvent(throwable)) + is DataThrowable.GameThrowable -> throwable(Event.GameExceptionEvent(throwable)) + } + } - is DataThrowable.LetterThrowable -> { - _throwable.value = throwable - } + private fun throwable(event: Event) { + viewModelScope.launch { + _throwableFlow.emit(event) } } + + sealed class Event { + data class NetworkExceptionEvent(val throwable: Throwable) : Event() + data class LetterExceptionEvent(val throwable: Throwable) : Event() + data class GameExceptionEvent(val throwable: Throwable) : Event() + } } diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index c3c27b0bb..97cb5ad7c 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -140,6 +140,8 @@ <string name="snackbar_location_message">위치 권한이 필요해요!</string> <string name="snackbar_storage_message">저장소 권한이 필요해요!</string> <string name="snackbar_action_title">이동하기</string> + <string name="snackbar_action_re_request_message">다시 요청해주세요!</string> + <string name="snackbar_action__re_request_title">나가기</string> <!-- SendLetterDialog --> <string name="send_letter_dialog_hint">이 곳에 내용을 작성해주세요!</string> From 0e9a035100c6b2b9a75975c2ebd520e84bee633c Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 15:50:05 +0900 Subject: [PATCH 21/24] =?UTF-8?q?refactor:=20repeatOnStarted=20=ED=99=95?= =?UTF-8?q?=EC=9E=A5=ED=95=A8=EC=88=98=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdventureDetailActivity.kt | 31 +++++++------------ .../naaga/util/extension/LifeCycleOwnerExt.kt | 14 +++++++++ 2 files changed, 26 insertions(+), 19 deletions(-) create mode 100644 android/app/src/main/java/com/now/naaga/util/extension/LifeCycleOwnerExt.kt diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt index 1f1b21554..950a6700c 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailActivity.kt @@ -5,9 +5,6 @@ import android.content.Intent import android.os.Bundle import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle import com.bumptech.glide.Glide import com.google.android.material.tabs.TabLayoutMediator import com.now.domain.model.AdventureResult @@ -17,9 +14,9 @@ import com.now.naaga.data.firebase.analytics.DefaultAnalyticsDelegate import com.now.naaga.databinding.ActivityAdventureDetailBinding import com.now.naaga.presentation.adventuredetail.viewpager.ViewPagerAdapter import com.now.naaga.presentation.uimodel.model.OpenLetterUiModel +import com.now.naaga.util.extension.repeatOnStarted import com.now.naaga.util.extension.showSnackbarWithEvent import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch @AndroidEntryPoint class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by DefaultAnalyticsDelegate() { @@ -49,24 +46,20 @@ class AdventureDetailActivity : AppCompatActivity(), AnalyticsDelegate by Defaul } private fun subscribe() { - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.uiState.collect { adventureDetailUiState -> - when (adventureDetailUiState) { - is AdventureDetailUiState.Loading, is AdventureDetailUiState.Error -> Unit - is AdventureDetailUiState.Success -> initView(adventureDetailUiState) - } + repeatOnStarted { + viewModel.uiState.collect { adventureDetailUiState -> + when (adventureDetailUiState) { + is AdventureDetailUiState.Loading, is AdventureDetailUiState.Error -> Unit + is AdventureDetailUiState.Success -> initView(adventureDetailUiState) } } } - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.throwableFlow.collect { event -> - when (event) { - is AdventureDetailViewModel.Event.NetworkExceptionEvent -> showReRequestSnackbar() - is AdventureDetailViewModel.Event.LetterExceptionEvent -> showReRequestSnackbar() - is AdventureDetailViewModel.Event.GameExceptionEvent -> showReRequestSnackbar() - } + repeatOnStarted { + viewModel.throwableFlow.collect { event -> + when (event) { + is AdventureDetailViewModel.Event.NetworkExceptionEvent -> showReRequestSnackbar() + is AdventureDetailViewModel.Event.LetterExceptionEvent -> showReRequestSnackbar() + is AdventureDetailViewModel.Event.GameExceptionEvent -> showReRequestSnackbar() } } } diff --git a/android/app/src/main/java/com/now/naaga/util/extension/LifeCycleOwnerExt.kt b/android/app/src/main/java/com/now/naaga/util/extension/LifeCycleOwnerExt.kt new file mode 100644 index 000000000..985936fce --- /dev/null +++ b/android/app/src/main/java/com/now/naaga/util/extension/LifeCycleOwnerExt.kt @@ -0,0 +1,14 @@ +package com.now.naaga.util.extension + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +fun LifecycleOwner.repeatOnStarted(block: suspend CoroutineScope.() -> Unit) { + lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED, block) + } +} From 3fac1bc0b5237a970c35fa3976fd6425b86fb0f0 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 16:17:13 +0900 Subject: [PATCH 22/24] =?UTF-8?q?feat:=20=EC=95=A1=ED=8B=B0=EB=B9=84?= =?UTF-8?q?=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/AndroidManifest.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index aa08a8a71..798fb8e3a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -70,6 +70,10 @@ android:name=".presentation.setting.SettingActivity" android:screenOrientation="portrait" android:exported="false" /> + <activity + android:name=".presentation.adventuredetail.AdventureDetailActivity" + android:screenOrientation="portrait" + android:exported="false" /> <activity android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity" android:exported="true"> From 6d0c43846b21e186fc6699d1d674fa033d77c7b2 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 16:37:26 +0900 Subject: [PATCH 23/24] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../now/naaga/AdventureDetailViewModelTest.kt | 106 +++++++++++++++--- 1 file changed, 89 insertions(+), 17 deletions(-) diff --git a/android/app/src/test/java/com/now/naaga/AdventureDetailViewModelTest.kt b/android/app/src/test/java/com/now/naaga/AdventureDetailViewModelTest.kt index 4ba7f38c4..5c73f192c 100644 --- a/android/app/src/test/java/com/now/naaga/AdventureDetailViewModelTest.kt +++ b/android/app/src/test/java/com/now/naaga/AdventureDetailViewModelTest.kt @@ -1,41 +1,45 @@ package com.now.naaga -import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import com.now.domain.model.AdventureResult import com.now.domain.model.Coordinate +import com.now.domain.model.Place import com.now.domain.model.Player import com.now.domain.model.letter.OpenLetter +import com.now.domain.model.type.AdventureResultType import com.now.domain.model.type.LogType +import com.now.domain.repository.AdventureRepository import com.now.domain.repository.LetterRepository +import com.now.naaga.presentation.adventuredetail.AdventureDetailUiState import com.now.naaga.presentation.adventuredetail.AdventureDetailViewModel +import com.now.naaga.presentation.uimodel.mapper.toUiModel import io.mockk.coEvery import io.mockk.mockk import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue +import junit.framework.TestCase.assertSame import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.setMain import org.junit.Before -import org.junit.Rule import org.junit.Test +import java.time.LocalDateTime class AdventureDetailViewModelTest { private lateinit var vm: AdventureDetailViewModel private lateinit var letterRepository: LetterRepository - - @get:Rule - val instantExecutorRule = InstantTaskExecutorRule() + private lateinit var adventureRepository: AdventureRepository @OptIn(ExperimentalCoroutinesApi::class) @Before fun setup() { Dispatchers.setMain(UnconfinedTestDispatcher()) letterRepository = mockk() - vm = AdventureDetailViewModel(letterRepository) + adventureRepository = mockk() + vm = AdventureDetailViewModel(letterRepository, adventureRepository) } @Test - fun `읽은 쪽지를 불러올 때 작성한 쪽지는 불러오지 않는다`() { + fun `읽은 쪽지만 불러오면 AdventureDetailUiState는 Loading 상태다`() { // given coEvery { letterRepository.fetchLetterLogs(1L, LogType.READ) @@ -44,16 +48,14 @@ class AdventureDetailViewModelTest { } // when - vm.fetchLetterLogs(1L, LogType.READ) + vm.fetchReadLetter(1L) // then - assertTrue(vm.readLetters.isInitialized) - assertEquals(vm.readLetters.getOrAwaitValue(), fakeReadLetterLogs) - assertEquals(vm.writeLetters.isInitialized, false) + assertSame(vm.uiState.value, AdventureDetailUiState.Loading) } @Test - fun `작성한 쪽지를 불러올 때 읽은 쪽지는 불러오지 않는다`() { + fun `작성한 쪽지만 불러오면 AdventureDetailUiState는 Loading 상태다`() { // given coEvery { letterRepository.fetchLetterLogs(1L, LogType.WRITE) @@ -62,12 +64,68 @@ class AdventureDetailViewModelTest { } // when - vm.fetchLetterLogs(1L, LogType.WRITE) + vm.fetchWriteLetter(1L) // then - assertEquals(vm.readLetters.isInitialized, false) - assertTrue(vm.writeLetters.isInitialized) - assertEquals(vm.writeLetters.getOrAwaitValue(), fakeWriteLetterLogs) + assertSame(vm.uiState.value, AdventureDetailUiState.Loading) + } + + @Test + fun `읽은 쪽지와 작성한 쪽지를 모두 불러와도 AdventureDetailUiState은 Loading 상태다`() { + // given + coEvery { + letterRepository.fetchLetterLogs(1L, LogType.WRITE) + } coAnswers { + fakeWriteLetterLogs + } + + coEvery { + letterRepository.fetchLetterLogs(1L, LogType.READ) + } coAnswers { + fakeReadLetterLogs + } + + // when + vm.fetchWriteLetter(1L) + vm.fetchReadLetter(1L) + + // then + assertSame(vm.uiState.value, AdventureDetailUiState.Loading) + } + + @Test + fun `읽은 쪽지, 작성한 쪽지, 게임 결과를 불러오면 AdventureDetailUiState은 Success 상태다`() { + // given + coEvery { + letterRepository.fetchLetterLogs(1L, LogType.WRITE) + } coAnswers { + fakeWriteLetterLogs + } + + coEvery { + letterRepository.fetchLetterLogs(1L, LogType.READ) + } coAnswers { + fakeReadLetterLogs + } + + coEvery { + adventureRepository.fetchAdventureResult(1L) + } coAnswers { + fakeAdventureResult + } + + // when + vm.fetchWriteLetter(1L) + vm.fetchReadLetter(1L) + vm.fetchAdventureResult(1L) + + // then + val actual = AdventureDetailUiState.Success( + readLetters = fakeReadLetterLogs.map { it.toUiModel() }, + writeLetters = fakeWriteLetterLogs.map { it.toUiModel() }, + adventureResult = fakeAdventureResult, + ) + assertEquals(vm.uiState.value, actual) } private val fakeReadLetterLogs = listOf( @@ -89,4 +147,18 @@ class AdventureDetailViewModelTest { registerDate = "now", ), ) + + private val fakeAdventureResult = AdventureResult( + id = 1L, + gameId = 2L, + destination = Place(1L, "집", Coordinate(123.0, 37.0), "", ""), + resultType = AdventureResultType.FAIL, + score = 123, + playTime = 123, + distance = 123, + hintUses = 123, + tryCount = 1, + beginTime = LocalDateTime.now(), + endTime = LocalDateTime.now(), + ) } From 5d6abee4b00674424329264b35ae5da07dba60e6 Mon Sep 17 00:00:00 2001 From: krrong <khk9664@naver.com> Date: Tue, 17 Oct 2023 22:22:55 +0900 Subject: [PATCH 24/24] =?UTF-8?q?refactor:=20=EB=94=94=ED=8F=B4=ED=8A=B8?= =?UTF-8?q?=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/adventuredetail/AdventureDetailViewModel.kt | 2 +- .../naaga/presentation/uimodel/model/OpenLetterUiModel.kt | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt index 84efa37c2..74cff1dd1 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/adventuredetail/AdventureDetailViewModel.kt @@ -53,7 +53,7 @@ class AdventureDetailViewModel @Inject constructor( } private fun getOpenLetterUiModels(letters: List<OpenLetter>): List<OpenLetterUiModel> { - if (letters.isEmpty()) return listOf(OpenLetterUiModel.getDefault()) + if (letters.isEmpty()) return listOf(OpenLetterUiModel.DEFAULT_OPEN_LETTER) return letters.map { it.toUiModel() } } diff --git a/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt b/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt index e8df08386..65b21dc63 100644 --- a/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt +++ b/android/app/src/main/java/com/now/naaga/presentation/uimodel/model/OpenLetterUiModel.kt @@ -7,9 +7,6 @@ data class OpenLetterUiModel( ) { companion object { private const val DEFAULT_MESSAGE = "쪽지가 없습니다." - - fun getDefault(): OpenLetterUiModel { - return OpenLetterUiModel("", "", DEFAULT_MESSAGE) - } + val DEFAULT_OPEN_LETTER = OpenLetterUiModel("", "", DEFAULT_MESSAGE) } }