Skip to content

Commit

Permalink
HomeFeature ViewState and InternalAction
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-magda committed Nov 13, 2023
1 parent 0fec8a6 commit 7d353d9
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import ru.nobird.app.presentation.redux.container.ReduxView

class HomeFragment :
Fragment(R.layout.fragment_home),
ReduxView<HomeFeature.State, HomeFeature.Action.ViewAction> {
ReduxView<HomeFeature.ViewState, HomeFeature.Action.ViewAction> {
companion object {
fun newInstance(): Fragment =
HomeFragment()
Expand Down Expand Up @@ -172,7 +172,7 @@ class HomeFragment :
}
}

override fun render(state: HomeFeature.State) {
override fun render(state: HomeFeature.ViewState) {
homeViewStateDelegate.switchState(state.homeState)

renderSwipeRefresh(state)
Expand All @@ -186,7 +186,7 @@ class HomeFragment :
gamificationToolbarDelegate?.render(state.toolbarState)
}

private fun renderSwipeRefresh(state: HomeFeature.State) {
private fun renderSwipeRefresh(state: HomeFeature.ViewState) {
with(viewBinding.homeScreenSwipeRefreshLayout) {
isEnabled = state.homeState is HomeFeature.HomeState.Content
updateIsRefreshing(state.isRefreshing)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import shared
import UIKit

final class HomeViewModel: FeatureViewModel<HomeFeatureState, HomeFeatureMessage, HomeFeatureActionViewAction> {
final class HomeViewModel: FeatureViewModel<HomeFeature.ViewState, HomeFeatureMessage, HomeFeatureActionViewAction> {
private var applicationWasInBackground = false
private var shouldReloadContent = false

Expand All @@ -25,7 +25,10 @@ final class HomeViewModel: FeatureViewModel<HomeFeatureState, HomeFeatureMessage
)
}

override func shouldNotifyStateDidChange(oldState: HomeFeatureState, newState: HomeFeatureState) -> Bool {
override func shouldNotifyStateDidChange(
oldState: HomeFeature.ViewState,
newState: HomeFeature.ViewState
) -> Bool {
!oldState.isEqual(newState)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,7 @@ struct HomeView: View {
}
}

@available(iOS 17, *)
#Preview {
UIKitViewControllerPreview {
HomeAssembly().makeModule()
}
HomeAssembly().makeModule()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import ru.nobird.android.view.redux.viewmodel.ReduxViewModel
import ru.nobird.app.presentation.redux.container.ReduxViewContainer

class HomeViewModel(
reduxViewContainer: ReduxViewContainer<HomeFeature.State, HomeFeature.Message, HomeFeature.Action.ViewAction>
) : ReduxViewModel<HomeFeature.State, HomeFeature.Message, HomeFeature.Action.ViewAction>(reduxViewContainer)
reduxViewContainer: ReduxViewContainer<HomeFeature.ViewState, HomeFeature.Message, HomeFeature.Action.ViewAction>
) : ReduxViewModel<HomeFeature.ViewState, HomeFeature.Message, HomeFeature.Action.ViewAction>(reduxViewContainer)
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import org.hyperskill.app.home.presentation.HomeFeature
import ru.nobird.app.presentation.redux.feature.Feature

interface HomeComponent {
val homeFeature: Feature<HomeFeature.State, HomeFeature.Message, HomeFeature.Action>
val homeFeature: Feature<HomeFeature.ViewState, HomeFeature.Message, HomeFeature.Action>
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class HomeComponentImpl(private val appGraph: AppGraph) : HomeComponent {
private val challengeWidgetComponent: ChallengeWidgetComponent =
appGraph.buildChallengeWidgetComponent()

override val homeFeature: Feature<HomeFeature.State, HomeFeature.Message, HomeFeature.Action>
override val homeFeature: Feature<HomeFeature.ViewState, HomeFeature.Message, HomeFeature.Action>
get() = HomeFeatureBuilder.build(
homeInteractor,
appGraph.profileDataComponent.currentProfileStateRepository,
Expand All @@ -33,6 +33,7 @@ class HomeComponentImpl(private val appGraph: AppGraph) : HomeComponent {
gamificationToolbarComponent.gamificationToolbarActionDispatcher,
challengeWidgetComponent.challengeWidgetReducer,
challengeWidgetComponent.challengeWidgetActionDispatcher,
challengeWidgetComponent.challengeWidgetViewStateMapper,
appGraph.loggerComponent.logger,
appGraph.commonComponent.buildKonfig.buildVariant
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import org.hyperskill.app.analytic.domain.interactor.AnalyticInteractor
import org.hyperskill.app.challenges.widget.presentation.ChallengeWidgetActionDispatcher
import org.hyperskill.app.challenges.widget.presentation.ChallengeWidgetFeature
import org.hyperskill.app.challenges.widget.presentation.ChallengeWidgetReducer
import org.hyperskill.app.challenges.widget.view.mapper.ChallengeWidgetViewStateMapper
import org.hyperskill.app.core.domain.BuildVariant
import org.hyperskill.app.core.presentation.ActionDispatcherOptions
import org.hyperskill.app.core.presentation.transformState
import org.hyperskill.app.core.view.mapper.SharedDateFormatter
import org.hyperskill.app.freemium.domain.interactor.FreemiumInteractor
import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarActionDispatcher
Expand All @@ -16,6 +18,7 @@ import org.hyperskill.app.home.domain.interactor.HomeInteractor
import org.hyperskill.app.home.presentation.HomeActionDispatcher
import org.hyperskill.app.home.presentation.HomeFeature
import org.hyperskill.app.home.presentation.HomeReducer
import org.hyperskill.app.home.view.mapper.HomeViewStateMapper
import org.hyperskill.app.logging.presentation.wrapWithLogger
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
Expand Down Expand Up @@ -45,9 +48,10 @@ internal object HomeFeatureBuilder {
gamificationToolbarActionDispatcher: GamificationToolbarActionDispatcher,
challengeWidgetReducer: ChallengeWidgetReducer,
challengeWidgetActionDispatcher: ChallengeWidgetActionDispatcher,
challengeWidgetViewStateMapper: ChallengeWidgetViewStateMapper,
logger: Logger,
buildVariant: BuildVariant
): Feature<HomeFeature.State, HomeFeature.Message, HomeFeature.Action> {
): Feature<HomeFeature.ViewState, HomeFeature.Message, HomeFeature.Action> {
val homeReducer = HomeReducer(
gamificationToolbarReducer = gamificationToolbarReducer,
challengeWidgetReducer = challengeWidgetReducer
Expand All @@ -64,6 +68,9 @@ internal object HomeFeatureBuilder {
dateFormatter,
topicRepeatedFlow
)
val homeViewStateMapper = HomeViewStateMapper(
challengeWidgetViewStateMapper = challengeWidgetViewStateMapper
)

return ReduxFeature(
HomeFeature.State(
Expand All @@ -73,16 +80,17 @@ internal object HomeFeatureBuilder {
),
homeReducer
)
.transformState(homeViewStateMapper::map)
.wrapWithActionDispatcher(homeActionDispatcher)
.wrapWithActionDispatcher(
gamificationToolbarActionDispatcher.transform(
transformAction = { it.safeCast<HomeFeature.Action.GamificationToolbarAction>()?.action },
transformAction = { it.safeCast<HomeFeature.InternalAction.GamificationToolbarAction>()?.action },
transformMessage = HomeFeature.Message::GamificationToolbarMessage
)
)
.wrapWithActionDispatcher(
challengeWidgetActionDispatcher.transform(
transformAction = { it.safeCast<HomeFeature.Action.ChallengeWidgetAction>()?.action },
transformAction = { it.safeCast<HomeFeature.InternalAction.ChallengeWidgetAction>()?.action },
transformMessage = HomeFeature.Message::ChallengeWidgetMessage
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.hyperskill.app.core.view.mapper.SharedDateFormatter
import org.hyperskill.app.freemium.domain.interactor.FreemiumInteractor
import org.hyperskill.app.home.domain.interactor.HomeInteractor
import org.hyperskill.app.home.presentation.HomeFeature.Action
import org.hyperskill.app.home.presentation.HomeFeature.InternalAction
import org.hyperskill.app.home.presentation.HomeFeature.Message
import org.hyperskill.app.profile.domain.repository.CurrentProfileStateRepository
import org.hyperskill.app.sentry.domain.interactor.SentryInteractor
Expand All @@ -32,7 +33,7 @@ import org.hyperskill.app.topics_repetitions.domain.flow.TopicRepeatedFlow
import org.hyperskill.app.topics_repetitions.domain.interactor.TopicsRepetitionsInteractor
import ru.nobird.app.presentation.redux.dispatcher.CoroutineActionDispatcher

class HomeActionDispatcher(
internal class HomeActionDispatcher(
config: ActionDispatcherOptions,
homeInteractor: HomeInteractor,
private val currentProfileStateRepository: CurrentProfileStateRepository,
Expand Down Expand Up @@ -71,8 +72,9 @@ class HomeActionDispatcher(

override suspend fun doSuspendableAction(action: Action) {
when (action) {
is Action.FetchHomeScreenData -> handleFetchHomeScreenData(::onNewMessage)
is Action.LaunchTimer -> {
is InternalAction.FetchHomeScreenData ->
handleFetchHomeScreenData(::onNewMessage)
is InternalAction.LaunchTimer -> {
if (isTimerLaunched) {
return
}
Expand All @@ -99,7 +101,7 @@ class HomeActionDispatcher(
}
.launchIn(actionScope)
}
is Action.LogAnalyticEvent ->
is InternalAction.LogAnalyticEvent ->
analyticInteractor.logEvent(action.analyticEvent)
else -> {
// no op
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ package org.hyperskill.app.home.presentation
import org.hyperskill.app.analytic.domain.model.AnalyticEvent
import org.hyperskill.app.challenges.widget.presentation.ChallengeWidgetFeature
import org.hyperskill.app.challenges.widget.presentation.ChallengeWidgetFeature.isRefreshing
import org.hyperskill.app.challenges.widget.view.model.ChallengeWidgetViewState
import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarFeature
import org.hyperskill.app.gamification_toolbar.presentation.GamificationToolbarFeature.isRefreshing
import org.hyperskill.app.step.domain.model.Step
import org.hyperskill.app.step.domain.model.StepRoute
import org.hyperskill.app.streaks.domain.model.Streak

interface HomeFeature {
data class State(
object HomeFeature {
internal data class State(
val homeState: HomeState,
val toolbarState: GamificationToolbarFeature.State,
val challengeWidgetState: ChallengeWidgetFeature.State
Expand All @@ -21,6 +22,13 @@ interface HomeFeature {
challengeWidgetState.isRefreshing
}

data class ViewState(
val homeState: HomeState,
val toolbarState: GamificationToolbarFeature.State,
val challengeWidgetViewState: ChallengeWidgetViewState,
val isRefreshing: Boolean
)

sealed interface HomeState {
/**
* Represents initial state.
Expand Down Expand Up @@ -122,22 +130,16 @@ interface HomeFeature {
/**
* Message Wrappers
*/
data class GamificationToolbarMessage(val message: GamificationToolbarFeature.Message) : Message
data class ChallengeWidgetMessage(val message: ChallengeWidgetFeature.Message) : Message
data class GamificationToolbarMessage(
val message: GamificationToolbarFeature.Message
) : Message

data class ChallengeWidgetMessage(
val message: ChallengeWidgetFeature.Message
) : Message
}

sealed interface Action {
object FetchHomeScreenData : Action
object LaunchTimer : Action

data class LogAnalyticEvent(val analyticEvent: AnalyticEvent) : Action

/**
* Action Wrappers
*/
data class GamificationToolbarAction(val action: GamificationToolbarFeature.Action) : Action
data class ChallengeWidgetAction(val action: ChallengeWidgetFeature.Action) : Action

sealed interface ViewAction : Action {
sealed interface NavigateTo : ViewAction {
data class StepScreen(val stepRoute: StepRoute) : NavigateTo
Expand All @@ -150,9 +152,28 @@ interface HomeFeature {
data class GamificationToolbarViewAction(
val viewAction: GamificationToolbarFeature.Action.ViewAction
) : ViewAction

data class ChallengeWidgetViewAction(
val viewAction: ChallengeWidgetFeature.Action.ViewAction
) : ViewAction
}
}

internal sealed interface InternalAction : Action {
object FetchHomeScreenData : InternalAction
object LaunchTimer : InternalAction

data class LogAnalyticEvent(val analyticEvent: AnalyticEvent) : InternalAction

/**
* Action Wrappers
*/
data class GamificationToolbarAction(
val action: GamificationToolbarFeature.Action
) : InternalAction

data class ChallengeWidgetAction(
val action: ChallengeWidgetFeature.Action
) : InternalAction
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import org.hyperskill.app.home.domain.analytic.HomeClickedTopicsRepetitionsCardH
import org.hyperskill.app.home.domain.analytic.HomeViewedHyperskillAnalyticEvent
import org.hyperskill.app.home.presentation.HomeFeature.Action
import org.hyperskill.app.home.presentation.HomeFeature.HomeState
import org.hyperskill.app.home.presentation.HomeFeature.InternalAction
import org.hyperskill.app.home.presentation.HomeFeature.Message
import org.hyperskill.app.home.presentation.HomeFeature.State
import ru.nobird.app.presentation.redux.reducer.StateReducer

private typealias HomeReducerResult = Pair<State, Set<Action>>

class HomeReducer(
internal class HomeReducer(
private val gamificationToolbarReducer: GamificationToolbarReducer,
private val challengeWidgetReducer: ChallengeWidgetReducer
) : StateReducer<State, Message, Action> {
Expand All @@ -44,7 +45,7 @@ class HomeReducer(
// Timer Messages
is Message.ReadyToLaunchNextProblemInTimer ->
if (state.homeState is HomeState.Content) {
state to setOf(Action.LaunchTimer)
state to setOf(InternalAction.LaunchTimer)
} else {
null
}
Expand Down Expand Up @@ -143,7 +144,7 @@ class HomeReducer(
state.homeState.repetitionsState.recommendedRepetitionsCount == 0
state to setOf(
Action.ViewAction.NavigateTo.TopicsRepetitionsScreen,
Action.LogAnalyticEvent(
InternalAction.LogAnalyticEvent(
HomeClickedTopicsRepetitionsCardHyperskillAnalyticEvent(isCompleted = isCompleted)
)
)
Expand All @@ -167,7 +168,7 @@ class HomeReducer(
}
}
val logEventAction = if (analyticsEvent != null) {
setOf(Action.LogAnalyticEvent(analyticsEvent))
setOf(InternalAction.LogAnalyticEvent(analyticsEvent))
} else {
emptySet()
}
Expand All @@ -178,13 +179,13 @@ class HomeReducer(
}
// Analytic Messages
is Message.ViewedEventMessage ->
state to setOf(Action.LogAnalyticEvent(HomeViewedHyperskillAnalyticEvent()))
state to setOf(InternalAction.LogAnalyticEvent(HomeViewedHyperskillAnalyticEvent()))
is Message.ClickedProblemOfDayCardEventMessage -> {
if (state.homeState is HomeState.Content) {
when (state.homeState.problemOfDayState) {
is HomeFeature.ProblemOfDayState.NeedToSolve -> {
state to setOf(
Action.LogAnalyticEvent(
InternalAction.LogAnalyticEvent(
HomeClickedProblemOfDayCardHyperskillAnalyticEvent(
isCompleted = false
)
Expand All @@ -193,7 +194,7 @@ class HomeReducer(
}
is HomeFeature.ProblemOfDayState.Solved -> {
state to setOf(
Action.LogAnalyticEvent(
InternalAction.LogAnalyticEvent(
HomeClickedProblemOfDayCardHyperskillAnalyticEvent(
isCompleted = true
)
Expand Down Expand Up @@ -227,7 +228,7 @@ class HomeReducer(
forceUpdate && (state.homeState is HomeState.Content || state.homeState is HomeState.NetworkError)
val (homeState, homeActions) =
if (shouldReloadHome) {
HomeState.Loading to setOf(Action.FetchHomeScreenData)
HomeState.Loading to setOf(InternalAction.FetchHomeScreenData)
} else {
state.homeState to emptySet()
}
Expand Down Expand Up @@ -256,8 +257,8 @@ class HomeReducer(
state.homeState is HomeState.Content && !state.homeState.isRefreshing
) {
state.homeState.copy(isRefreshing = true) to setOf(
Action.FetchHomeScreenData,
Action.LogAnalyticEvent(HomeClickedPullToRefreshHyperskillAnalyticEvent())
InternalAction.FetchHomeScreenData,
InternalAction.LogAnalyticEvent(HomeClickedPullToRefreshHyperskillAnalyticEvent())
)
} else {
state.homeState to emptySet()
Expand Down Expand Up @@ -293,7 +294,7 @@ class HomeReducer(
if (it is GamificationToolbarFeature.Action.ViewAction) {
Action.ViewAction.GamificationToolbarViewAction(it)
} else {
Action.GamificationToolbarAction(it)
InternalAction.GamificationToolbarAction(it)
}
}
.toSet()
Expand All @@ -312,7 +313,7 @@ class HomeReducer(
if (it is ChallengeWidgetFeature.Action.ViewAction) {
Action.ViewAction.ChallengeWidgetViewAction(it)
} else {
Action.ChallengeWidgetAction(it)
InternalAction.ChallengeWidgetAction(it)
}
}
.toSet()
Expand Down
Loading

0 comments on commit 7d353d9

Please sign in to comment.