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

Merged
merged 23 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
931d72c
show resume lesson modal
rachaelblue Oct 31, 2024
7b70dce
present resume lesson modal from lessonViewModel instead
rachaelblue Nov 7, 2024
757c417
add blurred background view
rachaelblue Nov 13, 2024
2a0091d
adjust modal spacing
rachaelblue Nov 13, 2024
7ca5933
add use case and view model to get interface strings
rachaelblue Nov 14, 2024
c631a10
center subtitle
rachaelblue Nov 15, 2024
66a9264
Merge branch 'develop' of https://github.com/CruGlobal/godtools-swift…
rachaelblue Nov 15, 2024
8649ed9
remove unused initialPageConfig param
rachaelblue Nov 15, 2024
d16ac6d
remove unused bool
rachaelblue Nov 15, 2024
7268346
clean up
rachaelblue Nov 15, 2024
582f5f9
Merge branch 'develop' of https://github.com/CruGlobal/godtools-swift…
rachaelblue Nov 19, 2024
2de0a4f
present modal from flow and remove closures
rachaelblue Nov 20, 2024
04ed3d3
change font size
rachaelblue Nov 20, 2024
46ac16a
present lesson view after appears
rachaelblue Nov 25, 2024
0b1dda9
actually commit changes
rachaelblue Nov 25, 2024
7f367ba
bump min version to iOS15
rachaelblue Nov 25, 2024
b7cec39
Update pod to minimum iOS 15
levieggertcru Nov 25, 2024
7d1c74b
Remove iOS 14 obsoleted files
levieggertcru Nov 25, 2024
8ef7cdb
Add method getLessonView
levieggertcru Nov 25, 2024
00f9ae7
Add computed properties
levieggertcru Nov 26, 2024
67d9948
Merge pull request #2357 from CruGlobal/GT-2465-create-extension-for-…
levieggertcru Dec 4, 2024
5ec0e70
Update tests target for iOS 15
levieggertcru Dec 4, 2024
f58b7b4
Set ui tests min deployment to ios 15
levieggertcru Dec 5, 2024
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
2 changes: 1 addition & 1 deletion Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ source 'https://cdn.cocoapods.org/'
source 'https://github.com/CruGlobal/cocoapods-specs.git'

# Uncomment this line to define a global platform for your project
platform :ios, '14.0'
platform :ios, '15.0'

# Specs finder:
# https://github.com/CocoaPods/Specs/find/master
Expand Down
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: 6001489c49a3af8a0ae8b169bf2604ccf3009666

PODFILE CHECKSUM: 1816453b60fe876696e3cc9b1da49602bb07e16b
PODFILE CHECKSUM: 62029dbaa542f28b266404816e2713f7474b6cb7

COCOAPODS: 1.15.2
162 changes: 89 additions & 73 deletions godtools.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ struct ToolDetailsSectionDescriptionTextView: View {

VStack(alignment: .center, spacing: 0) {

BackwardsCompatibleTextWithLinks(
geometry: geometry,
text: text,
textColor: textColor,
textFont: textFont,
fontSize: fontSize,
TextWithLinksView(
stringContainingUrls: text,
textColor: textColor.color,
font: textFont.font(size: fontSize),
lineSpacing: lineSpacing,
urlTappedClosure: { (url: URL) in
textAlignment: .leading,
handleUrlClosure: { (url: URL) in

viewModel.urlTapped(url: url)
}
Expand Down
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