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

ALTAPPS-557: StepQuizHints integrate State to ViewState mapping #330

Merged
Merged
Show file tree
Hide file tree
Changes from 6 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 @@ -6,10 +6,9 @@ import coil.ImageLoader
import coil.load
import coil.transform.CircleCropTransformation
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.hyperskill.app.android.R
import org.hyperskill.app.android.databinding.LayoutStepQuizHintsBinding
import org.hyperskill.app.reactions.domain.model.ReactionType
import org.hyperskill.app.step_quiz_hints.model.StepQuizHintsViewState
import org.hyperskill.app.step_quiz_hints.view.model.StepQuizHintsViewState
import org.hyperskill.app.step_quiz_hints.presentation.StepQuizHintsFeature
import ru.nobird.android.view.base.ui.delegate.ViewStateDelegate
import ru.nobird.android.view.base.ui.extension.setTextIfChanged
Expand Down Expand Up @@ -68,22 +67,22 @@ class StepQuizHintsDelegate(
stepQuizHintContentTextView.originalText = state.hintText
}
stepQuizHintBeforeRateGroup.isVisible =
state.hintState == StepQuizHintsViewState.HintState.ReactToHint
state.hintState == StepQuizHintsViewState.HintState.REACT_TO_HINT
stepQuizSeeNextHintButton.root.isVisible =
state.hintState == StepQuizHintsViewState.HintState.SeeNextHint
state.hintState == StepQuizHintsViewState.HintState.SEE_NEXT_HINT
stepQuizHintDescriptionTextView.isVisible =
state.hintState != StepQuizHintsViewState.HintState.SeeNextHint
if (state.hintState != StepQuizHintsViewState.HintState.SeeNextHint) {
state.hintState != StepQuizHintsViewState.HintState.SEE_NEXT_HINT
if (state.hintState != StepQuizHintsViewState.HintState.SEE_NEXT_HINT) {
@Suppress("KotlinConstantConditions")
stepQuizHintDescriptionTextView.setTextIfChanged(
when (state.hintState) {
StepQuizHintsViewState.HintState.ReactToHint -> org.hyperskill.app.R.string.step_quiz_hints_helpful_question_text
StepQuizHintsViewState.HintState.LastHint -> org.hyperskill.app.R.string.step_quiz_hints_last_hint_text
StepQuizHintsViewState.HintState.SeeNextHint -> error("Can't evaluate text for state = $state")
StepQuizHintsViewState.HintState.REACT_TO_HINT -> org.hyperskill.app.R.string.step_quiz_hints_helpful_question_text
StepQuizHintsViewState.HintState.LAST_HINT -> org.hyperskill.app.R.string.step_quiz_hints_last_hint_text
StepQuizHintsViewState.HintState.SEE_NEXT_HINT -> error("Can't evaluate text for state = $state")
}.let(context::getString)
)
}
if (state.hintState == StepQuizHintsViewState.HintState.ReactToHint) {
if (state.hintState == StepQuizHintsViewState.HintState.REACT_TO_HINT) {
stepQuizHintReportTextView.setOnClickListener {
handleHintReportClick(context, onNewMessage)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import org.hyperskill.app.android.databinding.LayoutStepQuizHintsBinding
import org.hyperskill.app.android.step_quiz_hints.delegate.StepQuizHintsDelegate
import org.hyperskill.app.core.injection.ReduxViewModelFactory
import org.hyperskill.app.step.domain.model.Step
import org.hyperskill.app.step_quiz_hints.model.StepQuizHintsViewState
import org.hyperskill.app.step_quiz_hints.view.model.StepQuizHintsViewState
import org.hyperskill.app.step_quiz_hints.presentation.StepQuizHintsFeature
import org.hyperskill.app.step_quiz_hints.presentation.StepQuizHintsViewModel
import ru.nobird.android.view.base.ui.extension.snackbar
Expand Down
4 changes: 4 additions & 0 deletions iosHyperskillApp/iosHyperskillApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@
2C96743F288831BB0091B6C9 /* StepQuizCodeSamplesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C96743E288831BB0091B6C9 /* StepQuizCodeSamplesView.swift */; };
2C96744228883A180091B6C9 /* StepQuizCodeViewDataMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C96744128883A180091B6C9 /* StepQuizCodeViewDataMapper.swift */; };
2C96744428883E710091B6C9 /* BlockOptionsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C96744328883E710091B6C9 /* BlockOptionsExtensions.swift */; };
2C97B0CD298124C1001DF1A0 /* StepQuizHintsViewStateKsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C97B0CC298124C1001DF1A0 /* StepQuizHintsViewStateKsExtensions.swift */; };
2C97E55A2859A2C500EA1A21 /* StepQuizNameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C97E5592859A2C500EA1A21 /* StepQuizNameView.swift */; };
2C97F50A28880B6F00DE77B7 /* SkeletonRoundedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C97F50928880B6F00DE77B7 /* SkeletonRoundedButton.swift */; };
2C98C7A62850B93100857783 /* alt.css in Resources */ = {isa = PBXBuildFile; fileRef = 2C98C79E2850B93100857783 /* alt.css */; };
Expand Down Expand Up @@ -616,6 +617,7 @@
2C96743E288831BB0091B6C9 /* StepQuizCodeSamplesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepQuizCodeSamplesView.swift; sourceTree = "<group>"; };
2C96744128883A180091B6C9 /* StepQuizCodeViewDataMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepQuizCodeViewDataMapper.swift; sourceTree = "<group>"; };
2C96744328883E710091B6C9 /* BlockOptionsExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockOptionsExtensions.swift; sourceTree = "<group>"; };
2C97B0CC298124C1001DF1A0 /* StepQuizHintsViewStateKsExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepQuizHintsViewStateKsExtensions.swift; sourceTree = "<group>"; };
2C97E5592859A2C500EA1A21 /* StepQuizNameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepQuizNameView.swift; sourceTree = "<group>"; };
2C97F50928880B6F00DE77B7 /* SkeletonRoundedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonRoundedButton.swift; sourceTree = "<group>"; };
2C98C79E2850B93100857783 /* alt.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = alt.css; sourceTree = "<group>"; };
Expand Down Expand Up @@ -999,6 +1001,7 @@
2C0FA878292FD73400A37636 /* ProfileSettingsFeatureStateKsExtensions.swift */,
2CFD7C67292542FB00902748 /* StepFeatureStateKsExtensions.swift */,
2CFD7C692925447600902748 /* StepQuizFeatureStateKsExtensions.swift */,
2C97B0CC298124C1001DF1A0 /* StepQuizHintsViewStateKsExtensions.swift */,
E9AD65A9292DC0BE00E574F0 /* TopicsRepetitionsFeatureStateKsExtensions.swift */,
);
path = Extensions;
Expand Down Expand Up @@ -2861,6 +2864,7 @@
2C1F5879280D2D1300372A37 /* WebOAuthURLParser.swift in Sources */,
E99B21892887E9DA006A6154 /* StepQuizTableSkeletonView.swift in Sources */,
E9F2CC552922694F00691540 /* TopicsRepetitionsChartBar.swift in Sources */,
2C97B0CD298124C1001DF1A0 /* StepQuizHintsViewStateKsExtensions.swift in Sources */,
2C6B30A828B7C47800609CE8 /* AuthNewUserPlaceholderAssembly.swift in Sources */,
2C5B2A1D286595960097B270 /* CodeCompletionTableViewCell.swift in Sources */,
2C27C77E28773042006A641A /* NukeManager.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import Foundation
import shared

extension StepQuizHintsViewStateKs: Equatable {
public static func == (lhs: StepQuizHintsViewStateKs, rhs: StepQuizHintsViewStateKs) -> Bool {
switch (lhs, rhs) {
case (.idle, .idle):
return true
case (.initialLoading, .initialLoading):
return true
case (.hintLoading, .hintLoading):
return true
case (.error, .error):
return true
case (.content(let lhsData), .content(let rhsData)):
return StepQuizHintsViewStateContentKs(lhsData) == StepQuizHintsViewStateContentKs(rhsData)
case (.content, .error):
return false
case (.content, .hintLoading):
return false
case (.content, .idle):
return false
case (.content, .initialLoading):
return false
case (.error, .content):
return false
case (.error, .hintLoading):
return false
case (.error, .idle):
return false
case (.error, .initialLoading):
return false
case (.hintLoading, .content):
return false
case (.hintLoading, .error):
return false
case (.hintLoading, .idle):
return false
case (.hintLoading, .initialLoading):
return false
case (.initialLoading, .content):
return false
case (.initialLoading, .error):
return false
case (.initialLoading, .hintLoading):
return false
case (.initialLoading, .idle):
return false
case (.idle, .content):
return false
case (.idle, .error):
return false
case (.idle, .hintLoading):
return false
case (.idle, .initialLoading):
return false
}
}
}

extension StepQuizHintsViewStateContentKs: Equatable {
public static func == (lhs: StepQuizHintsViewStateContentKs, rhs: StepQuizHintsViewStateContentKs) -> Bool {
switch (lhs, rhs) {
case (.seeHintButton, .seeHintButton):
return true
case (.hintCard(let lhsData), .hintCard(let rhsData)):
return lhsData.isEqual(rhsData)
case (.hintCard, .seeHintButton):
return false
case (.seeHintButton, .hintCard):
return false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,26 @@ import Foundation
import shared

final class StepQuizHintsViewModel: FeatureViewModel<
StepQuizHintsFeatureState,
StepQuizHintsViewState,
StepQuizHintsFeatureMessage,
StepQuizHintsFeatureActionViewAction
> {
let stepID: Int64

var stateKs: StepQuizHintsViewStateKs { .init(state) }

init(stepID: Int64, feature: Presentation_reduxFeature) {
self.stepID = stepID
super.init(feature: feature)
}

override func shouldNotifyStateDidChange(
oldState: StepQuizHintsViewState,
newState: StepQuizHintsViewState
) -> Bool {
StepQuizHintsViewStateKs(oldState) != StepQuizHintsViewStateKs(newState)
}

func loadHintsIDs() {
onNewMessage(StepQuizHintsFeatureMessageInitWithStepId(stepId: stepID))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,17 @@ struct StepQuizHintCardView: View {
private(set) var appearance = Appearance()

let authorAvatarSource: String?

let authorName: String

let hintText: String

let hintHasReaction: Bool
let hintState: StepQuizHintsViewStateHintState

let onReactionTapped: (ReactionType) -> Void

let onReportTapped: () -> Void

let onReportAlertAppeared: () -> Void

let onReportAlertConfirmed: () -> Void

let onReportAlertCanceled: () -> Void

let hasNextHints: Bool

let onNextHintTapped: (() -> Void)

@State private var isPresentingReportAlert = false
Expand All @@ -54,7 +46,7 @@ struct StepQuizHintCardView: View {

Spacer()

if !hintHasReaction {
if hintState == .reactToHint {
Button(Strings.StepQuiz.Hints.reportButton) {
isPresentingReportAlert = true
onReportTapped()
Expand All @@ -80,18 +72,18 @@ struct StepQuizHintCardView: View {
}
}

if hintHasReaction {
if hasNextHints {
StepQuizShowHintButton(text: Strings.StepQuiz.Hints.seeNextHint) {
isShowingMore = false
onNextHintTapped()
}
} else {
if hintState == .seeNextHint {
StepQuizShowHintButton(text: Strings.StepQuiz.Hints.seeNextHint) {
isShowingMore = false
onNextHintTapped()
}
} else {
if hintState == .lastHint {
Text(Strings.StepQuiz.Hints.lastHint)
.font(.caption)
.foregroundColor(.secondaryText)
}
} else {

HStack(spacing: LayoutInsets.smallInset) {
Text(Strings.StepQuiz.Hints.helpfulQuestion)
.font(.caption)
Expand Down Expand Up @@ -145,27 +137,38 @@ struct StepQuizHintCardView_Previews: PreviewProvider {
authorAvatarSource: nil,
authorName: "Name Surname",
hintText: "Python is used for almost everything in programming.",
hintHasReaction: true,
hintState: .reactToHint,
onReactionTapped: { _ in },
onReportTapped: {},
onReportAlertAppeared: {},
onReportAlertConfirmed: {},
onReportAlertCanceled: {},
onNextHintTapped: {}
)

StepQuizHintCardView(
authorAvatarSource: nil,
authorName: "Name Surname",
hintText: "Python is used for almost everything in programming.",
hintState: .seeNextHint,
onReactionTapped: { _ in },
onReportTapped: {},
onReportAlertAppeared: {},
onReportAlertConfirmed: {},
onReportAlertCanceled: {},
hasNextHints: true,
onNextHintTapped: {}
)

StepQuizHintCardView(
authorAvatarSource: nil,
authorName: "Name Surname",
hintText: "Python is used for almost everything in programming.",
hintHasReaction: false,
hintState: .lastHint,
onReactionTapped: { _ in },
onReportTapped: {},
onReportAlertAppeared: {},
onReportAlertConfirmed: {},
onReportAlertCanceled: {},
hasNextHints: true,
onNextHintTapped: {}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,38 +27,39 @@ struct StepQuizHintsView: View {

@ViewBuilder
private func buildBody() -> some View {
switch viewModel.state {
case is StepQuizHintsFeatureStateIdle:
switch viewModel.stateKs {
case .idle:
SkeletonRoundedView()
.frame(height: appearance.skeletonInitialHeight)
.onAppear {
viewModel.loadHintsIDs()
}
case is StepQuizHintsFeatureStateLoading:
.onAppear(perform: viewModel.loadHintsIDs)
case .initialLoading, .hintLoading:
SkeletonRoundedView()
.frame(height: appearance.skeletonHintHeight)
case is StepQuizHintsFeatureStateNetworkError:
case .error:
StepQuizShowHintButton(
text: Strings.Placeholder.networkErrorButtonText,
showLightning: false
) {
viewModel.onLoadHintButtonTap()
}
case let content as StepQuizHintsFeatureStateContent:
buildContent(state: content)
default:
Text("Unkwown state")
showLightning: false,
onClick: viewModel.onLoadHintButtonTap
)
case .content(let sealedState):
buildContent(state: StepQuizHintsViewStateContentKs(sealedState))
}
}

@ViewBuilder
private func buildContent(state: StepQuizHintsFeatureStateContent) -> some View {
if let hint = state.currentHint {
private func buildContent(state: StepQuizHintsViewStateContentKs) -> some View {
switch state {
case .seeHintButton:
StepQuizShowHintButton(
text: Strings.StepQuiz.Hints.showButton,
onClick: viewModel.onLoadHintButtonTap
)
case .hintCard(let data):
StepQuizHintCardView(
authorAvatarSource: hint.user.avatar,
authorName: hint.user.fullName,
hintText: hint.localizedText,
hintHasReaction: state.hintHasReaction,
authorAvatarSource: data.authorAvatar,
authorName: data.authorName,
hintText: data.hintText,
hintState: data.hintState,
onReactionTapped: viewModel.onHintReactionButtonTap(reaction:),
onReportTapped: viewModel.logClickedReportEvent,
onReportAlertAppeared: viewModel.logHintNoticeShownEvent,
Expand All @@ -67,22 +68,15 @@ struct StepQuizHintsView: View {
viewModel.logHintNoticeHiddenEvent(isReported: true)
},
onReportAlertCanceled: { viewModel.logHintNoticeHiddenEvent(isReported: false) },
hasNextHints: !state.hintsIds.isEmpty,
onNextHintTapped: viewModel.onLoadHintButtonTap
)
} else if !state.hintsIds.isEmpty {
StepQuizShowHintButton(text: Strings.StepQuiz.Hints.showButton) {
viewModel.onLoadHintButtonTap()
}
}
}

private func handleViewAction(_ viewAction: StepQuizHintsFeatureActionViewAction) {
switch viewAction {
case is StepQuizHintsFeatureActionViewActionShowNetworkError:
switch StepQuizHintsFeatureActionViewActionKs(viewAction) {
case .showNetworkError:
ProgressHUD.showError(status: Strings.General.connectionError)
default:
print("StepQuizHintsViewView :: \(#function) viewAction = \(viewAction)")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package org.hyperskill.app.step_quiz_hints.injection

import org.hyperskill.app.core.injection.AppGraph
import org.hyperskill.app.core.injection.ReduxViewModelFactory
import org.hyperskill.app.core.presentation.transformState
import org.hyperskill.app.step.domain.model.Step
import org.hyperskill.app.step_quiz_hints.mapper.StepQuizHintsViewStateMapper
import org.hyperskill.app.step_quiz_hints.presentation.StepQuizHintsViewModel
import ru.nobird.app.presentation.redux.container.wrapWithViewContainer

Expand All @@ -21,9 +19,7 @@ class PlatformStepQuizHintsComponentImpl(
StepQuizHintsViewModel::class.java to
{
StepQuizHintsViewModel(
reduxViewContainer = stepQuizHintComponent.stepQuizHintsFeature
.transformState(StepQuizHintsViewStateMapper::mapState)
.wrapWithViewContainer(),
reduxViewContainer = stepQuizHintComponent.stepQuizHintsFeature.wrapWithViewContainer(),
step = step
)
}
Expand Down
Loading