Skip to content

Commit

Permalink
Refactor FXIOS-6937 [v121] Create the state model for the private tab…
Browse files Browse the repository at this point in the history
…s view controller (#17211)
  • Loading branch information
yoanarios authored Nov 8, 2023
1 parent 9772cac commit 153a861
Show file tree
Hide file tree
Showing 13 changed files with 141 additions and 22 deletions.
18 changes: 15 additions & 3 deletions Client.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
2178A6A4291455F7002EC290 /* ReaderModeFontSizeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2178A6A3291455F7002EC290 /* ReaderModeFontSizeButton.swift */; };
217AEF76284666D4004EED37 /* IntroViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 217AEF75284666D4004EED37 /* IntroViewModelTests.swift */; };
2197DF8A287624BF00215624 /* LibraryViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2197DF89287624BF00215624 /* LibraryViewModelTests.swift */; };
219914052AF963F900153598 /* TabTrayAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 219914042AF963F900153598 /* TabTrayAction.swift */; };
21996BAB2AE95AFC00E0D55F /* TabTrayPanelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21996BAA2AE95AFC00E0D55F /* TabTrayPanelType.swift */; };
219A0FD52ACC8506009A6D1A /* InactiveTabsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 219A0FD42ACC8506009A6D1A /* InactiveTabsCell.swift */; };
219A0FD72ACC8C03009A6D1A /* InactiveTabsHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 219A0FD62ACC8C03009A6D1A /* InactiveTabsHeaderView.swift */; };
Expand Down Expand Up @@ -2207,6 +2208,7 @@
217AEF75284666D4004EED37 /* IntroViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntroViewModelTests.swift; sourceTree = "<group>"; };
2194437EA9B44A00EDC037FA /* gu-IN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "gu-IN"; path = "gu-IN.lproj/FindInPage.strings"; sourceTree = "<group>"; };
2197DF89287624BF00215624 /* LibraryViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryViewModelTests.swift; sourceTree = "<group>"; };
219914042AF963F900153598 /* TabTrayAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabTrayAction.swift; sourceTree = "<group>"; };
21996BAA2AE95AFC00E0D55F /* TabTrayPanelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabTrayPanelType.swift; sourceTree = "<group>"; };
219A0FD42ACC8506009A6D1A /* InactiveTabsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InactiveTabsCell.swift; sourceTree = "<group>"; };
219A0FD62ACC8C03009A6D1A /* InactiveTabsHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InactiveTabsHeaderView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -7366,6 +7368,7 @@
212429F22AA27204002D57A8 /* Legacy */ = {
isa = PBXGroup;
children = (
2FDE87FD1ABB3817005317B1 /* LegacyRemoteTabsPanel.swift */,
216E9A3829D2119300ABE69B /* LegacyInactiveTabs */,
D301AAED1A3A55B70078DD1D /* LegacyGridTabViewController.swift */,
43BDBBFD2752FA8600254DE4 /* LegacyTabCell.swift */,
Expand All @@ -7380,13 +7383,10 @@
21357F2B293FDB07004BF9FD /* RemoteTabs */ = {
isa = PBXGroup;
children = (
2FDE87FD1ABB3817005317B1 /* LegacyRemoteTabsPanel.swift */,
1DEBC55D2AC4ED70006E4801 /* RemoteTabsPanel.swift */,
1D2F68AE2ACB272500524B92 /* RemoteTabsTableViewController.swift */,
1D2F68AA2ACB262900524B92 /* RemoteTabsPanelAction.swift */,
1D8487B32AD0C6C100F7527C /* RemoteTabsPanelMiddleware.swift */,
210887CB293E8800000AB4EE /* RemoteTabsErrorCell.swift */,
1D2F68B02ACCA22000524B92 /* RemoteTabsEmptyView.swift */,
21357F2C293FDB60004BF9FD /* RemoteTabsErrorDataSource.swift */,
21357F2E294237D8004BF9FD /* RemoteTabsClientAndTabsDataSource.swift */,
);
Expand Down Expand Up @@ -7474,6 +7474,14 @@
path = Resources;
sourceTree = "<group>";
};
219914032AF963E000153598 /* Action */ = {
isa = PBXGroup;
children = (
219914042AF963F900153598 /* TabTrayAction.swift */,
);
path = Action;
sourceTree = "<group>";
};
219A0FD32ACC84C5009A6D1A /* InactiveTabs */ = {
isa = PBXGroup;
children = (
Expand All @@ -7496,6 +7504,8 @@
21C5B3582AF2A7130093F366 /* Views */ = {
isa = PBXGroup;
children = (
210887CB293E8800000AB4EE /* RemoteTabsErrorCell.swift */,
1D2F68B02ACCA22000524B92 /* RemoteTabsEmptyView.swift */,
214EF4142AC5D5D0005BCCDA /* TabDisplayView.swift */,
1DDE3DB22AC34E1E0039363B /* TabCell.swift */,
43162A2E2492DB7800F91658 /* EmptyPrivateTabsView.swift */,
Expand Down Expand Up @@ -7562,6 +7572,7 @@
212429F22AA27204002D57A8 /* Legacy */,
21357F2B293FDB07004BF9FD /* RemoteTabs */,
21C5B3572AF2A6D80093F366 /* LayoutManager */,
219914032AF963E000153598 /* Action */,
21C5B3592AF2A73F0093F366 /* State */,
21C5B3582AF2A7130093F366 /* Views */,
213BF7522AC21D1B00C53A64 /* TabDisplayViewController.swift */,
Expand Down Expand Up @@ -12651,6 +12662,7 @@
EB1C84BF212EFFBF001489DF /* BrowserViewController+ReaderMode.swift in Sources */,
96D95016270238500079D39D /* Throttler.swift in Sources */,
8A93080B27C01AD60052167D /* SingleActionViewModel.swift in Sources */,
219914052AF963F900153598 /* TabTrayAction.swift in Sources */,
5AA0CC662A4B8F6100014E2A /* PasswordManagerCoordinator.swift in Sources */,
8A7368AD27924AAF005D7704 /* CanRemoveQuickActionBookmark.swift in Sources */,
8A0621B829428FBD005D1EFD /* OpenTabNotificationObject.swift in Sources */,
Expand Down
18 changes: 18 additions & 0 deletions Client/Frontend/Browser/Tabs/Action/TabTrayAction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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 Redux

enum TabTrayAction: Action {
case togglePrivateMode(Bool)
case openExistingTab
case addNewTab(Bool) // isPrivate
case closeTab
case closeAllTabs
case closeInactiveTab

// Private tabs action
case learnMorePrivateMode
}
2 changes: 1 addition & 1 deletion Client/Frontend/Browser/Tabs/State/TabCellState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import Foundation

/// WIP. Defines tab-specific state that is reflected in the new TabCell.
struct TabCellState {
struct TabCellState: Equatable {
let isSelected: Bool
let isPrivate: Bool
let isFxHomeTab: Bool
Expand Down
58 changes: 47 additions & 11 deletions Client/Frontend/Browser/Tabs/State/TabTrayState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,69 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/

import Foundation
import Redux

enum TabTrayLayoutType: Equatable {
case regular // iPad
case compact // iPhone
}

struct TabTrayState {
struct TabTrayState: ScreenState, Equatable {
var isPrivateMode: Bool
var selectedPanel: TabTrayPanelType?
var tabViewState: TabViewState
var remoteTabsState: RemoteTabsPanelState?
var selectedPanel: TabTrayPanelType?

var layout: TabTrayLayoutType = .compact
// TODO: FXIOS-7359 Move logic to show "\u{221E}" over 100 tabs to reducer
var normalTabsCount: String
var navigationTitle: String
var navigationTitle: String? {
return selectedPanel?.navTitle
}

var isSyncTabsPanel: Bool {
return selectedPanel == .syncedTabs
}

// For test and mock purposes will be deleted once Redux is integrated
static func getMockState(isPrivateMode: Bool) -> TabTrayState {
let tabViewState = TabViewState.getMockState(isPrivateMode: isPrivateMode)
return TabTrayState(isPrivateMode: isPrivateMode,
tabViewState: tabViewState,
remoteTabsState: nil,
normalTabsCount: "2",
navigationTitle: "")
init(_ appState: AppState) {
guard let panelState = store.state.screenState(TabTrayState.self, for: .tabsPanel) else {
self.init()
return
}

self.init(isPrivateMode: panelState.isPrivateMode,
tabViewState: panelState.tabViewState,
remoteTabsState: panelState.remoteTabsState,
normalTabsCount: panelState.normalTabsCount)
}

init() {
let tabViewState = TabViewState.getMockState(isPrivateMode: false)
self.init(isPrivateMode: false,
tabViewState: tabViewState,
remoteTabsState: nil,
normalTabsCount: "2")
}

init(isPrivateMode: Bool,
tabViewState: TabViewState,
remoteTabsState: RemoteTabsPanelState?,
normalTabsCount: String) {
self.isPrivateMode = isPrivateMode
self.tabViewState = tabViewState
self.remoteTabsState = remoteTabsState
self.normalTabsCount = normalTabsCount
}

static let reducer: Reducer<Self> = { state, action in
// TODO: Complete in FXIOS-7359
return state
}

static func == (lhs: TabTrayState, rhs: TabTrayState) -> Bool {
return lhs.isPrivateMode == rhs.isPrivateMode
&& lhs.selectedPanel == rhs.selectedPanel
&& lhs.layout == rhs.layout
&& lhs.tabViewState == rhs.tabViewState
}
}
5 changes: 3 additions & 2 deletions Client/Frontend/Browser/Tabs/State/TabViewState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import Foundation

struct TabViewState {
struct TabViewState: Equatable {
var isPrivateMode: Bool
var tabs: [TabCellState]

Expand All @@ -13,7 +13,8 @@ struct TabViewState {
var isInactiveTabsExpanded = true

var isPrivateTabsEmpty: Bool {
return isPrivateMode && tabs.isEmpty
guard isPrivateMode else { return false }
return tabs.isEmpty
}

// For test and mock purposes will be deleted once Redux is integrated
Expand Down
6 changes: 3 additions & 3 deletions Client/Frontend/Browser/Tabs/TabTrayViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ class TabTrayViewController: UIViewController,
init(delegate: TabTrayViewControllerDelegate,
themeManager: ThemeManager = AppContainer.shared.resolve(),
and notificationCenter: NotificationProtocol = NotificationCenter.default) {
self.state = TabTrayState.getMockState(isPrivateMode: false)
self.state = TabTrayState()
self.delegate = delegate
self.themeManager = themeManager
self.notificationCenter = notificationCenter
Expand Down Expand Up @@ -283,9 +283,9 @@ class TabTrayViewController: UIViewController,
}

private func updateTitle() {
guard let panel = state.selectedPanel else { return }
guard let navigationTitle = state.navigationTitle else { return }

navigationItem.title = panel.navTitle
navigationItem.title = navigationTitle
}

private func setupForiPad() {
Expand Down
2 changes: 2 additions & 0 deletions Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ class TabDisplayView: UIView,

// MARK: UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
guard !state.isPrivateTabsEmpty else { return 0 }

guard !shouldHideInactiveTabs else { return 1 }

return TabDisplaySection.allCases.count
Expand Down
1 change: 1 addition & 0 deletions Client/Redux/GlobalState/ActiveScreenAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Redux

enum AppScreen {
case themeSettings
case tabsPanel
case remoteTabsPanel
}

Expand Down
6 changes: 6 additions & 0 deletions Client/Redux/GlobalState/ActiveScreenState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import Redux

enum AppScreenState: Equatable {
case themeSettings(ThemeSettingsState)
case tabsPanel(TabTrayState)
case remoteTabsPanel(RemoteTabsPanelState)

static let reducer: Reducer<Self> = { state, action in
switch state {
case .themeSettings(let state): return .themeSettings(ThemeSettingsState.reducer(state, action))
case .tabsPanel(let state): return
.tabsPanel(TabTrayState.reducer(state, action))
case .remoteTabsPanel(let state): return .remoteTabsPanel(RemoteTabsPanelState.reducer(state, action))
}
}
Expand All @@ -21,6 +24,7 @@ enum AppScreenState: Equatable {
switch self {
case .themeSettings: return .themeSettings
case .remoteTabsPanel: return .remoteTabsPanel
case .tabsPanel: return .tabsPanel
}
}
}
Expand All @@ -45,6 +49,8 @@ struct ActiveScreensState: Equatable {
screens = screens.filter({ return $0.associatedAppScreen != screenType })
case .showScreen(.themeSettings):
screens += [.themeSettings(ThemeSettingsState())]
case .showScreen(.tabsPanel):
screens += [.tabsPanel(TabTrayState())]
case .showScreen(.remoteTabsPanel):
screens += [.remoteTabsPanel(RemoteTabsPanelState())]
}
Expand Down
47 changes: 45 additions & 2 deletions Tests/ClientTests/TabTray/TabDisplayViewTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,49 @@ final class TabDisplayViewTests: XCTestCase {
DependencyHelperMock().reset()
}

func testAmountOfSections_ForRegularTabsWithInactiveTabs() {
func testNumberOfSections_ForRegularTabsWithInactiveTabs() {
let subject = createSubject(isPrivateMode: false,
emptyTabs: false,
emptyInactiveTabs: false)

XCTAssertEqual(subject.collectionView.numberOfSections, 2)
}

func testAmountOfSections_ForRegularTabsWithoutInactiveTabs() {
func testNumberOfSections_ForRegularTabsWithoutInactiveTabs() {
let subject = createSubject(isPrivateMode: false,
emptyTabs: false,
emptyInactiveTabs: true)

XCTAssertEqual(subject.collectionView.numberOfSections, 1)
}

func testNumberOfSections_PrivateTabsAndInactiveTabs() {
let subject = createSubject(isPrivateMode: true,
emptyTabs: false,
emptyInactiveTabs: false)

let numberOfSections = subject.collectionView.numberOfSections
XCTAssertEqual(numberOfSections, 1)
}

func testNumberOfSections_PrivateTabsWithoutInactiveTabs() {
let subject = createSubject(isPrivateMode: true,
emptyTabs: false,
emptyInactiveTabs: true)

let numberOfSections = subject.collectionView.numberOfSections
XCTAssertEqual(numberOfSections, 1)
}

func testNumberOfSections_PrivateTabsWithEmptyTabs() {
let subject = createSubject(isPrivateMode: true,
emptyTabs: true,
emptyInactiveTabs: true)

let numberOfSections = subject.collectionView.numberOfSections
XCTAssertEqual(numberOfSections, 0)
}

func testAmountOfSections_ForPrivateTabsWithoutInactiveTabs() {
let subject = createSubject(isPrivateMode: true,
emptyTabs: false,
Expand Down Expand Up @@ -65,6 +92,22 @@ final class TabDisplayViewTests: XCTestCase {
XCTAssertFalse(subject.state.isInactiveTabsExpanded)
}

func testIsPrivateTabsEmpty() {
let subject = createSubject(isPrivateMode: true,
emptyTabs: true,
emptyInactiveTabs: true)

XCTAssertTrue(subject.state.isPrivateTabsEmpty)
}

func testIsPrivateTabsNotEmpty() {
let subject = createSubject(isPrivateMode: true,
emptyTabs: false,
emptyInactiveTabs: true)

XCTAssertFalse(subject.state.isPrivateTabsEmpty)
}

// MARK: - Private
private func createSubject(isPrivateMode: Bool,
emptyTabs: Bool,
Expand Down

0 comments on commit 153a861

Please sign in to comment.