Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

테마 업데이트 시점 변경 #96

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ class HintRepositoryImpl @Inject constructor(
return hintLocalDataSource.getHint(themeId, hintCode)?.toDomain()
}

override suspend fun saveHints(themeId: Int): Result<Long> {
//TODO : 리팩토링 필요. hint를 저장하는데, 최신의 updatedTime이 나올거라고 예상할수가 없고 그래서도 안됨
override suspend fun saveHints(themeId: Int): Result<Pair<Int, Long>> {
val updatedTime = System.currentTimeMillis()
return hintRemoteDataSource.getHints(themeId)
.suspendOnSuccess {
themeLocalDataSource.updateUpdatedInfo(themeId, updatedTime)
hintLocalDataSource.saveHints(themeId, it)
}.mapOnSuccess { updatedTime }
}.mapOnSuccess { Pair(themeId, updatedTime) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import com.nextroom.nextroom.domain.model.Result

interface HintRepository {
suspend fun getHint(hintCode: String): Hint?
suspend fun saveHints(themeId: Int): Result<Long>
suspend fun saveHints(themeId: Int): Result<Pair<Int, Long>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ class AdminMainFragment :

private val viewModel: AdminMainViewModel by viewModels()
private val adapter: ThemesAdapter by lazy {
ThemesAdapter(
onStartGame = ::startGame,
onClickUpdate = viewModel::updateTheme,
)
ThemesAdapter(onStartGame = ::startGame)
}
private val state: AdminMainState
get() = viewModel.container.stateFlow.value
Expand Down Expand Up @@ -88,7 +85,7 @@ class AdminMainFragment :
}

srlTheme.setOnRefreshListener {
viewModel.loadData()
viewModel.fetchData()
}

llBanner.setOnClickListener {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.nextroom.nextroom.presentation.ui.adminmain

import androidx.lifecycle.viewModelScope
import com.nextroom.nextroom.domain.model.Mypage
import com.nextroom.nextroom.domain.model.Result
import com.nextroom.nextroom.domain.model.onFailure
import com.nextroom.nextroom.domain.model.onSuccess
import com.nextroom.nextroom.domain.model.suspendOnSuccess
import com.nextroom.nextroom.domain.repository.AdminRepository
import com.nextroom.nextroom.domain.repository.BannerRepository
import com.nextroom.nextroom.domain.repository.DataStoreRepository
Expand All @@ -15,7 +15,11 @@ import com.nextroom.nextroom.presentation.model.ThemeInfoPresentation
import com.nextroom.nextroom.presentation.model.toPresentation
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.supervisorScope
import kotlinx.coroutines.withContext
import org.orbitmvi.orbit.Container
import org.orbitmvi.orbit.syntax.simple.intent
Expand All @@ -36,7 +40,7 @@ class AdminMainViewModel @Inject constructor(
override val container: Container<AdminMainState, AdminMainEvent> = container(AdminMainState(loading = true))

init {
loadData()
fetchData()
fetchBanners()

viewModelScope.launch {
Expand All @@ -57,59 +61,76 @@ class AdminMainViewModel @Inject constructor(
}
}

fun updateTheme(themeId: Int) = intent {
themeRepository
.getThemes()
.onSuccess { themes ->
themes
.find { it.id == themeId }
?.let { themeRepository.upsertTheme(it) }
}.onFailure {
handleError(it)
return@intent
}

hintRepository.saveHints(themeId).onSuccess { updatedAt ->
reduce {
state.copy(
themes = state.themes.toMutableList()
.map { if (it.id == themeId) it.copy(recentUpdated = updatedAt) else it },
)
}
}.onFailure(::handleError)
}

fun start(themeId: Int, readyToStart: () -> Unit) = intent {
themeRepository.updateLatestTheme(themeId)
withContext(Dispatchers.Main) {
readyToStart()
}
}

fun loadData() = intent {
fun fetchData() = intent {
reduce { state.copy(loading = true) }
adminRepository.getUserSubscribe().suspendOnSuccess {
reduce { state.copy(subscribeStatus = it.status) }
themeRepository.getThemes().onSuccess {
updateThemes(
it.map { themeInfo ->
val updatedAt = themeRepository.getUpdatedInfo(themeInfo.id)
themeInfo.toPresentation(updatedAt)
},
)

viewModelScope.launch {
supervisorScope {
try {
val userSubscribeDeferred = async(Dispatchers.IO) { fetchUserSubscribe() }
val themesDeferred = async(Dispatchers.IO) { getThemes() }

userSubscribeDeferred.await()
.getOrNull
?.let {
updateSubscribeStatus(it)
}

val themes = themesDeferred.await()
val updateAtHashMap = mutableMapOf<Int, Long>()
saveHints(themes)
.associate { it.getOrThrow }
.also { updateAtHashMap.putAll(it) }
if (state.themes.isEmpty()) {
updateThemes(themes)
} else {
updateThemes(
state.themes
.toMutableList()
.map { if (it.id in updateAtHashMap) it.copy(recentUpdated = updateAtHashMap.getValue(it.id)) else it }
)
}
} catch (ex: Exception) {
//TODO : 리팩토링 필요. ex로 부터 어떤 에러인지 추출할수가 없음. 중간에 에러 정보를 잃음.
handleError(Result.Failure.OperationError(ex))
}
}
}
themeRepository.getThemes().onSuccess {
updateThemes(
it.map { themeInfo ->
val updatedAt = themeRepository.getUpdatedInfo(themeInfo.id)
themeInfo.toPresentation(updatedAt)
},
)
}.onFailure(::handleError)

reduce { state.copy(loading = false) }
}

private fun updateSubscribeStatus(myPage: Mypage) = intent {
reduce { state.copy(subscribeStatus = myPage.status) }
}

private suspend fun fetchUserSubscribe() = adminRepository.getUserSubscribe()

private suspend fun getThemes(): List<ThemeInfoPresentation> {
return themeRepository.getThemes()
.getOrThrow
.map { themeInfo ->
themeRepository
.getUpdatedInfo(themeInfo.id)
.let { updatedAt ->
themeInfo.toPresentation(updatedAt)
}
}
}

private suspend fun saveHints(themes: List<ThemeInfoPresentation>) = coroutineScope {
return@coroutineScope themes
.map { theme -> async(Dispatchers.IO) { hintRepository.saveHints(theme.id) } }
.awaitAll()
}

private fun updateShopInfo(shopName: String) = intent {
reduce { state.copy(shopName = shopName) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,19 @@ import com.nextroom.nextroom.presentation.databinding.ItemThemeBinding
import com.nextroom.nextroom.presentation.model.ThemeInfoPresentation

class ThemesAdapter(
private val onStartGame: (Int) -> Unit,
private val onClickUpdate: (Int) -> Unit,
private val onStartGame: (Int) -> Unit
) : ListAdapter<ThemeInfoPresentation, ThemesAdapter.ThemeViewHolder>(diffUtil) {

class ThemeViewHolder(
private val binding: ItemThemeBinding,
onStartGame: (Int) -> Unit,
onClickUpdate: (Int) -> Unit,
onStartGame: (Int) -> Unit
) : RecyclerView.ViewHolder(binding.root) {

private lateinit var item: ThemeInfoPresentation
private val context = binding.root.context

init {
binding.root.setOnClickListener { onStartGame(item.id) }
binding.btnUpdate.setOnClickListener { onClickUpdate(item.id) }
}

fun bind(themeInfo: ThemeInfoPresentation) = with(binding) {
Expand All @@ -44,8 +41,7 @@ class ThemesAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ThemeViewHolder {
return ThemeViewHolder(
ItemThemeBinding.inflate(LayoutInflater.from(parent.context), parent, false),
onStartGame,
onClickUpdate,
onStartGame
)
}

Expand Down
22 changes: 0 additions & 22 deletions presentation/src/main/res/layout/item_theme.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,28 +35,6 @@
app:layout_constraintTop_toBottomOf="@id/tv_theme_name"
tools:text="최근 업데이트 : 2023.01.02" />

<View
android:id="@+id/btn_update"
android:layout_width="48dp"
android:layout_height="34dp"
android:padding="10dp"
app:layout_constraintBottom_toBottomOf="@id/tv_recent_update"
app:layout_constraintStart_toEndOf="@id/tv_recent_update"
app:layout_constraintTop_toTopOf="@id/tv_recent_update" />

<ImageView
android:id="@+id/iv_update"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="12dp"
android:background="@drawable/bg_update_button"
android:contentDescription="@string/update_button_description"
android:padding="2.5dp"
android:src="@drawable/ic_update24"
app:layout_constraintBottom_toBottomOf="@id/btn_update"
app:layout_constraintStart_toStartOf="@id/btn_update"
app:layout_constraintTop_toTopOf="@id/btn_update" />

<View
android:layout_width="0dp"
android:layout_height="1dp"
Expand Down