diff --git a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/gamification_toolbar/view/ui/delegate/GamificationToolbarDelegate.kt b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/gamification_toolbar/view/ui/delegate/GamificationToolbarDelegate.kt index 1ecbbe2346..21f741cc2a 100644 --- a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/gamification_toolbar/view/ui/delegate/GamificationToolbarDelegate.kt +++ b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/gamification_toolbar/view/ui/delegate/GamificationToolbarDelegate.kt @@ -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, @@ -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 ) } } diff --git a/iosHyperskillApp/iosHyperskillApp/Sources/Modules/GamificationToolbar/Views/GamificationToolbarContent.swift b/iosHyperskillApp/iosHyperskillApp/Sources/Modules/GamificationToolbar/Views/GamificationToolbarContent.swift index 5d57fdc472..36556dc407 100644 --- a/iosHyperskillApp/iosHyperskillApp/Sources/Modules/GamificationToolbar/Views/GamificationToolbarContent.swift +++ b/iosHyperskillApp/iosHyperskillApp/Sources/Modules/GamificationToolbar/Views/GamificationToolbarContent.swift @@ -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), diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/data/repository/GamificationToolbarRepositoryImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/data/repository/GamificationToolbarRepositoryImpl.kt new file mode 100644 index 0000000000..1691374a07 --- /dev/null +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/data/repository/GamificationToolbarRepositoryImpl.kt @@ -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 = + gamificationToolbarRemoteDataSource.getGamificationToolbarData() +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/data/source/GamificationToolbarRemoteDataSource.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/data/source/GamificationToolbarRemoteDataSource.kt new file mode 100644 index 0000000000..e8226bf0ab --- /dev/null +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/data/source/GamificationToolbarRemoteDataSource.kt @@ -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 +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/domain/model/GamificationToolbarData.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/domain/model/GamificationToolbarData.kt new file mode 100644 index 0000000000..d90ad0b531 --- /dev/null +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/domain/model/GamificationToolbarData.kt @@ -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 +) \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/domain/model/GamificationToolbarTrackProgress.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/domain/model/GamificationToolbarTrackProgress.kt new file mode 100644 index 0000000000..f408c51e8f --- /dev/null +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/domain/model/GamificationToolbarTrackProgress.kt @@ -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 +) \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/domain/repository/GamificationToolbarRepository.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/domain/repository/GamificationToolbarRepository.kt new file mode 100644 index 0000000000..90cc8b051e --- /dev/null +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/domain/repository/GamificationToolbarRepository.kt @@ -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 +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/injection/GamificationToolbarComponentImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/injection/GamificationToolbarComponentImpl.kt index f9e1ea385c..a33b1393e2 100644 --- a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/injection/GamificationToolbarComponentImpl.kt +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/injection/GamificationToolbarComponentImpl.kt @@ -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, @@ -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 ) } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarActionDispatcher.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarActionDispatcher.kt index 351d9977d9..d675708e9d 100644 --- a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarActionDispatcher.kt +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarActionDispatcher.kt @@ -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(config.createConfig()) { init { - profileInteractor.solvedStepsSharedFlow + submissionRepository.solvedStepsSharedFlow .onEach { onNewMessage(Message.StepSolved) } .launchIn(actionScope) @@ -71,69 +64,23 @@ 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 -> { @@ -141,37 +88,4 @@ class GamificationToolbarActionDispatcher( } } } - - private suspend fun fetchTrackWithProgressThroughStudyPlan( - forceLoadFromRemote: Boolean - ): Result = - 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 = - 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 - ) - } - } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarFeature.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarFeature.kt index ab05eda4b7..38a1a2315d 100644 --- a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarFeature.kt +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarFeature.kt @@ -1,11 +1,12 @@ package org.hyperskill.app.gamification_toolbar.presentation import org.hyperskill.app.analytic.domain.model.AnalyticEvent +import org.hyperskill.app.gamification_toolbar.domain.model.GamificationToolbarData import org.hyperskill.app.gamification_toolbar.domain.model.GamificationToolbarScreen -import org.hyperskill.app.sentry.domain.model.transaction.HyperskillSentryTransaction +import org.hyperskill.app.gamification_toolbar.domain.model.GamificationToolbarTrackProgress +import org.hyperskill.app.streaks.domain.model.HistoricalStreak import org.hyperskill.app.streaks.domain.model.Streak import org.hyperskill.app.study_plan.domain.model.StudyPlan -import org.hyperskill.app.track.domain.model.TrackWithProgress object GamificationToolbarFeature { sealed interface State { @@ -13,9 +14,10 @@ object GamificationToolbarFeature { object Loading : State object Error : State data class Content( - val streak: Streak?, + val trackProgress: GamificationToolbarTrackProgress?, + val currentStreak: Int, + val historicalStreak: HistoricalStreak, val hypercoinsBalance: Int, - val trackWithProgress: TrackWithProgress?, internal val isRefreshing: Boolean = false ) : State } @@ -31,16 +33,9 @@ object GamificationToolbarFeature { object FetchGamificationToolbarDataError : Message data class FetchGamificationToolbarDataSuccess( - val streak: Streak?, - val hypercoinsBalance: Int, - val trackWithProgress: TrackWithProgress? + val gamificationToolbarData: GamificationToolbarData ) : Message - sealed interface FetchTrackWithProgressResult : Message { - data class Success(val trackWithProgress: TrackWithProgress?) : FetchTrackWithProgressResult - object Error : FetchTrackWithProgressResult - } - object PullToRefresh : Message /** @@ -66,11 +61,6 @@ object GamificationToolbarFeature { val forceUpdate: Boolean ) : Action - data class FetchTrackWithProgress( - val trackId: Long, - val transaction: HyperskillSentryTransaction - ) : Action - data class LogAnalyticEvent(val analyticEvent: AnalyticEvent) : Action sealed interface ViewAction : Action { diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarReducer.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarReducer.kt index b3cd72d33c..15ede810ed 100644 --- a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarReducer.kt +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/presentation/GamificationToolbarReducer.kt @@ -7,6 +7,8 @@ import org.hyperskill.app.gamification_toolbar.domain.model.GamificationToolbarS import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarFeature.Action import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarFeature.Message import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarFeature.State +import org.hyperskill.app.streaks.domain.model.HistoricalStreak +import org.hyperskill.app.streaks.domain.model.StreakState import ru.nobird.app.presentation.redux.reducer.StateReducer class GamificationToolbarReducer( @@ -26,9 +28,10 @@ class GamificationToolbarReducer( State.Error to emptySet() is Message.FetchGamificationToolbarDataSuccess -> State.Content( - streak = message.streak, - hypercoinsBalance = message.hypercoinsBalance, - trackWithProgress = message.trackWithProgress + trackProgress = message.gamificationToolbarData.trackProgress, + currentStreak = message.gamificationToolbarData.currentStreak, + historicalStreak = HistoricalStreak(message.gamificationToolbarData.streakState), + hypercoinsBalance = message.gamificationToolbarData.hypercoinsBalance ) to emptySet() is Message.PullToRefresh -> when (state) { @@ -44,29 +47,31 @@ class GamificationToolbarReducer( else -> null } - is Message.FetchTrackWithProgressResult -> { - if (state is State.Content && message is Message.FetchTrackWithProgressResult.Success) { - state.copy(trackWithProgress = message.trackWithProgress) to emptySet() - } else { - null - } - } // Flow Messages is Message.StepSolved -> - if (state is State.Content) { - state.copy(streak = state.streak?.getStreakWithTodaySolved()) to emptySet() + if (state is State.Content && state.historicalStreak.state == StreakState.NOTHING) { + state.copy( + historicalStreak = HistoricalStreak(StreakState.COMPLETED), + currentStreak = state.currentStreak + 1 + ) to emptySet() } else { null } is Message.HypercoinsBalanceChanged -> if (state is State.Content) { - state.copy(hypercoinsBalance = message.hypercoinsBalance) to emptySet() + state.copy( + hypercoinsBalance = message.hypercoinsBalance + ) to emptySet() } else { null } is Message.StreakChanged -> - if (state is State.Content) { - state.copy(streak = message.streak) to emptySet() + if (state is State.Content && message.streak != null) { + state.copy( + currentStreak = message.streak.currentStreak, + historicalStreak = message.streak.history.firstOrNull()?.state?.let { HistoricalStreak(it) } + ?: state.historicalStreak + ) to emptySet() } else { null } @@ -74,13 +79,10 @@ class GamificationToolbarReducer( if (state is State.Content) { if (message.studyPlan.trackId != null) { state to setOf( - Action.FetchTrackWithProgress( - message.studyPlan.trackId, - screen.fetchTrackProgressSentryTransaction - ) + Action.FetchGamificationToolbarData(screen, forceUpdate = true) ) } else { - state.copy(trackWithProgress = null) to emptySet() + state.copy(trackProgress = null) to emptySet() } } else { null @@ -88,17 +90,9 @@ class GamificationToolbarReducer( } is Message.TopicCompleted -> { if (state is State.Content) { - val trackId = state.trackWithProgress?.track?.id - if (trackId != null) { - state to setOf( - Action.FetchTrackWithProgress( - trackId, - screen.fetchTrackProgressSentryTransaction - ) - ) - } else { - state to emptySet() - } + state to setOf( + Action.FetchGamificationToolbarData(screen, forceUpdate = true) + ) } else { null } diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/remote/GamificationToolbarRemoteDataSourceImpl.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/remote/GamificationToolbarRemoteDataSourceImpl.kt new file mode 100644 index 0000000000..1a944386b0 --- /dev/null +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/remote/GamificationToolbarRemoteDataSourceImpl.kt @@ -0,0 +1,22 @@ +package org.hyperskill.app.gamification_toolbar.remote + +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.request.get +import io.ktor.http.ContentType +import io.ktor.http.contentType +import org.hyperskill.app.gamification_toolbar.data.source.GamificationToolbarRemoteDataSource +import org.hyperskill.app.gamification_toolbar.domain.model.GamificationToolbarData +import org.hyperskill.app.gamification_toolbar.remote.model.CurrentGamificationToolbarResponse + +class GamificationToolbarRemoteDataSourceImpl( + private val httpClient: HttpClient +) : GamificationToolbarRemoteDataSource { + override suspend fun getGamificationToolbarData(): Result = + kotlin.runCatching { + httpClient + .get("/api/gamification-toolbars/current") { + contentType(ContentType.Application.Json) + }.body().gamificationToolbars.first() + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/remote/model/CurrentGamificationToolbarResponse.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/remote/model/CurrentGamificationToolbarResponse.kt new file mode 100644 index 0000000000..c794c979d3 --- /dev/null +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/gamification_toolbar/remote/model/CurrentGamificationToolbarResponse.kt @@ -0,0 +1,16 @@ +package org.hyperskill.app.gamification_toolbar.remote.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.hyperskill.app.core.remote.Meta +import org.hyperskill.app.core.remote.MetaResponse +import org.hyperskill.app.gamification_toolbar.domain.model.GamificationToolbarData + +@Serializable +class CurrentGamificationToolbarResponse( + @SerialName("meta") + override val meta: Meta, + + @SerialName("gamification-toolbars") + val gamificationToolbars: List +) : MetaResponse \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/domain/repository/SubmissionRepository.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/domain/repository/SubmissionRepository.kt index 7a3026a804..de62be087f 100644 --- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/domain/repository/SubmissionRepository.kt +++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_quiz/domain/repository/SubmissionRepository.kt @@ -1,6 +1,7 @@ package org.hyperskill.app.step_quiz.domain.repository import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow import org.hyperskill.app.step.domain.model.StepContext import org.hyperskill.app.step_quiz.domain.model.submissions.Reply import org.hyperskill.app.step_quiz.domain.model.submissions.Submission @@ -8,6 +9,9 @@ import org.hyperskill.app.step_quiz.domain.model.submissions.Submission interface SubmissionRepository { val solvedStepsMutableSharedFlow: MutableSharedFlow + val solvedStepsSharedFlow: SharedFlow + get() = solvedStepsMutableSharedFlow + suspend fun getSubmissionsForStep( stepId: Long, userId: Long,