diff --git a/firefox-ios/Client.xcodeproj/project.pbxproj b/firefox-ios/Client.xcodeproj/project.pbxproj index fb59fc275d6e..8bcbbc359fa7 100644 --- a/firefox-ios/Client.xcodeproj/project.pbxproj +++ b/firefox-ios/Client.xcodeproj/project.pbxproj @@ -32,7 +32,6 @@ 0AFF7F6D2C7C7BBA00265214 /* CertificatesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AFF7F6A2C7C7BB900265214 /* CertificatesViewController.swift */; }; 0B11AF022CB412D100AD51D5 /* Metrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B11AF002CB412D100AD51D5 /* Metrics.swift */; }; 0B11AF042CB4130F00AD51D5 /* Metrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B11AF032CB4130F00AD51D5 /* Metrics.swift */; }; - 0AFF7F6E2C7C7BBA00265214 /* CertificatesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AFF7F6B2C7C7BB900265214 /* CertificatesModel.swift */; }; 0B305E1B1E3A98A900BE0767 /* BookmarksTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B305E1A1E3A98A900BE0767 /* BookmarksTests.swift */; }; 0B3D670E1E09B90B00C1EFC7 /* AuthenticationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B3D670D1E09B90B00C1EFC7 /* AuthenticationTest.swift */; }; 0B3F8C5E2CA4471C00DB5367 /* EditBookmarkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B3F8C5D2CA4471C00DB5367 /* EditBookmarkViewModel.swift */; }; @@ -583,7 +582,11 @@ 60D71AEC26AAF45E00355588 /* UIColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60D71AEB26AAF45E00355588 /* UIColorExtension.swift */; }; 630FE1342C7FB42500D9D6B2 /* NativeErrorPageMockModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 630FE1302C7FB42500D9D6B2 /* NativeErrorPageMockModel.swift */; }; 630FE1352C7FB42500D9D6B2 /* NativeErrorPageViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 630FE1322C7FB42500D9D6B2 /* NativeErrorPageViewControllerTests.swift */; }; + 631A369F2CC0A4FE0044DFEB /* NativeErrorPageMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631A369E2CC0A4FE0044DFEB /* NativeErrorPageMiddleware.swift */; }; + 631A36A32CC0B2470044DFEB /* NativeErrorPageHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 631A36A22CC0B2470044DFEB /* NativeErrorPageHelper.swift */; }; 63306D3921103EAE00F25400 /* LegacySavedTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63306D3821103EAE00F25400 /* LegacySavedTab.swift */; }; + 63B213282CCA796D00A466DB /* NativeErrorPageAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B213272CCA796D00A466DB /* NativeErrorPageAction.swift */; }; + 63B2132A2CCA797400A466DB /* NativeErrorPageState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B213292CCA797400A466DB /* NativeErrorPageState.swift */; }; 63F7A9AA2C7529ED005846F5 /* NativeErrorPageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63F7A9A92C7529ED005846F5 /* NativeErrorPageModel.swift */; }; 63F7A9AC2C752BB0005846F5 /* NativeErrorPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63F7A9AB2C752BB0005846F5 /* NativeErrorPageViewController.swift */; }; 6669B5E2211418A200CA117B /* WebsiteDataSearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6669B5E1211418A200CA117B /* WebsiteDataSearchResultsViewController.swift */; }; @@ -2276,7 +2279,6 @@ 0AFF7F6A2C7C7BB900265214 /* CertificatesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CertificatesViewController.swift; sourceTree = ""; }; 0B11AF002CB412D100AD51D5 /* Metrics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Metrics.swift; sourceTree = ""; }; 0B11AF032CB4130F00AD51D5 /* Metrics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Metrics.swift; sourceTree = ""; }; - 0AFF7F6B2C7C7BB900265214 /* CertificatesModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CertificatesModel.swift; sourceTree = ""; }; 0B305E1A1E3A98A900BE0767 /* BookmarksTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksTests.swift; sourceTree = ""; }; 0B3D670D1E09B90B00C1EFC7 /* AuthenticationTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationTest.swift; sourceTree = ""; }; 0B3F8C5D2CA4471C00DB5367 /* EditBookmarkViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditBookmarkViewModel.swift; sourceTree = ""; }; @@ -6502,9 +6504,13 @@ 63094229AA6EC744599B77A4 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/ClearPrivateData.strings; sourceTree = ""; }; 630FE1302C7FB42500D9D6B2 /* NativeErrorPageMockModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeErrorPageMockModel.swift; sourceTree = ""; }; 630FE1322C7FB42500D9D6B2 /* NativeErrorPageViewControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeErrorPageViewControllerTests.swift; sourceTree = ""; }; + 631A369E2CC0A4FE0044DFEB /* NativeErrorPageMiddleware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeErrorPageMiddleware.swift; sourceTree = ""; }; + 631A36A22CC0B2470044DFEB /* NativeErrorPageHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeErrorPageHelper.swift; sourceTree = ""; }; 63306D3821103EAE00F25400 /* LegacySavedTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacySavedTab.swift; sourceTree = ""; }; 634148899F41CAA3BCF71E8B /* or */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = or; path = or.lproj/Localizable.strings; sourceTree = ""; }; 63B04BE882C41584580E0E59 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = "fa.lproj/Default Browser.strings"; sourceTree = ""; }; + 63B213272CCA796D00A466DB /* NativeErrorPageAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeErrorPageAction.swift; sourceTree = ""; }; + 63B213292CCA797400A466DB /* NativeErrorPageState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeErrorPageState.swift; sourceTree = ""; }; 63F7A9A92C7529ED005846F5 /* NativeErrorPageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeErrorPageModel.swift; sourceTree = ""; }; 63F7A9AB2C752BB0005846F5 /* NativeErrorPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeErrorPageViewController.swift; sourceTree = ""; }; 63FE433D87018CDDFCF592E3 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/ErrorPages.strings; sourceTree = ""; }; @@ -10527,6 +10533,10 @@ isa = PBXGroup; children = ( 63F7A9A92C7529ED005846F5 /* NativeErrorPageModel.swift */, + 63B213292CCA797400A466DB /* NativeErrorPageState.swift */, + 63B213272CCA796D00A466DB /* NativeErrorPageAction.swift */, + 631A369E2CC0A4FE0044DFEB /* NativeErrorPageMiddleware.swift */, + 631A36A22CC0B2470044DFEB /* NativeErrorPageHelper.swift */, 63F7A9AB2C752BB0005846F5 /* NativeErrorPageViewController.swift */, ); path = NativeErrorPage; @@ -15718,6 +15728,7 @@ DFACBF81277B916B003D5F41 /* ConfigurableGradientView.swift in Sources */, 7482205C1DBAB56300EEEA72 /* MailProviders.swift in Sources */, 8A93F87029D3A597004159D9 /* SceneCoordinator.swift in Sources */, + 631A36A32CC0B2470044DFEB /* NativeErrorPageHelper.swift in Sources */, C88E7A602A05551B0072E638 /* NimbusOnboardingFeatureLayerProtocol.swift in Sources */, 8CFD56882AAF057D003157A6 /* SwitchFakespotProduction.swift in Sources */, C40046FA1CF8E0B200B08303 /* BackForwardListAnimator.swift in Sources */, @@ -15765,6 +15776,7 @@ 2386E4E624F8358E0072EF17 /* HomepageMessageCard.swift in Sources */, 21618A8C2A438A0900A5189E /* ActiveScreenAction.swift in Sources */, E15DE7C2293A7AED00B32667 /* PhotonActionSheetLineSeparator.swift in Sources */, + 631A369F2CC0A4FE0044DFEB /* NativeErrorPageMiddleware.swift in Sources */, 8CE1E43A2B8C76C80026530B /* LoginListView.swift in Sources */, 8A832A9429DC99BA0025D5DD /* LaunchScreenViewController.swift in Sources */, 21E77E4E2AA8BA5200FABA10 /* TabTrayViewController.swift in Sources */, @@ -15844,6 +15856,7 @@ 0E77DF0F2CB8220000B80BA1 /* GeneratedPasswordStorage.swift in Sources */, 219A0FDB2ACCCFFC009A6D1A /* InactiveTabsSectionManager.swift in Sources */, B2981F8A2B71AD7A00132C1B /* AutofillAccessoryViewButtonItem.swift in Sources */, + 63B213282CCA796D00A466DB /* NativeErrorPageAction.swift in Sources */, 211F00AC27F4D918001D9189 /* HistoryPanel+Search.swift in Sources */, 8AF347E02CADD1C300624036 /* HomepageAction.swift in Sources */, 96EB6C3827D821B800A9D159 /* HistoryPanelViewModel.swift in Sources */, @@ -16197,6 +16210,7 @@ 8C4B0F5D2C076B12008B3E74 /* UpdatableAddressFields+Decodable.swift in Sources */, C8B0F5F6283B7CCE007AE65D /* PocketStory.swift in Sources */, C81AC6B626160091007800C5 /* LegacyTabTrayViewModel.swift in Sources */, + 63B2132A2CCA797400A466DB /* NativeErrorPageState.swift in Sources */, 8ADAE4222A33A113007BF926 /* SendAnonymousUsageDataSetting.swift in Sources */, E170CA542B72C07A0082EFC5 /* FakespotActionFooterView.swift in Sources */, C8EDDBF229DF1159003A4C07 /* URLScanner.swift in Sources */, diff --git a/firefox-ios/Client/Coordinators/Browser/BrowserCoordinator.swift b/firefox-ios/Client/Coordinators/Browser/BrowserCoordinator.swift index 290c1aa072a8..a0be0242d09d 100644 --- a/firefox-ios/Client/Coordinators/Browser/BrowserCoordinator.swift +++ b/firefox-ios/Client/Coordinators/Browser/BrowserCoordinator.swift @@ -793,9 +793,7 @@ class BrowserCoordinator: BaseCoordinator, func showNativeErrorPage(overlayManager: OverlayModeManager) { // TODO: FXIOS-9641 #21239 Integration with Redux - presenting view - let errorPageModel = ErrorPageModel(errorTitle: "", errorDecription: "", errorCode: "") - let errorpageController = NativeErrorPageViewController(model: errorPageModel, - windowUUID: windowUUID, + let errorpageController = NativeErrorPageViewController(windowUUID: windowUUID, overlayManager: overlayManager) guard browserViewController.embedContent(errorpageController) else { logger.log("Unable to embed private homepage", level: .debug, category: .coordinator) diff --git a/firefox-ios/Client/Frontend/Browser/BrowserViewController/Extensions/BrowserViewController+WebViewDelegates.swift b/firefox-ios/Client/Frontend/Browser/BrowserViewController/Extensions/BrowserViewController+WebViewDelegates.swift index 7b0c944b5249..4c1cd0173c5d 100644 --- a/firefox-ios/Client/Frontend/Browser/BrowserViewController/Extensions/BrowserViewController+WebViewDelegates.swift +++ b/firefox-ios/Client/Frontend/Browser/BrowserViewController/Extensions/BrowserViewController+WebViewDelegates.swift @@ -756,8 +756,24 @@ extension BrowserViewController: WKNavigationDelegate { return } - if let url = error.userInfo[NSURLErrorFailingURLErrorKey] as? URL { - ErrorPageHelper(certStore: profile.certStore).loadPage(error, forUrl: url, inWebView: webView) + if isNativeErrorPageEnabled { + guard var errorURLpath = URLComponents(string: "\(InternalURL.baseUrl)/\(ErrorPageHandler.path)" ) else { return } + errorURLpath.queryItems = [URLQueryItem( + name: InternalURL.Param.url.rawValue, + value: webView.url?.absoluteString + )] + guard let errorPageURL = errorURLpath.url else { return } + let action = NativeErrorPageAction(networkError: error, + windowUUID: windowUUID, + actionType: NativeErrorPageActionType.receivedError + ) + store.dispatch(action) + + webView.load(PrivilegedRequest(url: errorPageURL) as URLRequest) + } else { + if let url = error.userInfo[NSURLErrorFailingURLErrorKey] as? URL { + ErrorPageHelper(certStore: profile.certStore).loadPage(error, forUrl: url, inWebView: webView) + } } } diff --git a/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift b/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift index 073c50faacf9..93acb2a44c97 100644 --- a/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift +++ b/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift @@ -136,6 +136,11 @@ class BrowserViewController: UIViewController, var isToolbarNavigationHintEnabled: Bool { return featureFlags.isFeatureEnabled(.toolbarNavigationHint, checking: .buildOnly) } + + var isNativeErrorPageEnabled: Bool { + return featureFlags.isFeatureEnabled(.nativeErrorPage, checking: .buildOnly) + } + private var browserViewControllerState: BrowserViewControllerState? // Header stack view can contain the top url bar, top reader mode, top ZoomPageBar @@ -1467,10 +1472,6 @@ class BrowserViewController: UIViewController, // MARK: - Native Error Page - private func isNativeErrorPage() -> Bool { - featureFlags.isFeatureEnabled(.nativeErrorPage, checking: .buildOnly) - } - func showEmbeddedNativeErrorPage() { // TODO: FXIOS-9641 #21239 Implement Redux for Native Error Pages browserDelegate?.showNativeErrorPage(overlayManager: overlayManager) @@ -1518,7 +1519,7 @@ class BrowserViewController: UIViewController, if isAboutHomeURL { showEmbeddedHomepage(inline: true, isPrivate: tabManager.selectedTab?.isPrivate ?? false) - } else if isErrorURL && isNativeErrorPage() { + } else if isErrorURL && isNativeErrorPageEnabled { showEmbeddedNativeErrorPage() } else { showEmbeddedWebview() diff --git a/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageAction.swift b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageAction.swift new file mode 100644 index 000000000000..93d9071ac26c --- /dev/null +++ b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageAction.swift @@ -0,0 +1,29 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Redux +import Common + +final class NativeErrorPageAction: Action { + let networkError: NSError? + let nativePageErrorModel: ErrorPageModel? + init( + networkError: NSError? = nil, + nativePageErrorModel: ErrorPageModel? = nil, + windowUUID: WindowUUID, + actionType: any ActionType + ) { + self.networkError = networkError + self.nativePageErrorModel = nativePageErrorModel + super.init(windowUUID: windowUUID, actionType: actionType) + } +} + +enum NativeErrorPageActionType: ActionType { + case receivedError +} + +enum NativeErrorPageMiddlewareActionType: ActionType { + case initialize +} diff --git a/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageHelper.swift b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageHelper.swift new file mode 100644 index 000000000000..cebe1448146f --- /dev/null +++ b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageHelper.swift @@ -0,0 +1,41 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Common +import Foundation +import WebKit +import GCDWebServers +import Shared +import Storage + +class NativeErrorPageHelper { + enum NetworkErrorType { + case noInternetConnection + } + + var error: NSError + + var errorDescriptionItem: String { + return error.localizedDescription + } + + init(error: NSError) { + self.error = error + } + + func parseErrorDetails() -> ErrorPageModel { + var title = "" + var description = "" + switch error.code { + case Int(CFNetworkErrors.cfurlErrorNotConnectedToInternet.rawValue): + title = .NativeErrorPage.NoInternetConnection.TitleLabel + description = .NativeErrorPage.NoInternetConnection.Description + default: + break + } + + let model = ErrorPageModel(errorTitle: title, errorDescription: description) + return model + } +} diff --git a/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageMiddleware.swift b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageMiddleware.swift new file mode 100644 index 000000000000..b095b5a7a07a --- /dev/null +++ b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageMiddleware.swift @@ -0,0 +1,32 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Foundation +import Redux +import Shared +import Common + +final class NativeErrorPageMiddleware { + lazy var nativeErrorPageProvider: Middleware = { state, action in + let windowUUID = action.windowUUID + print(action.actionType) + switch action.actionType { + case NativeErrorPageActionType.receivedError: + guard let action = action as? NativeErrorPageAction, let error = action.networkError else {return} + self.initializeNativeErrorPage(windowUUID: windowUUID, error: error) + break + default: + break + } + } + + private func initializeNativeErrorPage(windowUUID: WindowUUID, error: NSError) { + let model = NativeErrorPageHelper(error: error).parseErrorDetails() + let newAction = NativeErrorPageAction(nativePageErrorModel: model, + windowUUID: windowUUID, + actionType: NativeErrorPageMiddlewareActionType.initialize + ) + store.dispatch(newAction) + } +} diff --git a/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageModel.swift b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageModel.swift index 060eb6c87cb6..ef830cb60f24 100644 --- a/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageModel.swift +++ b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageModel.swift @@ -4,8 +4,7 @@ import Foundation -struct ErrorPageModel { +struct ErrorPageModel: Equatable { let errorTitle: String - let errorDecription: String - let errorCode: String + let errorDescription: String } diff --git a/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageState.swift b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageState.swift new file mode 100644 index 000000000000..b8885f169c6c --- /dev/null +++ b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageState.swift @@ -0,0 +1,70 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Redux +import Shared +import Common + +struct NativeErrorPageState: ScreenState, Equatable { + var windowUUID: WindowUUID + var title: String? + var description: String? + + init(appState: AppState, uuid: WindowUUID) { + guard let nativeErrorPageState = store.state.screenState( + NativeErrorPageState.self, + for: .nativeErrorPage, + window: uuid + ) else { + self.init(windowUUID: uuid) + return + } + + self.init( + windowUUID: nativeErrorPageState.windowUUID, + title: nativeErrorPageState.title, + description: nativeErrorPageState.description + ) + } + + init( + windowUUID: WindowUUID, + title: String? = nil, + description: String? = nil + ) { + self.windowUUID = windowUUID + self.title = title + self.description = description + } + + static let reducer: Reducer = { state, action in + print(action.actionType) + guard action.windowUUID == .unavailable || action.windowUUID == state.windowUUID else { return NativeErrorPageState( + windowUUID: state.windowUUID, + title: state.title, + description: state.description + )} + switch action.actionType { + case NativeErrorPageMiddlewareActionType.initialize: + guard let action = action as? NativeErrorPageAction, let model = action.nativePageErrorModel else { + return NativeErrorPageState( + windowUUID: state.windowUUID, + title: state.title, + description: state.description + ) + } + return NativeErrorPageState( + windowUUID: state.windowUUID, + title: model.errorTitle, + description: model.errorDescription + ) + default: + return NativeErrorPageState( + windowUUID: state.windowUUID, + title: state.title, + description: state.description + ) + } + } +} diff --git a/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageViewController.swift b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageViewController.swift index dbb015a703f4..c0c322dfce8f 100644 --- a/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageViewController.swift +++ b/firefox-ios/Client/Frontend/NativeErrorPage/NativeErrorPageViewController.swift @@ -10,8 +10,9 @@ import Shared final class NativeErrorPageViewController: UIViewController, Themeable, - ContentContainable { - private let model: ErrorPageModel + ContentContainable, + StoreSubscriber { + typealias SubscriberStateType = NativeErrorPageState private let windowUUID: WindowUUID // MARK: Themable Variables @@ -24,6 +25,7 @@ final class NativeErrorPageViewController: UIViewController, private var overlayManager: OverlayModeManager var contentType: ContentType = .nativeErrorPage + private var nativeErrorPageState: NativeErrorPageState // MARK: UI Elements private struct UX { @@ -72,14 +74,12 @@ final class NativeErrorPageViewController: UIViewController, label.adjustsFontForContentSizeCategory = true label.font = FXFontStyles.Bold.title2.scaledFont() label.numberOfLines = 0 - label.text = .NativeErrorPage.NoInternetConnection.TitleLabel } private lazy var errorDescriptionLabel: UILabel = .build { label in label.adjustsFontForContentSizeCategory = true label.font = FXFontStyles.Regular.body.scaledFont() label.numberOfLines = 0 - label.text = .NativeErrorPage.NoInternetConnection.Description } private lazy var reloadButton: PrimaryRoundedButton = .build { button in @@ -89,37 +89,67 @@ final class NativeErrorPageViewController: UIViewController, private var contraintsList = [NSLayoutConstraint]() - required init?( - coder aDecoder: NSCoder - ) { - fatalError( - "init(coder:) has not been implemented" - ) - } - init( - model: ErrorPageModel, windowUUID: WindowUUID, themeManager: ThemeManager = AppContainer.shared.resolve(), overlayManager: OverlayModeManager, notificationCenter: NotificationProtocol = NotificationCenter.default ) { - self.model = model self.windowUUID = windowUUID self.themeManager = themeManager self.overlayManager = overlayManager self.notificationCenter = notificationCenter + nativeErrorPageState = NativeErrorPageState(windowUUID: windowUUID) + super.init( nibName: nil, bundle: nil ) + subscribeToRedux() configureUI() setupLayout() adjustConstraints() showViewForCurrentOrientation() } + // MARK: Redux + func newState(state: NativeErrorPageState) { +// if state.title != nil { + nativeErrorPageState = state + titleLabel.text = state.title + errorDescriptionLabel.text = state.description +// } + } + + func subscribeToRedux() { + let action = ScreenAction(windowUUID: windowUUID, + actionType: ScreenActionType.showScreen, + screen: .nativeErrorPage) + store.dispatch(action) + let uuid = windowUUID + store.subscribe(self, transform: { + return $0.select({ appState in + return NativeErrorPageState(appState: appState, uuid: uuid) + }) + }) + } + + func unsubscribeFromRedux() { + let action = ScreenAction(windowUUID: windowUUID, + actionType: ScreenActionType.closeScreen, + screen: .nativeErrorPage) + store.dispatch(action) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + unsubscribeFromRedux() + } + override func viewDidLoad() { super.viewDidLoad() listenForThemeChange(view) diff --git a/firefox-ios/Client/Redux/GlobalState/ActiveScreenAction.swift b/firefox-ios/Client/Redux/GlobalState/ActiveScreenAction.swift index 58af1862ce86..1f843d5b55a6 100644 --- a/firefox-ios/Client/Redux/GlobalState/ActiveScreenAction.swift +++ b/firefox-ios/Client/Redux/GlobalState/ActiveScreenAction.swift @@ -33,6 +33,7 @@ enum AppScreen { case trackingProtection case toolbar case passwordGenerator + case nativeErrorPage } enum ScreenActionType: ActionType { diff --git a/firefox-ios/Client/Redux/GlobalState/ActiveScreenState.swift b/firefox-ios/Client/Redux/GlobalState/ActiveScreenState.swift index 54f6b19ec416..1c461d9a1278 100644 --- a/firefox-ios/Client/Redux/GlobalState/ActiveScreenState.swift +++ b/firefox-ios/Client/Redux/GlobalState/ActiveScreenState.swift @@ -22,6 +22,7 @@ enum AppScreenState: Equatable { case trackingProtection(TrackingProtectionState) case toolbar(ToolbarState) case passwordGenerator(PasswordGeneratorState) + case nativeErrorPage(NativeErrorPageState) static let reducer: Reducer = { state, action in switch state { @@ -53,6 +54,8 @@ enum AppScreenState: Equatable { return .toolbar(ToolbarState.reducer(state, action)) case .passwordGenerator(let state): return .passwordGenerator(PasswordGeneratorState.reducer(state, action)) + case .nativeErrorPage(let state): + return .nativeErrorPage(NativeErrorPageState.reducer(state, action)) } } @@ -73,6 +76,7 @@ enum AppScreenState: Equatable { case .trackingProtection: return .trackingProtection case .toolbar: return .toolbar case .passwordGenerator: return .passwordGenerator + case .nativeErrorPage: return .nativeErrorPage } } @@ -92,6 +96,7 @@ enum AppScreenState: Equatable { case .trackingProtection(let state): return state.windowUUID case .toolbar(let state): return state.windowUUID case .passwordGenerator(let state): return state.windowUUID + case .nativeErrorPage(let state): return state.windowUUID } } } @@ -158,6 +163,8 @@ struct ActiveScreensState: Equatable { screens.append(.toolbar(ToolbarState(windowUUID: uuid))) case .passwordGenerator: screens.append(.passwordGenerator(PasswordGeneratorState(windowUUID: uuid))) + case .nativeErrorPage: + screens.append(.nativeErrorPage(NativeErrorPageState(windowUUID: uuid))) } default: return screens diff --git a/firefox-ios/Client/Redux/GlobalState/AppState.swift b/firefox-ios/Client/Redux/GlobalState/AppState.swift index 099f77ea9fa9..e10a5288fc95 100644 --- a/firefox-ios/Client/Redux/GlobalState/AppState.swift +++ b/firefox-ios/Client/Redux/GlobalState/AppState.swift @@ -32,6 +32,7 @@ struct AppState: StateType { case (.toolbar(let state), .toolbar): return state as? S case (.trackingProtection(let state), .trackingProtection): return state as? S case (.passwordGenerator(let state), .passwordGenerator): return state as? S + case (.nativeErrorPage(let state), .nativeErrorPage): return state as? S default: return nil } }.first(where: { @@ -65,7 +66,8 @@ let middlewares = [ ToolbarMiddleware().toolbarProvider, TrackingProtectionMiddleware().trackingProtectionProvider, PasswordGeneratorMiddleware().passwordGeneratorProvider, - PocketMiddleware().pocketSectionProvider + PocketMiddleware().pocketSectionProvider, + NativeErrorPageMiddleware().nativeErrorPageProvider ] // In order for us to mock and test the middlewares easier,