diff --git a/Core/Core.xcodeproj/project.pbxproj b/Core/Core.xcodeproj/project.pbxproj index 3ba4ab39b..081a4c261 100644 --- a/Core/Core.xcodeproj/project.pbxproj +++ b/Core/Core.xcodeproj/project.pbxproj @@ -2466,7 +2466,7 @@ repositoryURL = "https://github.com/facebook/facebook-ios-sdk"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 16.3.1; + minimumVersion = 17.4.0; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/Core/Core/Domain/Model/CourseBlockModel.swift b/Core/Core/Domain/Model/CourseBlockModel.swift index c2525627b..731e47176 100644 --- a/Core/Core/Domain/Model/CourseBlockModel.swift +++ b/Core/Core/Domain/Model/CourseBlockModel.swift @@ -166,6 +166,7 @@ public struct CourseVertical: Identifiable, Hashable { public let type: BlockType public let completion: Double public var childs: [CourseBlock] + public var webUrl: String public var isDownloadable: Bool { return childs.first(where: { $0.isDownloadable }) != nil @@ -178,7 +179,8 @@ public struct CourseVertical: Identifiable, Hashable { displayName: String, type: BlockType, completion: Double, - childs: [CourseBlock] + childs: [CourseBlock], + webUrl: String ) { self.blockId = blockId self.id = id @@ -187,6 +189,7 @@ public struct CourseVertical: Identifiable, Hashable { self.type = type self.completion = completion self.childs = childs + self.webUrl = webUrl } } diff --git a/Course/Course.xcodeproj/project.pbxproj b/Course/Course.xcodeproj/project.pbxproj index 737558bc2..81830204f 100644 --- a/Course/Course.xcodeproj/project.pbxproj +++ b/Course/Course.xcodeproj/project.pbxproj @@ -27,7 +27,7 @@ 02454CA02A2618E70043052A /* YouTubeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02454C9F2A2618E70043052A /* YouTubeView.swift */; }; 02454CA22A26190A0043052A /* EncodedVideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02454CA12A26190A0043052A /* EncodedVideoView.swift */; }; 02454CA42A26193F0043052A /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02454CA32A26193F0043052A /* WebView.swift */; }; - 02454CA62A26196C0043052A /* UnknownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02454CA52A26196C0043052A /* UnknownView.swift */; }; + 02454CA62A26196C0043052A /* NotAvailableOnMobileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02454CA52A26196C0043052A /* NotAvailableOnMobileView.swift */; }; 02454CA82A2619890043052A /* DiscussionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02454CA72A2619890043052A /* DiscussionView.swift */; }; 02454CAA2A2619B40043052A /* LessonProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02454CA92A2619B40043052A /* LessonProgressView.swift */; }; 0248C92729C097EB00DC8402 /* CourseVerticalViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0248C92629C097EB00DC8402 /* CourseVerticalViewModel.swift */; }; @@ -134,7 +134,7 @@ 02454C9F2A2618E70043052A /* YouTubeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YouTubeView.swift; sourceTree = ""; }; 02454CA12A26190A0043052A /* EncodedVideoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncodedVideoView.swift; sourceTree = ""; }; 02454CA32A26193F0043052A /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = ""; }; - 02454CA52A26196C0043052A /* UnknownView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnknownView.swift; sourceTree = ""; }; + 02454CA52A26196C0043052A /* NotAvailableOnMobileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotAvailableOnMobileView.swift; sourceTree = ""; }; 02454CA72A2619890043052A /* DiscussionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscussionView.swift; sourceTree = ""; }; 02454CA92A2619B40043052A /* LessonProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LessonProgressView.swift; sourceTree = ""; }; 0248C92629C097EB00DC8402 /* CourseVerticalViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseVerticalViewModel.swift; sourceTree = ""; }; @@ -285,7 +285,7 @@ 02454C9F2A2618E70043052A /* YouTubeView.swift */, 02454CA12A26190A0043052A /* EncodedVideoView.swift */, 02454CA32A26193F0043052A /* WebView.swift */, - 02454CA52A26196C0043052A /* UnknownView.swift */, + 02454CA52A26196C0043052A /* NotAvailableOnMobileView.swift */, 02454CA72A2619890043052A /* DiscussionView.swift */, 02454CA92A2619B40043052A /* LessonProgressView.swift */, BAD9CA2C2B2736BB00DE790A /* LessonLineProgressView.swift */, @@ -951,7 +951,7 @@ BA58CF5D2B3D804D005B102E /* CourseStorage.swift in Sources */, 067B7B502BED339200D1768F /* PlayerControllerProtocol.swift in Sources */, 067B7B4E2BED339200D1768F /* PlayerTrackerProtocol.swift in Sources */, - 02454CA62A26196C0043052A /* UnknownView.swift in Sources */, + 02454CA62A26196C0043052A /* NotAvailableOnMobileView.swift in Sources */, 0766DFD0299AB29000EBEF6A /* PlayerViewController.swift in Sources */, 022C64DC29ACFDEE000F532B /* Data_HandoutsResponse.swift in Sources */, 022C64D829ACEC48000F532B /* HandoutsView.swift in Sources */, diff --git a/Course/Course/Data/CourseRepository.swift b/Course/Course/Data/CourseRepository.swift index 5da361928..09e86c588 100644 --- a/Course/Course/Data/CourseRepository.swift +++ b/Course/Course/Data/CourseRepository.swift @@ -202,7 +202,8 @@ public class CourseRepository: CourseRepositoryProtocol { displayName: sequential.displayName, type: BlockType(rawValue: sequential.type) ?? .unknown, completion: sequential.completion ?? 0, - childs: childs + childs: childs, + webUrl: sequential.webUrl ) } @@ -440,7 +441,8 @@ And there are various ways of describing it-- call it oral poetry or displayName: sequential.displayName, type: BlockType(rawValue: sequential.type) ?? .unknown, completion: sequential.completion ?? 0, - childs: childs + childs: childs, + webUrl: sequential.webUrl ) } diff --git a/Course/Course/Domain/CourseInteractor.swift b/Course/Course/Domain/CourseInteractor.swift index 42f6074f4..bcafab40d 100644 --- a/Course/Course/Domain/CourseInteractor.swift +++ b/Course/Course/Domain/CourseInteractor.swift @@ -170,7 +170,8 @@ public class CourseInteractor: CourseInteractorProtocol { displayName: vertical.displayName, type: vertical.type, completion: vertical.completion, - childs: newChilds + childs: newChilds, + webUrl: vertical.webUrl ) } diff --git a/Course/Course/Presentation/CourseRouter.swift b/Course/Course/Presentation/CourseRouter.swift index a9b33ef79..f3efe9cae 100644 --- a/Course/Course/Presentation/CourseRouter.swift +++ b/Course/Course/Presentation/CourseRouter.swift @@ -62,6 +62,8 @@ public protocol CourseRouter: BaseRouter { ) func showDatesAndCalendar() + + func showGatedContentError(url: String) } // Mark - For testing and SwiftUI preview @@ -122,5 +124,7 @@ public class CourseRouterMock: BaseRouterMock, CourseRouter { ) {} public func showDatesAndCalendar() {} + + public func showGatedContentError(url: String) {} } #endif diff --git a/Course/Course/Presentation/Outline/ContinueWithView.swift b/Course/Course/Presentation/Outline/ContinueWithView.swift index 0380e51d7..e8345bbb0 100644 --- a/Course/Course/Presentation/Outline/ContinueWithView.swift +++ b/Course/Course/Presentation/Outline/ContinueWithView.swift @@ -125,7 +125,8 @@ struct ContinueWithView_Previews: PreviewProvider { displayName: "Second Unit", type: .vertical, completion: 1, - childs: blocks + childs: blocks, + webUrl: "" ) ) { } } diff --git a/Course/Course/Presentation/Outline/CourseVertical/CourseVerticalView.swift b/Course/Course/Presentation/Outline/CourseVertical/CourseVerticalView.swift index 1614e075d..ff3306072 100644 --- a/Course/Course/Presentation/Outline/CourseVertical/CourseVerticalView.swift +++ b/Course/Course/Presentation/Outline/CourseVertical/CourseVerticalView.swift @@ -161,8 +161,10 @@ struct CourseVerticalView_Previews: PreviewProvider { displayName: "Vertical", type: .vertical, completion: 0, - childs: []) - ], + childs: [], + webUrl: "" + ) + ], sequentialProgress: SequentialProgress( assignmentType: "Advanced Assessment Tools", numPointsEarned: 1, diff --git a/Course/Course/Presentation/Subviews/CustomDisclosureGroup.swift b/Course/Course/Presentation/Subviews/CustomDisclosureGroup.swift index e783bdc07..f7ae7ea54 100644 --- a/Course/Course/Presentation/Subviews/CustomDisclosureGroup.swift +++ b/Course/Course/Presentation/Subviews/CustomDisclosureGroup.swift @@ -80,7 +80,10 @@ struct CustomDisclosureGroup: View { guard let chapterIndex = chapterIndex else { return } guard let sequentialIndex else { return } guard let courseVertical = sequential.childs.first else { return } - guard let block = courseVertical.childs.first else { return } + guard let block = courseVertical.childs.first else { + viewModel.router.showGatedContentError(url: courseVertical.webUrl) + return + } viewModel.trackSequentialClicked(sequential) if viewModel.config.uiComponents.courseDropDownNavigationEnabled { @@ -279,7 +282,8 @@ struct CustomDisclosureGroup_Previews: PreviewProvider { displayName: "Vertical 1", type: .vertical, completion: 0, - childs: [] + childs: [], + webUrl: "" ), CourseVertical( blockId: "1-1-2", @@ -288,7 +292,8 @@ struct CustomDisclosureGroup_Previews: PreviewProvider { displayName: "Vertical 2", type: .vertical, completion: 1.0, - childs: [] + childs: [], + webUrl: "" ) ], sequentialProgress: SequentialProgress( @@ -312,7 +317,8 @@ struct CustomDisclosureGroup_Previews: PreviewProvider { displayName: "Vertical 3", type: .vertical, completion: 1.0, - childs: [] + childs: [], + webUrl: "" ) ], sequentialProgress: SequentialProgress( @@ -344,7 +350,8 @@ struct CustomDisclosureGroup_Previews: PreviewProvider { displayName: "Vertical 4", type: .vertical, completion: 1.0, - childs: [] + childs: [], + webUrl: "" ), CourseVertical( blockId: "2-1-2", @@ -353,7 +360,8 @@ struct CustomDisclosureGroup_Previews: PreviewProvider { displayName: "Vertical 5", type: .vertical, completion: 1.0, - childs: [] + childs: [], + webUrl: "" ) ], sequentialProgress: SequentialProgress( diff --git a/Course/Course/Presentation/Unit/CourseUnitView.swift b/Course/Course/Presentation/Unit/CourseUnitView.swift index f2a50efe1..81736c6fe 100644 --- a/Course/Course/Presentation/Unit/CourseUnitView.swift +++ b/Course/Course/Presentation/Unit/CourseUnitView.swift @@ -256,10 +256,8 @@ public struct CourseUnitView: View { case .unknown(let url): if index >= viewModel.index - 1 && index <= viewModel.index + 1 { if viewModel.connectivity.isInternetAvaliable { - UnknownView(url: url, viewModel: viewModel) + NotAvailableOnMobileView(url: url) .frameLimit(width: reader.size.width) - Spacer() - .frame(minHeight: 100) } else { OfflineContentView( isDownloadable: false @@ -539,7 +537,8 @@ struct CourseUnitView_Previews: PreviewProvider { displayName: "6", type: .vertical, completion: 0, - childs: blocks + childs: blocks, + webUrl: "" ) ], sequentialProgress: SequentialProgress( @@ -572,7 +571,8 @@ struct CourseUnitView_Previews: PreviewProvider { displayName: "4", type: .vertical, completion: 0, - childs: blocks + childs: blocks, + webUrl: "" ) ], sequentialProgress: SequentialProgress( diff --git a/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitDropDownCell.swift b/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitDropDownCell.swift index a00a2de0d..5a280cbeb 100644 --- a/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitDropDownCell.swift +++ b/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitDropDownCell.swift @@ -87,7 +87,8 @@ struct CourseUnitDropDownCell_Previews: PreviewProvider { multiDevice: true, offlineDownload: nil ) - ] + ], + webUrl: "" ) CourseUnitDropDownCell( diff --git a/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitDropDownList.swift b/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitDropDownList.swift index 86459a13a..e449f77fc 100644 --- a/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitDropDownList.swift +++ b/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitDropDownList.swift @@ -119,7 +119,8 @@ struct CourseUnitDropDownList_Previews: PreviewProvider { displayName: "First Unit", type: .vertical, completion: 0, - childs: blocks + childs: blocks, + webUrl: "" ), CourseVertical( blockId: "2", @@ -128,7 +129,8 @@ struct CourseUnitDropDownList_Previews: PreviewProvider { displayName: "Second Unit", type: .vertical, completion: 1, - childs: blocks + childs: blocks, + webUrl: "" ), CourseVertical( blockId: "3", @@ -137,7 +139,8 @@ struct CourseUnitDropDownList_Previews: PreviewProvider { displayName: "Third Unit", type: .vertical, completion: 0, - childs: blocks + childs: blocks, + webUrl: "" ), CourseVertical( blockId: "4", @@ -146,7 +149,8 @@ struct CourseUnitDropDownList_Previews: PreviewProvider { displayName: "Fourth Unit", type: .vertical, completion: 1, - childs: blocks + childs: blocks, + webUrl: "" ) ] diff --git a/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitVerticalsDropdownView.swift b/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitVerticalsDropdownView.swift index e5f289ea4..89f410ed3 100644 --- a/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitVerticalsDropdownView.swift +++ b/Course/Course/Presentation/Unit/Subviews/DropdownList/CourseUnitVerticalsDropdownView.swift @@ -135,7 +135,8 @@ struct CourseUnitVerticalsDropdownView_Previews: PreviewProvider { displayName: "First Unit", type: .vertical, completion: 0, - childs: blocks + childs: blocks, + webUrl: "" ), CourseVertical( blockId: "2", @@ -144,7 +145,8 @@ struct CourseUnitVerticalsDropdownView_Previews: PreviewProvider { displayName: "Second Unit", type: .vertical, completion: 1, - childs: blocks + childs: blocks, + webUrl: "" ), CourseVertical( blockId: "3", @@ -153,7 +155,8 @@ struct CourseUnitVerticalsDropdownView_Previews: PreviewProvider { displayName: "Third Unit", type: .vertical, completion: 0, - childs: blocks + childs: blocks, + webUrl: "" ), CourseVertical( blockId: "4", @@ -162,7 +165,8 @@ struct CourseUnitVerticalsDropdownView_Previews: PreviewProvider { displayName: "Fourth Unit", type: .vertical, completion: 1, - childs: blocks + childs: blocks, + webUrl: "" ) ] diff --git a/Course/Course/Presentation/Unit/Subviews/NotAvailableOnMobileView.swift b/Course/Course/Presentation/Unit/Subviews/NotAvailableOnMobileView.swift new file mode 100644 index 000000000..49741df69 --- /dev/null +++ b/Course/Course/Presentation/Unit/Subviews/NotAvailableOnMobileView.swift @@ -0,0 +1,45 @@ +// +// NotAvailableOnMobileView.swift +// Course +// +// Created by  Stepanok Ivan on 30.05.2023. +// + +import SwiftUI +import Core +import Theme + +public struct NotAvailableOnMobileView: View { + let url: String + + public init(url: String) { + self.url = url + } + + public var body: some View { + ZStack(alignment: .center) { + VStack(spacing: 10) { + Spacer() + CoreAssets.notAvaliable.swiftUIImage + Text(CourseLocalization.NotAvaliable.title) + .font(Theme.Fonts.titleLarge) + .multilineTextAlignment(.center) + .padding(.top, 40) + Text(CourseLocalization.NotAvaliable.description) + .font(Theme.Fonts.bodyLarge) + .multilineTextAlignment(.center) + .padding(.top, 12) + StyledButton(CourseLocalization.NotAvaliable.button, action: { + if let url = URL(string: url), UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + } + }) + .frame(width: 215) + .padding(.top, 40) + Spacer() + } + .padding(24) + } + .navigationBarHidden(false) + } +} diff --git a/Course/Course/Presentation/Unit/Subviews/UnknownView.swift b/Course/Course/Presentation/Unit/Subviews/UnknownView.swift deleted file mode 100644 index d38104a23..000000000 --- a/Course/Course/Presentation/Unit/Subviews/UnknownView.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// UnknownView.swift -// Course -// -// Created by  Stepanok Ivan on 30.05.2023. -// - -import SwiftUI -import Core -import Theme - -struct UnknownView: View { - let url: String - let viewModel: CourseUnitViewModel - - var body: some View { - VStack(spacing: 0) { - Spacer() - CoreAssets.notAvaliable.swiftUIImage - Text(CourseLocalization.NotAvaliable.title) - .font(Theme.Fonts.titleLarge) - .multilineTextAlignment(.center) - .frame(maxWidth: .infinity) - .padding(.top, 40) - Text(CourseLocalization.NotAvaliable.description) - .font(Theme.Fonts.bodyLarge) - .multilineTextAlignment(.center) - .frame(maxWidth: .infinity) - .padding(.top, 12) - StyledButton(CourseLocalization.NotAvaliable.button, action: { - if let url = URL(string: url) { - UIApplication.shared.open(url) - } - }) - .frame(width: 215) - .padding(.top, 40) - Spacer() - } - .padding(24) - } -} diff --git a/Course/CourseTests/Presentation/Container/CourseContainerViewModelTests.swift b/Course/CourseTests/Presentation/Container/CourseContainerViewModelTests.swift index 09895748c..c87824041 100644 --- a/Course/CourseTests/Presentation/Container/CourseContainerViewModelTests.swift +++ b/Course/CourseTests/Presentation/Container/CourseContainerViewModelTests.swift @@ -67,7 +67,8 @@ final class CourseContainerViewModelTests: XCTestCase { displayName: "", type: .vertical, completion: 0, - childs: [block] + childs: [block], + webUrl: "" ) let sequential = CourseSequential( blockId: "", @@ -397,7 +398,8 @@ final class CourseContainerViewModelTests: XCTestCase { displayName: "", type: .vertical, completion: 0, - childs: [block] + childs: [block], + webUrl: "" ) let sequential = CourseSequential( @@ -543,7 +545,8 @@ final class CourseContainerViewModelTests: XCTestCase { displayName: "", type: .vertical, completion: 0, - childs: [block] + childs: [block], + webUrl: "" ) let sequential = CourseSequential( @@ -672,7 +675,8 @@ final class CourseContainerViewModelTests: XCTestCase { displayName: "", type: .vertical, completion: 0, - childs: [block] + childs: [block], + webUrl: "" ) let sequential = CourseSequential( @@ -802,7 +806,8 @@ final class CourseContainerViewModelTests: XCTestCase { displayName: "", type: .vertical, completion: 0, - childs: [block] + childs: [block], + webUrl: "" ) let sequential = CourseSequential( @@ -925,7 +930,8 @@ final class CourseContainerViewModelTests: XCTestCase { displayName: "", type: .vertical, completion: 0, - childs: [block] + childs: [block], + webUrl: "" ) let sequential = CourseSequential( @@ -1064,7 +1070,8 @@ final class CourseContainerViewModelTests: XCTestCase { displayName: "", type: .vertical, completion: 0, - childs: [block] + childs: [block], + webUrl: "" ) let sequential = CourseSequential( @@ -1225,7 +1232,8 @@ final class CourseContainerViewModelTests: XCTestCase { displayName: "", type: .vertical, completion: 0, - childs: [block, block2] + childs: [block, block2], + webUrl: "" ) let sequential = CourseSequential( diff --git a/Course/CourseTests/Presentation/Unit/CourseUnitViewModelTests.swift b/Course/CourseTests/Presentation/Unit/CourseUnitViewModelTests.swift index dd24288b6..8a43f206e 100644 --- a/Course/CourseTests/Presentation/Unit/CourseUnitViewModelTests.swift +++ b/Course/CourseTests/Presentation/Unit/CourseUnitViewModelTests.swift @@ -85,23 +85,27 @@ final class CourseUnitViewModelTests: XCTestCase { displayName: "0", type: .chapter, childs: [ - CourseSequential(blockId: "5", - id: "5", - displayName: "5", - type: .sequential, - completion: 0, - childs: [ - CourseVertical(blockId: "6", - id: "6", - courseId: "123", - displayName: "6", - type: .vertical, - completion: 0, - childs: blocks) - ], - sequentialProgress: nil, - due: Date() - ) + CourseSequential( + blockId: "5", + id: "5", + displayName: "5", + type: .sequential, + completion: 0, + childs: [ + CourseVertical( + blockId: "6", + id: "6", + courseId: "123", + displayName: "6", + type: .vertical, + completion: 0, + childs: blocks, + webUrl: "" + ) + ], + sequentialProgress: nil, + due: Date() + ) ]), CourseChapter( @@ -110,23 +114,27 @@ final class CourseUnitViewModelTests: XCTestCase { displayName: "2", type: .chapter, childs: [ - CourseSequential(blockId: "3", - id: "3", - displayName: "3", - type: .sequential, - completion: 0, - childs: [ - CourseVertical(blockId: "4", - id: "4", - courseId: "123", - displayName: "4", - type: .vertical, - completion: 0, - childs: blocks) - ], - sequentialProgress: nil, - due: Date() - ) + CourseSequential( + blockId: "3", + id: "3", + displayName: "3", + type: .sequential, + completion: 0, + childs: [ + CourseVertical( + blockId: "4", + id: "4", + courseId: "123", + displayName: "4", + type: .vertical, + completion: 0, + childs: blocks, + webUrl: "" + ) + ], + sequentialProgress: nil, + due: Date() + ) ]) ] diff --git a/OpenEdX/Router.swift b/OpenEdX/Router.swift index 0004ca0cf..4302385d6 100644 --- a/OpenEdX/Router.swift +++ b/OpenEdX/Router.swift @@ -544,6 +544,13 @@ public class Router: AuthorizationRouter, } } + public func showGatedContentError(url: String) { + let view = NotAvailableOnMobileView(url: url) + + let controller = UIHostingController(rootView: view) + navigationController.pushViewController(controller, animated: true) + } + private func openBlockInBrowser(blockURL: URL) { presentAlert( alertTitle: "",