Skip to content

Commit

Permalink
Implement interview preparation completed modal
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-magda committed Jan 4, 2024
1 parent 9d35ee0 commit 36afcbd
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ class StepDelegate<TFragment>(
mainScreenRouter.switch(Tabs.STUDY_PLAN)
}

StepCompletionFeature.Action.ViewAction.NavigateTo.Home -> {
fragment.requireRouter().backTo(MainScreen(Tabs.TRAINING))
mainScreenRouter.switch(Tabs.TRAINING)
}

is StepCompletionFeature.Action.ViewAction.ReloadStep -> {
fragment.requireRouter().replaceScreen(StepScreen(stepCompletionAction.stepRoute))
}
Expand Down
16 changes: 16 additions & 0 deletions iosHyperskillApp/iosHyperskillApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
2C186AD72B4693E200DADB26 /* InterviewPreparationWidgetContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C186AD62B4693E200DADB26 /* InterviewPreparationWidgetContentView.swift */; };
2C186AD92B46969D00DADB26 /* HomeWidgetCountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C186AD82B46969D00DADB26 /* HomeWidgetCountView.swift */; };
2C186ADB2B46989700DADB26 /* TopicsRepetitionsCountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C186ADA2B46989700DADB26 /* TopicsRepetitionsCountView.swift */; };
2C186ADD2B46A08E00DADB26 /* InterviewPreparationCompletedModalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C186ADC2B46A08E00DADB26 /* InterviewPreparationCompletedModalViewController.swift */; };
2C186ADF2B46A0A300DADB26 /* InterviewPreparationCompletedModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C186ADE2B46A0A300DADB26 /* InterviewPreparationCompletedModalView.swift */; };
2C198DFE2AEA444100DCD35A /* FillBlanksSelectContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C198DFD2AEA444100DCD35A /* FillBlanksSelectContainerView.swift */; };
2C198E012AEA835F00DCD35A /* StepQuizFillBlanksSelectOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C198E002AEA835F00DCD35A /* StepQuizFillBlanksSelectOptionsView.swift */; };
2C198E032AEA869300DCD35A /* StepQuizFillBlanksSelectOptionsCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C198E022AEA869300DCD35A /* StepQuizFillBlanksSelectOptionsCollectionViewCell.swift */; };
Expand Down Expand Up @@ -753,6 +755,8 @@
2C186AD62B4693E200DADB26 /* InterviewPreparationWidgetContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterviewPreparationWidgetContentView.swift; sourceTree = "<group>"; };
2C186AD82B46969D00DADB26 /* HomeWidgetCountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeWidgetCountView.swift; sourceTree = "<group>"; };
2C186ADA2B46989700DADB26 /* TopicsRepetitionsCountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopicsRepetitionsCountView.swift; sourceTree = "<group>"; };
2C186ADC2B46A08E00DADB26 /* InterviewPreparationCompletedModalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterviewPreparationCompletedModalViewController.swift; sourceTree = "<group>"; };
2C186ADE2B46A0A300DADB26 /* InterviewPreparationCompletedModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterviewPreparationCompletedModalView.swift; sourceTree = "<group>"; };
2C198DFD2AEA444100DCD35A /* FillBlanksSelectContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FillBlanksSelectContainerView.swift; sourceTree = "<group>"; };
2C198E002AEA835F00DCD35A /* StepQuizFillBlanksSelectOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepQuizFillBlanksSelectOptionsView.swift; sourceTree = "<group>"; };
2C198E022AEA869300DCD35A /* StepQuizFillBlanksSelectOptionsCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepQuizFillBlanksSelectOptionsCollectionViewCell.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1631,6 +1635,15 @@
path = Views;
sourceTree = "<group>";
};
2C186AE02B46A0AB00DADB26 /* InterviewPreparationCompleted */ = {
isa = PBXGroup;
children = (
2C186ADE2B46A0A300DADB26 /* InterviewPreparationCompletedModalView.swift */,
2C186ADC2B46A08E00DADB26 /* InterviewPreparationCompletedModalViewController.swift */,
);
path = InterviewPreparationCompleted;
sourceTree = "<group>";
};
2C198DFC2AEA441E00DCD35A /* Select */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3228,6 +3241,7 @@
children = (
E97BEA1D2977D26F00348EEC /* TopicCompletedModalViewController.swift */,
E9CC6C0329893D8400D8D070 /* TopicCompletedModalViewControllerDelegate.swift */,
2C186AE02B46A0AB00DADB26 /* InterviewPreparationCompleted */,
);
path = Modals;
sourceTree = "<group>";
Expand Down Expand Up @@ -4604,6 +4618,7 @@
E996D414292228A700A47498 /* TopicsRepetitionsView.swift in Sources */,
2CAE8D092805789100E6C83D /* StepCommentsStatisticsView.swift in Sources */,
E94BB0462A9DEF7C00736B7C /* StepQuizParsonsControlsView.swift in Sources */,
2C186ADD2B46A08E00DADB26 /* InterviewPreparationCompletedModalViewController.swift in Sources */,
2C5CBBE72948FC7A00113007 /* StepQuizSQLView.swift in Sources */,
2C54E4262A1F7086003406B9 /* TrackSelectionDetailsDescriptionView.swift in Sources */,
2C05AC462A0E9EBC0039C7EF /* ProjectSelectionListFeatureViewStateKsExtensions.swift in Sources */,
Expand Down Expand Up @@ -4892,6 +4907,7 @@
2C82BA322844B01D004C9013 /* PlaceholderView+Configurations.swift in Sources */,
2C25BFD52851F8F00036C689 /* UIColor+DesignSystem.swift in Sources */,
2C023C8D285DCA4300D2D5A9 /* DatasetExtensions.swift in Sources */,
2C186ADF2B46A0A300DADB26 /* InterviewPreparationCompletedModalView.swift in Sources */,
E91017152832975C002E70F5 /* CheckboxButton.swift in Sources */,
2C99B1002A14255F0018627B /* StudyPlanWidgetViewStateSectionItemStateWrapper.swift in Sources */,
E9E964872A0B8D8200841DF6 /* StepQuizProblemsLimitView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,6 @@ enum Images {
static let icon = "stage-implement-unsupported-modal-icon"
}

enum StageCompletedModal {
static let icon = "stage-implement-stage-completed-modal-icon"
}

enum ProjectCompletedModal {
static let icon = "stage-implement-project-completed-modal-icon"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,14 +257,16 @@ enum Strings {
static let networkError = sharedStrings.challenge_widget_network_error_text.localized()
}

// MARK: - Interview preparation widget -
// MARK: - Interview Preparation -

// MARK: Widget

enum InterviewPreparationWidget {
static let title = sharedStrings.interview_preparation_widget_title.localized()
static let networkError = sharedStrings.interview_preparation_widget_network_error_text.localized()
}

// MARK: - Interview preparation onboarding -
// MARK: Onboarding

enum InterviewPreparationOnboarding {
static let navigationTitle = sharedStrings.interview_preparation_onboarding_screen_title.localized()
Expand All @@ -274,6 +276,13 @@ enum Strings {
static let callToActionButton = sharedStrings.interview_preparation_onboarding_go_to_first_problem.localized()
}

// MARK: Completed modal

enum InterviewPreparationCompletedModal {
static let title = sharedStrings.interview_preparation_finished_modal_title.localized()
static let description = sharedStrings.interview_preparation_finished_modal_description.localized()
}

// MARK: - Topics widget -

enum TopicsWidget {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct StageImplementStageCompletedModalView: View {

var body: some View {
VStack(alignment: .leading, spacing: appearance.spacing) {
Image(Images.StageImplement.StageCompletedModal.icon)
Image(.stageImplementStageCompletedModalIcon)
.renderingMode(.original)
.aspectRatio(contentMode: .fit)
.frame(maxWidth: .infinity, alignment: .leading)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,37 @@ extension StepViewModel: ShareStreakModalViewControllerDelegate {
)
}
}

// MARK: - StepViewModel: InterviewPreparationCompletedModalViewControllerDelegate -

extension StepViewModel: InterviewPreparationCompletedModalViewControllerDelegate {
func interviewPreparationCompletedModalViewControllerDidAppear(
_ viewController: InterviewPreparationCompletedModalViewController
) {
onNewMessage(
StepFeatureMessageStepCompletionMessage(
message: StepCompletionFeatureMessageInterviewPreparationCompletedModalShownEventMessage()
)
)
}

func interviewPreparationCompletedModalViewControllerDidDisappear(
_ viewController: InterviewPreparationCompletedModalViewController
) {
onNewMessage(
StepFeatureMessageStepCompletionMessage(
message: StepCompletionFeatureMessageInterviewPreparationCompletedModalHiddenEventMessage()
)
)
}

func interviewPreparationCompletedModalViewControllerDidTapCallToActionButton(
_ viewController: InterviewPreparationCompletedModalViewController
) {
onNewMessage(
StepFeatureMessageStepCompletionMessage(
message: StepCompletionFeatureMessageInterviewPreparationCompletedModalGoToTrainingClicked()
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import SwiftUI

extension InterviewPreparationCompletedModalView {
struct Appearance {
let spacing: CGFloat = LayoutInsets.defaultInset * 2
let interitemSpacing = LayoutInsets.defaultInset
}
}

struct InterviewPreparationCompletedModalView: View {
private(set) var appearance = Appearance()

var onCallToActionTap: () -> Void = {}

var body: some View {
VStack(alignment: .leading, spacing: appearance.spacing) {
Image(.stageImplementStageCompletedModalIcon)
.renderingMode(.original)
.aspectRatio(contentMode: .fit)
.frame(maxWidth: .infinity, alignment: .leading)

VStack(alignment: .leading, spacing: appearance.interitemSpacing) {
Text(Strings.InterviewPreparationCompletedModal.title)
.font(.title2).bold()
.foregroundColor(.primaryText)

Text(Strings.InterviewPreparationCompletedModal.description)
.font(.body)
.foregroundColor(.primaryText)
}

Button(
Strings.Common.goToTraining,
action: onCallToActionTap
)
.buttonStyle(.primary)
.shineEffect()
}
.padding([.horizontal, .bottom])
}
}

#Preview {
InterviewPreparationCompletedModalView()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import SwiftUI

protocol InterviewPreparationCompletedModalViewControllerDelegate: AnyObject {
func interviewPreparationCompletedModalViewControllerDidAppear(
_ viewController: InterviewPreparationCompletedModalViewController
)
func interviewPreparationCompletedModalViewControllerDidDisappear(
_ viewController: InterviewPreparationCompletedModalViewController
)
func interviewPreparationCompletedModalViewControllerDidTapCallToActionButton(
_ viewController: InterviewPreparationCompletedModalViewController
)
}

final class InterviewPreparationCompletedModalViewController: PanModalSwiftUIViewController<
InterviewPreparationCompletedModalView
> {
private weak var delegate: InterviewPreparationCompletedModalViewControllerDelegate?

convenience init(delegate: InterviewPreparationCompletedModalViewControllerDelegate?) {
var view = InterviewPreparationCompletedModalView()

self.init(
isPresented: .init(get: { false }, set: { _ in }),
content: { view }
)

view.onCallToActionTap = { [weak self] in
guard let strongSelf = self else {
return
}

strongSelf.delegate?.interviewPreparationCompletedModalViewControllerDidTapCallToActionButton(strongSelf)
strongSelf.dismiss(animated: true)
}

self.delegate = delegate
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
delegate?.interviewPreparationCompletedModalViewControllerDidAppear(self)
}

override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
delegate?.interviewPreparationCompletedModalViewControllerDidDisappear(self)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ struct StepView: View {
case .studyPlan:
dismissPanModalAndNavigateBack()
TabBarRouter(tab: .studyPlan).route()
case .home:
dismissPanModalAndNavigateBack()
TabBarRouter(tab: .home).route()
}
case .showProblemOfDaySolvedModal(let showProblemOfDaySolvedModalViewAction):
presentDailyStepCompletedModal(
Expand Down Expand Up @@ -141,8 +144,8 @@ struct StepView: View {

// MARK: - StepView (Modals) -

extension StepView {
private func presentTopicCompletedModal(modalText: String, isNextStepAvailable: Bool) {
private extension StepView {
func presentTopicCompletedModal(modalText: String, isNextStepAvailable: Bool) {
let modal = TopicCompletedModalViewController(
modalText: modalText,
isNextStepAvailable: isNextStepAvailable,
Expand All @@ -151,7 +154,7 @@ extension StepView {
panModalPresenter.presentPanModal(modal)
}

private func presentDailyStepCompletedModal(
func presentDailyStepCompletedModal(
earnedGemsText: String,
shareStreakData: StepCompletionFeatureShareStreakData
) {
Expand All @@ -163,21 +166,22 @@ extension StepView {
panModalPresenter.presentPanModal(modal)
}

private func presentShareStreakModal(streak: Int) {
func presentShareStreakModal(streak: Int) {
let modal = ShareStreakModalViewController(
streak: streak,
delegate: viewModel
)
panModalPresenter.presentPanModal(modal)
}

private func presentShareStreakSystemModal(streak: Int) {
func presentShareStreakSystemModal(streak: Int) {
let activityViewController = ShareStreakAction.makeActivityViewController(for: streak)
modalRouter.present(module: activityViewController, modalPresentationStyle: .automatic)
}

private func presentInterviewPreparationFinishedModal() {
#warning("TODO: ALTAPPS-1093")
func presentInterviewPreparationFinishedModal() {
let modal = InterviewPreparationCompletedModalViewController(delegate: viewModel)
panModalPresenter.presentPanModal(modal)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ object StepCompletionFeature {
sealed interface NavigateTo : ViewAction {
object Back : NavigateTo
object StudyPlan : NavigateTo
object Home : NavigateTo
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ class StepCompletionReducer(private val stepRoute: StepRoute) : StateReducer<Sta
stepRoute.analyticRoute
)
),
Action.ViewAction.NavigateTo.StudyPlan
Action.ViewAction.NavigateTo.Home
)
/**
* Analytic
Expand Down

0 comments on commit 36afcbd

Please sign in to comment.