Skip to content

Commit

Permalink
shared use new gamification toolbar api
Browse files Browse the repository at this point in the history
  • Loading branch information
vladkash committed Oct 18, 2023
1 parent ba26e49 commit db91b74
Show file tree
Hide file tree
Showing 14 changed files with 173 additions and 173 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,12 @@ class GamificationToolbarDelegate(
if (state is GamificationToolbarFeature.State.Content) {
with(viewBinding.gamificationStreakDurationTextView) {
isVisible = true
val streakDuration = state.streak?.currentStreak ?: 0
val streakDuration = state.currentStreak
text = streakDuration.toString()
val historicalStreak = state.streak?.history?.firstOrNull()
setCompoundDrawablesWithIntrinsicBounds(
/* left = */ when {
historicalStreak?.state == StreakState.RECOVERED -> R.drawable.ic_menu_recovered_streak
historicalStreak?.isCompleted == true -> R.drawable.ic_menu_enabled_streak
state.historicalStreak.state == StreakState.RECOVERED -> R.drawable.ic_menu_recovered_streak
state.historicalStreak.isCompleted -> R.drawable.ic_menu_enabled_streak
else -> R.drawable.ic_menu_empty_streak
},
/* top = */ 0,
Expand All @@ -70,12 +69,12 @@ class GamificationToolbarDelegate(
text = state.hypercoinsBalance.toString()
}

state.trackWithProgress.let { trackProgress ->
state.trackProgress.let { trackProgress ->
viewBinding.gamificationTrackProgressLinearLayout.isVisible = trackProgress != null
if (trackProgress != null) {
viewBinding.gamificationTrackProgressView.setProgress(
trackProgress.averageProgress,
trackProgress.trackProgress.isCompleted
trackProgress.isCompleted
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,19 @@ struct GamificationToolbarContent: ToolbarContent {
HStack {}
case .content(let data):
HStack {
if let trackWithProgress = data.trackWithProgress {
if let trackProgress = data.trackProgress {
ProgressBarButtonItem(
progress: Float(trackWithProgress.averageProgress) / 100,
isCompleted: trackWithProgress.trackProgress.isCompleted,
progress: Float(trackProgress.averageProgress) / 100,
isCompleted: trackProgress.isCompleted,
onTap: onProgressTap
)
}

if let streak = data.streak {
StreakBarButtonItem(
currentStreak: Int(streak.currentStreak),
isCompletedToday: streak.history.first?.isCompleted == true,
onTap: onStreakTap
)
}
StreakBarButtonItem(
currentStreak: Int(data.currentStreak),
isCompletedToday: data.historicalStreak.isCompleted,
onTap: onStreakTap
)

GemsBarButtonItem(
hypercoinsBalance: Int(data.hypercoinsBalance),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.hyperskill.app.gamification_toolbar.data.repository

import org.hyperskill.app.gamification_toolbar.data.source.GamificationToolbarRemoteDataSource
import org.hyperskill.app.gamification_toolbar.domain.model.GamificationToolbarData
import org.hyperskill.app.gamification_toolbar.domain.repository.GamificationToolbarRepository

class GamificationToolbarRepositoryImpl(
private val gamificationToolbarRemoteDataSource: GamificationToolbarRemoteDataSource
) : GamificationToolbarRepository {
override suspend fun getGamificationToolbarData(): Result<GamificationToolbarData> =
gamificationToolbarRemoteDataSource.getGamificationToolbarData()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.hyperskill.app.gamification_toolbar.data.source

import org.hyperskill.app.gamification_toolbar.domain.model.GamificationToolbarData

interface GamificationToolbarRemoteDataSource {
suspend fun getGamificationToolbarData(): Result<GamificationToolbarData>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.hyperskill.app.gamification_toolbar.domain.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.hyperskill.app.streaks.domain.model.StreakState

@Serializable
data class GamificationToolbarData(
@SerialName("track_progress")
val trackProgress: GamificationToolbarTrackProgress?,
@SerialName("current_streak")
val currentStreak: Int,
@SerialName("streak_state")
val streakState: StreakState,
@SerialName("hypercoins_balance")
val hypercoinsBalance: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.hyperskill.app.gamification_toolbar.domain.model

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class GamificationToolbarTrackProgress(
@SerialName("is_completed")
val isCompleted: Boolean,
@SerialName("average_progress")
val averageProgress: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.hyperskill.app.gamification_toolbar.domain.repository

import org.hyperskill.app.gamification_toolbar.domain.model.GamificationToolbarData

interface GamificationToolbarRepository {
suspend fun getGamificationToolbarData(): Result<GamificationToolbarData>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package org.hyperskill.app.gamification_toolbar.injection

import org.hyperskill.app.core.injection.AppGraph
import org.hyperskill.app.core.presentation.ActionDispatcherOptions
import org.hyperskill.app.gamification_toolbar.data.repository.GamificationToolbarRepositoryImpl
import org.hyperskill.app.gamification_toolbar.data.source.GamificationToolbarRemoteDataSource
import org.hyperskill.app.gamification_toolbar.domain.model.GamificationToolbarScreen
import org.hyperskill.app.gamification_toolbar.domain.repository.GamificationToolbarRepository
import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarActionDispatcher
import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarReducer
import org.hyperskill.app.gamification_toolbar.remote.GamificationToolbarRemoteDataSourceImpl

class GamificationToolbarComponentImpl(
private val appGraph: AppGraph,
Expand All @@ -13,21 +17,25 @@ class GamificationToolbarComponentImpl(
override val gamificationToolbarReducer: GamificationToolbarReducer
get() = GamificationToolbarReducer(screen)

private val gamificationToolbarRemoteDataSource: GamificationToolbarRemoteDataSource =
GamificationToolbarRemoteDataSourceImpl(appGraph.networkComponent.authorizedHttpClient)

private val gamificationToolbarRepository: GamificationToolbarRepository
get() = GamificationToolbarRepositoryImpl(gamificationToolbarRemoteDataSource)

override val gamificationToolbarActionDispatcher: GamificationToolbarActionDispatcher
get() {
val profileComponent = appGraph.profileDataComponent
return GamificationToolbarActionDispatcher(
ActionDispatcherOptions(),
profileComponent.profileInteractor,
profileComponent.currentProfileStateRepository,
appGraph.buildStreaksDataComponent().streaksInteractor,
appGraph.analyticComponent.analyticInteractor,
appGraph.sentryComponent.sentryInteractor,
appGraph.submissionDataComponent.submissionRepository,
appGraph.streakFlowDataComponent.streakFlow,
profileComponent.currentProfileStateRepository,
appGraph.stateRepositoriesComponent.currentStudyPlanStateRepository,
appGraph.buildTrackDataComponent().trackRepository,
appGraph.buildProgressesDataComponent().progressesRepository,
appGraph.stepCompletionFlowDataComponent.topicCompletedFlow
appGraph.stepCompletionFlowDataComponent.topicCompletedFlow,
gamificationToolbarRepository,
appGraph.analyticComponent.analyticInteractor,
appGraph.sentryComponent.sentryInteractor
)
}
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,36 @@
package org.hyperskill.app.gamification_toolbar.presentation

import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.hyperskill.app.analytic.domain.interactor.AnalyticInteractor
import org.hyperskill.app.core.presentation.ActionDispatcherOptions
import org.hyperskill.app.gamification_toolbar.domain.repository.GamificationToolbarRepository
import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarFeature.Action
import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarFeature.Message
import org.hyperskill.app.profile.domain.interactor.ProfileInteractor
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
import org.hyperskill.app.profile.domain.repository.observeHypercoinsBalance
import org.hyperskill.app.progresses.domain.repository.ProgressesRepository
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
import org.hyperskill.app.step_completion.domain.flow.TopicCompletedFlow
import org.hyperskill.app.step_quiz.domain.repository.SubmissionRepository
import org.hyperskill.app.streaks.domain.flow.StreakFlow
import org.hyperskill.app.streaks.domain.interactor.StreaksInteractor
import org.hyperskill.app.study_plan.domain.repository.CurrentStudyPlanStateRepository
import org.hyperskill.app.track.domain.model.TrackWithProgress
import org.hyperskill.app.track.domain.repository.TrackRepository
import ru.nobird.app.presentation.redux.dispatcher.CoroutineActionDispatcher

class GamificationToolbarActionDispatcher(
config: ActionDispatcherOptions,
profileInteractor: ProfileInteractor,
private val currentProfileStateRepository: CurrentProfileStateRepository,
private val streaksInteractor: StreaksInteractor,
submissionRepository: SubmissionRepository,
streakFlow: StreakFlow,
currentProfileStateRepository: CurrentProfileStateRepository,
currentStudyPlanStateRepository: CurrentStudyPlanStateRepository,
topicCompletedFlow: TopicCompletedFlow,
private val gamificationToolbarRepository: GamificationToolbarRepository,
private val analyticInteractor: AnalyticInteractor,
private val sentryInteractor: SentryInteractor,
private val streakFlow: StreakFlow,
private val currentStudyPlanStateRepository: CurrentStudyPlanStateRepository,
private val trackRepository: TrackRepository,
private val progressesRepository: ProgressesRepository,
topicCompletedFlow: TopicCompletedFlow
private val sentryInteractor: SentryInteractor
) : CoroutineActionDispatcher<Action, Message>(config.createConfig()) {

init {
profileInteractor.solvedStepsSharedFlow
submissionRepository.solvedStepsSharedFlow
.onEach { onNewMessage(Message.StepSolved) }
.launchIn(actionScope)

Expand Down Expand Up @@ -71,107 +64,28 @@ class GamificationToolbarActionDispatcher(

override suspend fun doSuspendableAction(action: Action) {
when (action) {
is Action.FetchGamificationToolbarData -> coroutineScope {
is Action.FetchGamificationToolbarData -> {
val sentryTransaction = action.screen.fetchContentSentryTransaction
sentryInteractor.startTransaction(sentryTransaction)

val currentUserId = currentProfileStateRepository
.getState()
.map { it.id }
val gamificationToolbarData = gamificationToolbarRepository
.getGamificationToolbarData()
.getOrElse {
sentryInteractor.finishTransaction(sentryTransaction, throwable = it)
onNewMessage(Message.FetchGamificationToolbarDataError)
return@coroutineScope
return onNewMessage(Message.FetchGamificationToolbarDataError)
}

val streakResult = async { streaksInteractor.getUserStreak(currentUserId) }
val profileResult = async {
currentProfileStateRepository.getState(forceUpdate = true)
}
val trackWithProgressDeferred = async {
fetchTrackWithProgressThroughStudyPlan(action.forceUpdate)
}

val streak = streakResult.await().getOrElse {
sentryInteractor.finishTransaction(sentryTransaction, throwable = it)
onNewMessage(Message.FetchGamificationToolbarDataError)
return@coroutineScope
}
val profile = profileResult.await().getOrElse {
sentryInteractor.finishTransaction(sentryTransaction, throwable = it)
onNewMessage(Message.FetchGamificationToolbarDataError)
return@coroutineScope
}
val trackWithProgress = trackWithProgressDeferred.await().getOrElse {
sentryInteractor.finishTransaction(sentryTransaction, throwable = it)
onNewMessage(Message.FetchGamificationToolbarDataError)
return@coroutineScope
}

sentryInteractor.finishTransaction(sentryTransaction)

streakFlow.notifyDataChanged(streak)

onNewMessage(
Message.FetchGamificationToolbarDataSuccess(
streak,
profile.gamification.hypercoinsBalance,
trackWithProgress
)
Message.FetchGamificationToolbarDataSuccess(gamificationToolbarData)
)
}
is Action.FetchTrackWithProgress -> {
sentryInteractor.startTransaction(action.transaction)
fetchTrackWithProgress(action.trackId, true)
.fold(
onSuccess = { trackWithProgress ->
onNewMessage(Message.FetchTrackWithProgressResult.Success(trackWithProgress))
sentryInteractor.finishTransaction(action.transaction)
},
onFailure = {
onNewMessage(Message.FetchTrackWithProgressResult.Error)
sentryInteractor.finishTransaction(action.transaction, throwable = it)
}
)
}
is Action.LogAnalyticEvent ->
analyticInteractor.logEvent(action.analyticEvent)
else -> {
// no op
}
}
}

private suspend fun fetchTrackWithProgressThroughStudyPlan(
forceLoadFromRemote: Boolean
): Result<TrackWithProgress?> =
kotlin.runCatching {
val studyPlan =
currentStudyPlanStateRepository.getState(forceLoadFromRemote).getOrThrow()
if (studyPlan.trackId != null) {
fetchTrackWithProgress(studyPlan.trackId, forceLoadFromRemote).getOrThrow()
} else {
null
}
}

private suspend fun fetchTrackWithProgress(
trackId: Long,
forceLoadFromRemote: Boolean
): Result<TrackWithProgress?> =
coroutineScope {
kotlin.runCatching {
val trackDeferred = async {
trackRepository.getTrack(trackId, forceLoadFromRemote)
}
val trackProgressDeferred = async {
progressesRepository
.getTrackProgress(trackId, forceLoadFromRemote)
}
TrackWithProgress(
track = trackDeferred.await().getOrThrow(),
trackProgress = trackProgressDeferred.await().getOrThrow() ?: return@runCatching null
)
}
}
}
Loading

0 comments on commit db91b74

Please sign in to comment.