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

GT-2465 resume lesson modal #2352

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ SPEC REPOS:
- GodToolsShared

SPEC CHECKSUMS:
GodToolsShared: 404a619e53dc1890091397ac4e1da69afb5eabcd
GodToolsShared: 0b717d26f71b2eb7748b6999ad3d2d6fe7a8c401

PODFILE CHECKSUM: 1816453b60fe876696e3cc9b1da49602bb07e16b
PODFILE CHECKSUM: 4afa67206a45df71c21cb5eb808888f3037d2463

COCOAPODS: 1.15.2
123 changes: 49 additions & 74 deletions godtools.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// GetResumeLessonProgressModalInterfaceStringsRepository.swift
// godtools
//
// Created by Rachael Skeath on 11/14/24.
// Copyright © 2024 Cru. All rights reserved.
//

import Foundation
import Combine
import LocalizationServices

class GetResumeLessonProgressModalInterfaceStringsRepository: GetResumeLessonProgressModalInterfaceStringsRepositoryInterface {

private let localizationServices: LocalizationServices

init(localizationServices: LocalizationServices) {
self.localizationServices = localizationServices
}

func getStringsPublisher(translateInLanguage: AppLanguageDomainModel) -> AnyPublisher<ResumeLessonProgressModalInterfaceStringsDomainModel, Never> {

let localeId: String = translateInLanguage.localeId

let interfaceStrings = ResumeLessonProgressModalInterfaceStringsDomainModel(
title: localizationServices.stringForLocaleElseEnglish(localeIdentifier: localeId, key: "lessons.resumeLessonModal.title"),
subtitle: localizationServices.stringForLocaleElseEnglish(localeIdentifier: localeId, key: "lessons.resumeLessonModal.subtitle"),
startOverButtonText: localizationServices.stringForLocaleElseEnglish(localeIdentifier: localeId, key: "lessons.resumeLessonModal.startOverButton"),
continueButtonText: localizationServices.stringForLocaleElseEnglish(localeIdentifier: localeId, key: "lessons.resumeLessonModal.continueButton")
)

return Just(interfaceStrings)
.eraseToAnyPublisher()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ class UserLessonProgressDataLayerDependencies {

// MARK: - Domain Interface

func getResumeLessonProgressModalInterfaceStringsRepositoryInterface() -> GetResumeLessonProgressModalInterfaceStringsRepositoryInterface {
return GetResumeLessonProgressModalInterfaceStringsRepository(
localizationServices: coreDataLayer.getLocalizationServices()
)
}

func getStoreUserLessonProgressRepositoryInterface() -> StoreUserLessonProgressRepositoryInterface {
return StoreUserLessonProgressRepository(
lessonProgressRepository: coreDataLayer.getUserLessonProgressRepository()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ class UserLessonProgressDomainLayerDependencies {
self.coreDataLayer = coreDataLayer
}

func getResumeLessonProgressModalInterfaceStringsUseCase() -> GetResumeLessonProgressModalInterfaceStringsUseCase {
return GetResumeLessonProgressModalInterfaceStringsUseCase(
getResumeLessonModalInterfaceStringsRepo: dataLayer.getResumeLessonProgressModalInterfaceStringsRepositoryInterface()
)
}

func getStoreUserLessonProgressUseCase() -> StoreUserLessonProgressUseCase {
return StoreUserLessonProgressUseCase(
storeLessonProgressRepository: dataLayer.getStoreUserLessonProgressRepositoryInterface()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// ResumeLessonProgressModalInterfaceStringsDomainModel.swift
// godtools
//
// Created by Rachael Skeath on 11/14/24.
// Copyright © 2024 Cru. All rights reserved.
//

import Foundation

struct ResumeLessonProgressModalInterfaceStringsDomainModel {
let title: String
let subtitle: String
let startOverButtonText: String
let continueButtonText: String

static func emptyStrings() -> ResumeLessonProgressModalInterfaceStringsDomainModel {
return ResumeLessonProgressModalInterfaceStringsDomainModel(title: "", subtitle: "", startOverButtonText: "", continueButtonText: "")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// GetResumeLessonProgressModalInterfaceStringsRepositoryInterface.swift
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @levieggertcru, how do you feel about the naming convention making some names super long? Was debating to take out the word "progress", but still gonna be pretty long either way 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @rachaelblue I know some names get super long. I know we suffix a lot of key names such as UseCase, DomainModel, RepositoryInterface, etc.

And some names get descriptive based on feature so there isn't collisions with other features. (If we could namespace that would help here).

I think we could start omitting Repository from the interface naming.

Maybe GetResumeLessonInterfaceStringsInterface or even GetResumeLessonStringsInterface. A tiny bit shorter.

// godtools
//
// Created by Rachael Skeath on 11/14/24.
// Copyright © 2024 Cru. All rights reserved.
//

import Foundation
import Combine

protocol GetResumeLessonProgressModalInterfaceStringsRepositoryInterface {

func getStringsPublisher(translateInLanguage: AppLanguageDomainModel) -> AnyPublisher<ResumeLessonProgressModalInterfaceStringsDomainModel, Never>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// GetResumeLessonProgressModalInterfaceStringsUseCase.swift
// godtools
//
// Created by Rachael Skeath on 11/14/24.
// Copyright © 2024 Cru. All rights reserved.
//

import Foundation
import Combine

class GetResumeLessonProgressModalInterfaceStringsUseCase {

private let getResumeLessonModalInterfaceStringsRepo: GetResumeLessonProgressModalInterfaceStringsRepositoryInterface

init(getResumeLessonModalInterfaceStringsRepo: GetResumeLessonProgressModalInterfaceStringsRepositoryInterface) {
self.getResumeLessonModalInterfaceStringsRepo = getResumeLessonModalInterfaceStringsRepo
}

func getStringsPublisher(appLanguage: AppLanguageDomainModel) -> AnyPublisher<ResumeLessonProgressModalInterfaceStringsDomainModel, Never> {

return getResumeLessonModalInterfaceStringsRepo
.getStringsPublisher(translateInLanguage: appLanguage)
.eraseToAnyPublisher()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// ResumeLessonProgressModal.swift
// godtools
//
// Created by Rachael Skeath on 10/29/24.
// Copyright © 2024 Cru. All rights reserved.
//

import SwiftUI

struct ResumeLessonProgressModal: View {

private let buttonHeight: CGFloat = 48
private let modalInset: CGFloat = 28
private let buttonInset: CGFloat = 20
private let buttonSpace: CGFloat = 12

@ObservedObject private var viewModel: ResumeLessonProgressModalViewModel

init(viewModel: ResumeLessonProgressModalViewModel) {
self.viewModel = viewModel
}

var body: some View {
GeometryReader { geometry in
let totalSpaceAroundModal = modalInset * 2
let modalWidth = geometry.size.width - totalSpaceAroundModal
let totalSpaceAroundButtons = (buttonInset * 2) + buttonSpace
let buttonWidth = (modalWidth - totalSpaceAroundButtons) / 2

ZStack {
Color.clear
.edgesIgnoringSafeArea(.all)
.background(.ultraThinMaterial)

VStack(spacing: 0) {
Text(viewModel.interfaceStringsDomainModel.title)
.font(FontLibrary.sfProTextRegular.font(size: 28))
.foregroundColor(ColorPalette.gtGrey.color)
.padding(.top, 30)
.padding(.bottom, 15)

Text(viewModel.interfaceStringsDomainModel.subtitle)
.font(FontLibrary.sfProTextRegular.font(size: 16))
.foregroundColor(ColorPalette.gtGrey.color)
.multilineTextAlignment(.center)
.padding(.horizontal, buttonInset + 20)
.padding(.bottom, 35)

HStack(spacing: buttonSpace) {
GTWhiteButton(title: viewModel.interfaceStringsDomainModel.startOverButtonText, fontSize: 15, width: buttonWidth, height: buttonHeight) {
viewModel.startOverButtonTapped()
}
GTBlueButton(title: viewModel.interfaceStringsDomainModel.continueButtonText, fontSize: 15, width: buttonWidth, height: buttonHeight) {
viewModel.continueButtonTapped()
}
}
.padding(.horizontal, buttonInset)
.padding(.bottom, 21)
}
.background(Color.white)
.cornerRadius(6)
.shadow(color: Color.black.opacity(0.25), radius: 3, y: 3)
.frame(width: modalWidth)
.overlay(
RoundedRectangle(cornerRadius: 6)
.strokeBorder(Color.clear, lineWidth: 2)
)
}
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// ResumeLessonProgressModalViewModel.swift
// godtools
//
// Created by Rachael Skeath on 11/14/24.
// Copyright © 2024 Cru. All rights reserved.
//

import Foundation
import Combine

class ResumeLessonProgressModalViewModel: ObservableObject {

private weak var flowDelegate: FlowDelegate?
private let getInterfaceStringsUseCase: GetResumeLessonProgressModalInterfaceStringsUseCase
private let getCurrentAppLanguageUseCase: GetCurrentAppLanguageUseCase

private var cancellables: Set<AnyCancellable> = Set()

@Published private var appLanguage: AppLanguageDomainModel = LanguageCodeDomainModel.english.rawValue

@Published var interfaceStringsDomainModel: ResumeLessonProgressModalInterfaceStringsDomainModel = ResumeLessonProgressModalInterfaceStringsDomainModel.emptyStrings()

init(flowDelegate: FlowDelegate, getInterfaceStringsUseCase: GetResumeLessonProgressModalInterfaceStringsUseCase, getCurrentAppLanguageUseCase: GetCurrentAppLanguageUseCase) {
self.flowDelegate = flowDelegate
self.getInterfaceStringsUseCase = getInterfaceStringsUseCase
self.getCurrentAppLanguageUseCase = getCurrentAppLanguageUseCase

getCurrentAppLanguageUseCase
.getLanguagePublisher()
.receive(on: DispatchQueue.main)
.assign(to: &$appLanguage)

$appLanguage
.dropFirst()
.map { appLanguage in
getInterfaceStringsUseCase.getStringsPublisher(appLanguage: appLanguage)
}
.switchToLatest()
.receive(on: DispatchQueue.main)
.sink { [weak self] interfaceStrings in

self?.interfaceStringsDomainModel = interfaceStrings
}
.store(in: &cancellables)
}

// MARK: - Inputs

func startOverButtonTapped() {
flowDelegate?.navigate(step: .startOverTappedFromResumeLessonModal)
}

func continueButtonTapped() {
flowDelegate?.navigate(step: .continueTappedFromResumeLessonModal)
}
}
18 changes: 11 additions & 7 deletions godtools/App/Flows/App/AppFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,8 @@ class AppFlow: NSObject, ToolNavigationFlow, Flow {
}

case .lessonTappedFromLessonsList(let lessonListItem, let languageFilter):

if let languageFilter = languageFilter {
navigateToTool(toolDataModelId: lessonListItem.dataModelId, languageIds: [languageFilter.languageId], selectedLanguageIndex: 0, trainingTipsEnabled: false)
} else {
navigateToToolInAppLanguage(toolDataModelId: lessonListItem.dataModelId, trainingTipsEnabled: false)
}

navigateToLesson(lessonListItem: lessonListItem, languageFilter: languageFilter)

case .lessonLanguageFilterTappedFromLessons:
navigationController.pushViewController(getLessonLanguageFilterSelection(), animated: true)

Expand Down Expand Up @@ -809,6 +804,15 @@ extension AppFlow {

navigateToTool(toolDataModelId: toolDataModelId, languageIds: languageIds, selectedLanguageIndex: selectedLanguageIndex, trainingTipsEnabled: trainingTipsEnabled, shouldPersistToolSettings: shouldPersistToolSettings)
}

private func navigateToLesson(lessonListItem: LessonListItemDomainModel, languageFilter: LessonFilterLanguageDomainModel?) {

if let languageFilter = languageFilter {
navigateToTool(toolDataModelId: lessonListItem.dataModelId, languageIds: [languageFilter.languageId], selectedLanguageIndex: 0, trainingTipsEnabled: false)
} else {
navigateToToolInAppLanguage(toolDataModelId: lessonListItem.dataModelId, trainingTipsEnabled: false)
}
}

private func navigateToTool(toolDataModelId: String, languageIds: [String], selectedLanguageIndex: Int?, trainingTipsEnabled: Bool, shouldPersistToolSettings: Bool = false) {

Expand Down
2 changes: 2 additions & 0 deletions godtools/App/Flows/Flow/FlowStep.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ enum FlowStep {
case backTappedFromLessonLanguageFilter

// lesson
case startOverTappedFromResumeLessonModal
case continueTappedFromResumeLessonModal
case closeTappedFromLesson(lessonId: String, highestPageNumberViewed: Int)
case lessonFlowCompleted(state: LessonFlowCompletedState)

Expand Down
Loading
Loading