feat(creator): 커뮤니티 상태에 UI 모델을 적용한다

This commit is contained in:
2026-06-21 22:32:33 +09:00
parent f9501c156a
commit 88fcbe49f4
4 changed files with 25 additions and 15 deletions

View File

@@ -68,6 +68,8 @@ import kr.co.vividnext.sodalive.chat.talk.TalkTabRepository
import kr.co.vividnext.sodalive.chat.talk.TalkTabViewModel import kr.co.vividnext.sodalive.chat.talk.TalkTabViewModel
import kr.co.vividnext.sodalive.chat.talk.room.chatTalkRoomModule import kr.co.vividnext.sodalive.chat.talk.room.chatTalkRoomModule
import kr.co.vividnext.sodalive.common.ApiBuilder import kr.co.vividnext.sodalive.common.ApiBuilder
import kr.co.vividnext.sodalive.common.AndroidUtcRelativeTimeTextFormatter
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
import kr.co.vividnext.sodalive.explorer.ExplorerApi import kr.co.vividnext.sodalive.explorer.ExplorerApi
import kr.co.vividnext.sodalive.explorer.ExplorerRepository import kr.co.vividnext.sodalive.explorer.ExplorerRepository
import kr.co.vividnext.sodalive.explorer.ExplorerViewModel import kr.co.vividnext.sodalive.explorer.ExplorerViewModel
@@ -215,6 +217,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
private val otherModule = module { private val otherModule = module {
single { GsonBuilder().create() } single { GsonBuilder().create() }
single<UtcRelativeTimeTextFormatter> { AndroidUtcRelativeTimeTextFormatter(get()) }
single { PlaybackTrackingDatabase.getDatabase(get()) } single { PlaybackTrackingDatabase.getDatabase(get()) }
single<PlaybackTrackingDao> { get<PlaybackTrackingDatabase>().playbackTrackingDao() } single<PlaybackTrackingDao> { get<PlaybackTrackingDatabase>().playbackTrackingDao() }
} }
@@ -415,7 +418,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { CreatorChannelLiveViewModel(get()) } viewModel { CreatorChannelLiveViewModel(get()) }
viewModel { CreatorChannelAudioViewModel(get()) } viewModel { CreatorChannelAudioViewModel(get()) }
viewModel { CreatorChannelSeriesViewModel(get()) } viewModel { CreatorChannelSeriesViewModel(get()) }
viewModel { CreatorChannelCommunityViewModel(get()) } viewModel { CreatorChannelCommunityViewModel(get(), get()) }
viewModel { PushNotificationListViewModel(get()) } viewModel { PushNotificationListViewModel(get()) }
viewModel { CharacterTabViewModel(get()) } viewModel { CharacterTabViewModel(get()) }
viewModel { CharacterDetailViewModel(get()) } viewModel { CharacterDetailViewModel(get()) }

View File

@@ -8,12 +8,15 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityPostResponse import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityTabResponse import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityTabResponse
import kr.co.vividnext.sodalive.v2.creator.channel.community.model.CreatorChannelCommunityPostUiModel
import kr.co.vividnext.sodalive.v2.creator.channel.community.model.toCommunityPostUiModels
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
class CreatorChannelCommunityViewModel( class CreatorChannelCommunityViewModel(
private val repository: CreatorChannelRepository private val repository: CreatorChannelRepository,
private val relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
) : BaseViewModel() { ) : BaseViewModel() {
private val _communityStateLiveData = MutableLiveData<CreatorChannelCommunityUiState>() private val _communityStateLiveData = MutableLiveData<CreatorChannelCommunityUiState>()
@@ -61,7 +64,7 @@ class CreatorChannelCommunityViewModel(
val current = _communityStateLiveData.value as? CreatorChannelCommunityUiState.Content ?: content val current = _communityStateLiveData.value as? CreatorChannelCommunityUiState.Content ?: content
if (response.success && data != null) { if (response.success && data != null) {
_communityStateLiveData.value = current.copy( _communityStateLiveData.value = current.copy(
communityPosts = current.communityPosts + data.communityPosts, communityPosts = current.communityPosts + data.toCommunityPostUiModels(),
page = data.page, page = data.page,
size = data.size, size = data.size,
hasNext = data.hasNext, hasNext = data.hasNext,
@@ -89,7 +92,7 @@ class CreatorChannelCommunityViewModel(
requestCommunity(page = FIRST_PAGE, generation = generation) { response -> requestCommunity(page = FIRST_PAGE, generation = generation) { response ->
val data = response.data val data = response.data
if (response.success && data != null) { if (response.success && data != null) {
val communityPosts = data.communityPosts val communityPosts = data.toCommunityPostUiModels()
_communityStateLiveData.value = if (communityPosts.isEmpty() || data.communityPostCount == 0) { _communityStateLiveData.value = if (communityPosts.isEmpty() || data.communityPostCount == 0) {
CreatorChannelCommunityUiState.Empty CreatorChannelCommunityUiState.Empty
} else { } else {
@@ -137,7 +140,7 @@ class CreatorChannelCommunityViewModel(
} }
private fun CreatorChannelCommunityTabResponse.toContentState( private fun CreatorChannelCommunityTabResponse.toContentState(
communityPosts: List<CreatorChannelCommunityPostResponse> communityPosts: List<CreatorChannelCommunityPostUiModel>
) = CreatorChannelCommunityUiState.Content( ) = CreatorChannelCommunityUiState.Content(
communityPostCount = communityPostCount, communityPostCount = communityPostCount,
communityPosts = communityPosts, communityPosts = communityPosts,
@@ -149,24 +152,26 @@ class CreatorChannelCommunityViewModel(
private fun authToken(): String = "Bearer ${SharedPreferenceManager.token}" private fun authToken(): String = "Bearer ${SharedPreferenceManager.token}"
private fun CreatorChannelCommunityTabResponse.toCommunityPostUiModels(): List<CreatorChannelCommunityPostUiModel> =
communityPosts.toCommunityPostUiModels(
relativeTimeTextFormatter = relativeTimeTextFormatter,
isOwner = isOwner,
currentUserId = SharedPreferenceManager.userId
)
companion object { companion object {
val DEFAULT_PAGE_SIZE = 20 const val DEFAULT_PAGE_SIZE = 20
private const val FIRST_PAGE = 0 private const val FIRST_PAGE = 0
} }
} }
enum class CreatorChannelCommunityViewMode {
List,
Grid
}
sealed interface CreatorChannelCommunityUiState { sealed interface CreatorChannelCommunityUiState {
data object Loading : CreatorChannelCommunityUiState data object Loading : CreatorChannelCommunityUiState
data object Empty : CreatorChannelCommunityUiState data object Empty : CreatorChannelCommunityUiState
data class Error(val message: String?) : CreatorChannelCommunityUiState data class Error(val message: String?) : CreatorChannelCommunityUiState
data class Content( data class Content(
val communityPostCount: Int, val communityPostCount: Int,
val communityPosts: List<CreatorChannelCommunityPostResponse>, val communityPosts: List<CreatorChannelCommunityPostUiModel>,
val viewMode: CreatorChannelCommunityViewMode, val viewMode: CreatorChannelCommunityViewMode,
val page: Int, val page: Int,
val size: Int, val size: Int,

View File

@@ -12,6 +12,7 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import io.reactivex.rxjava3.subjects.SingleSubject import io.reactivex.rxjava3.subjects.SingleSubject
import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.AndroidUtcRelativeTimeTextFormatter
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityPostResponse import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityPostResponse
import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityTabResponse import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityTabResponse
@@ -44,7 +45,7 @@ class CreatorChannelCommunityPaginationTest {
SharedPreferenceManager.init(context) SharedPreferenceManager.init(context)
SharedPreferenceManager.token = "test-token" SharedPreferenceManager.token = "test-token"
repository = org.mockito.kotlin.mock() repository = org.mockito.kotlin.mock()
viewModel = CreatorChannelCommunityViewModel(repository) viewModel = CreatorChannelCommunityViewModel(repository, AndroidUtcRelativeTimeTextFormatter(context))
} }
@After @After

View File

@@ -11,6 +11,7 @@ import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.plugins.RxJavaPlugins import io.reactivex.rxjava3.plugins.RxJavaPlugins
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.AndroidUtcRelativeTimeTextFormatter
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityPostResponse import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityPostResponse
import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityTabResponse import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityTabResponse
@@ -44,7 +45,7 @@ class CreatorChannelCommunityViewModelTest {
SharedPreferenceManager.init(context) SharedPreferenceManager.init(context)
SharedPreferenceManager.token = "test-token" SharedPreferenceManager.token = "test-token"
repository = org.mockito.kotlin.mock() repository = org.mockito.kotlin.mock()
viewModel = CreatorChannelCommunityViewModel(repository) viewModel = CreatorChannelCommunityViewModel(repository, AndroidUtcRelativeTimeTextFormatter(context))
} }
@After @After