Skip to content

Commit

Permalink
remove main view controller storyboard (#2058)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/0/1205584556126567/f
Tech Design URL:
CC:

Description:

Note: This PR is based on #2045.
  • Loading branch information
brindy authored Oct 3, 2023
1 parent 1c5863f commit 02783fc
Show file tree
Hide file tree
Showing 33 changed files with 467 additions and 724 deletions.
2 changes: 1 addition & 1 deletion Core/UIViewControllerExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension UIViewController {
}

var isPad: Bool {
return traitCollection.horizontalSizeClass == .regular
return UIDevice.current.userInterfaceIdiom == .pad
}

@objc func buildActivities() -> [UIActivity] {
Expand Down
64 changes: 4 additions & 60 deletions DuckDuckGo.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

20 changes: 7 additions & 13 deletions DuckDuckGo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,19 +209,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
syncService.initializeIfNeeded()
self.syncService = syncService

let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)

guard let main = storyboard.instantiateInitialViewController(creator: { coder in
MainViewController(coder: coder,
bookmarksDatabase: self.bookmarksDatabase,
bookmarksDatabaseCleaner: self.syncDataProviders.bookmarksAdapter.databaseCleaner,
appTrackingProtectionDatabase: self.appTrackingProtectionDatabase,
syncService: self.syncService,
syncDataProviders: self.syncDataProviders)
}) else {
fatalError("Could not load MainViewController")
}

let main = MainViewController(bookmarksDatabase: bookmarksDatabase,
bookmarksDatabaseCleaner: syncDataProviders.bookmarksAdapter.databaseCleaner,
appTrackingProtectionDatabase: appTrackingProtectionDatabase,
syncService: syncService,
syncDataProviders: syncDataProviders)
main.loadViewIfNeeded()

window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = main
window?.makeKeyAndVisible()
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/BrowserChromeManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protocol BrowserChromeDelegate: AnyObject {
var barsMaxHeight: CGFloat { get }

var omniBar: OmniBar! { get }
var tabsBar: UIView! { get }
var tabBarContainer: UIView { get }
}

class BrowserChromeManager: NSObject, UIScrollViewDelegate {
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/HomeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class HomeViewController: UIViewController {

delegate?.home(self, searchTransitionUpdated: percent)
chromeDelegate?.omniBar.alpha = percent
chromeDelegate?.tabsBar.alpha = percent
chromeDelegate?.tabBarContainer.alpha = percent
}
}

Expand Down
335 changes: 335 additions & 0 deletions DuckDuckGo/MainView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
//
// MainView.swift
// DuckDuckGo
//
// Copyright © 2023 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import UIKit

class MainViewFactory {

private let coordinator: MainViewCoordinator

var superview: UIView {
coordinator.superview
}

private init(_ superview: UIView) {
coordinator = MainViewCoordinator(superview: superview)
}

static func createViewHierarchy(_ superview: UIView) -> MainViewCoordinator {
let factory = MainViewFactory(superview)

factory.createViews()
factory.disableAutoresizingOnViewAndImmediateSubviews(superview)
factory.constrainViews()

return factory.coordinator
}

private func disableAutoresizingOnViewAndImmediateSubviews(_ view: UIView) {
view.translatesAutoresizingMaskIntoConstraints = false
view.subviews.forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
}
}

}

/// Create functions. The lightweight subclases of UIView make it easier to debug to the UI.
extension MainViewFactory {

private func createViews() {
createLogoBackground()
createContentContainer()
createSuggestionTrayContainer()
createNotificationBarContainer()
createStatusBackground()
createTabBarContainer()
createNavigationBarContainer()
createProgressView()
createToolbar()
}

private func createProgressView() {
coordinator.progress = ProgressView()
superview.addSubview(coordinator.progress)
}

class NavigationBarContainer: UIView { }
private func createNavigationBarContainer() {
coordinator.navigationBarContainer = NavigationBarContainer()
superview.addSubview(coordinator.navigationBarContainer)
}

class NotificationBarContainer: UIView { }
private func createNotificationBarContainer() {
coordinator.notificationBarContainer = NotificationBarContainer()
superview.addSubview(coordinator.notificationBarContainer)
}

class ContentContainer: UIView { }
private func createContentContainer() {
coordinator.contentContainer = ContentContainer()
superview.addSubview(coordinator.contentContainer)
}

class StatusBackgroundView: UIView { }
private func createStatusBackground() {
coordinator.statusBackground = StatusBackgroundView()
superview.addSubview(coordinator.statusBackground)
}

class TabBarContainer: UIView { }
private func createTabBarContainer() {
coordinator.tabBarContainer = TabBarContainer()
superview.addSubview(coordinator.tabBarContainer)
}

class SuggestionTrayContainer: UIView { }
private func createSuggestionTrayContainer() {
coordinator.suggestionTrayContainer = SuggestionTrayContainer()
coordinator.suggestionTrayContainer.isHidden = true
coordinator.suggestionTrayContainer.backgroundColor = .clear
superview.addSubview(coordinator.suggestionTrayContainer)
}

private func createToolbar() {

coordinator.toolbar = HitTestingToolbar()
coordinator.toolbarBackButton = UIBarButtonItem(title: UserText.keyCommandBrowserBack, image: UIImage(named: "BrowsePrevious"))
coordinator.toolbarForwardButton = UIBarButtonItem(title: UserText.keyCommandBrowserForward, image: UIImage(named: "BrowseNext"))
coordinator.toolbarFireButton = UIBarButtonItem(title: UserText.actionForgetAll, image: UIImage(named: "Fire"))
coordinator.toolbarTabSwitcherButton = UIBarButtonItem(title: UserText.tabSwitcherAccessibilityLabel, image: UIImage(named: "Add-24"))
coordinator.lastToolbarButton = UIBarButtonItem(title: UserText.actionOpenBookmarks, image: UIImage(named: "Book-24"))
superview.addSubview(coordinator.toolbar)

coordinator.toolbar.setItems([
coordinator.toolbarBackButton!,
.flexibleSpace(),
coordinator.toolbarForwardButton!,
.flexibleSpace(),
coordinator.toolbarFireButton!,
.flexibleSpace(),
coordinator.toolbarTabSwitcherButton!,
.flexibleSpace(),
coordinator.lastToolbarButton!,
], animated: true)
}

class LogoBackgroundView: UIView { }
private func createLogoBackground() {
coordinator.logoContainer = LogoBackgroundView()
coordinator.logo = UIImageView(image: UIImage(named: "Logo"))
coordinator.logoText = UIImageView(image: UIImage(named: "TextDuckDuckGo"))

coordinator.logoContainer.backgroundColor = .clear
coordinator.logoContainer.addSubview(coordinator.logo)
coordinator.logoContainer.addSubview(coordinator.logoText)
superview.addSubview(coordinator.logoContainer)

disableAutoresizingOnViewAndImmediateSubviews(coordinator.logoContainer)
}

}

/// Add constraint functions
extension MainViewFactory {

private func constrainViews() {
constrainLogoBackground()
constrainContentContainer()
constrainSuggestionTrayContainer()
constrainNotificationBarContainer()
constrainStatusBackground()
constrainTabBarContainer()
constrainNavigationBarContainer()
constrainProgress()
constrainToolbar()
}

private func constrainProgress() {
let progress = coordinator.progress!
let navigationBarContainer = coordinator.navigationBarContainer!
NSLayoutConstraint.activate([
progress.constrainView(navigationBarContainer, by: .trailing),
progress.constrainView(navigationBarContainer, by: .leading),
progress.constrainAttribute(.height, to: 3),
progress.constrainView(navigationBarContainer, by: .top, to: .bottom),
])
}

private func constrainNavigationBarContainer() {
let navigationBarContainer = coordinator.navigationBarContainer!

coordinator.constraints.navigationBarContainerTop = navigationBarContainer.constrainView(superview.safeAreaLayoutGuide, by: .top)

NSLayoutConstraint.activate([
navigationBarContainer.constrainView(superview, by: .centerX),
navigationBarContainer.constrainView(superview, by: .width),
coordinator.constraints.navigationBarContainerTop,
navigationBarContainer.constrainAttribute(.height, to: 52),
])
}

private func constrainTabBarContainer() {
let tabBarContainer = coordinator.tabBarContainer!

coordinator.constraints.tabBarContainerTop = tabBarContainer.constrainView(superview.safeAreaLayoutGuide, by: .top)

NSLayoutConstraint.activate([
tabBarContainer.constrainView(superview, by: .leading),
tabBarContainer.constrainView(superview, by: .trailing),
tabBarContainer.constrainAttribute(.height, to: 40),
coordinator.constraints.tabBarContainerTop,
])
}

private func constrainStatusBackground() {
let statusBackground = coordinator.statusBackground!
let navigationBarContainer = coordinator.navigationBarContainer!
NSLayoutConstraint.activate([
statusBackground.constrainView(superview, by: .width),
statusBackground.constrainView(superview, by: .centerX),
statusBackground.constrainView(superview, by: .top),
statusBackground.constrainView(navigationBarContainer, by: .bottom),
])
}

private func constrainNotificationBarContainer() {
let notificationBarContainer = coordinator.notificationBarContainer!
let contentContainer = coordinator.contentContainer!
let navigationBarContainer = coordinator.navigationBarContainer!

coordinator.constraints.notificationContainerTop = notificationBarContainer.constrainView(navigationBarContainer, by: .top, to: .bottom)
coordinator.constraints.notificationContainerHeight = notificationBarContainer.constrainAttribute(.height, to: 0)

NSLayoutConstraint.activate([
notificationBarContainer.constrainView(superview, by: .width),
notificationBarContainer.constrainView(superview, by: .centerX),
coordinator.constraints.notificationContainerHeight,
notificationBarContainer.constrainView(contentContainer, by: .bottom, to: .top),
coordinator.constraints.notificationContainerTop,
])
}

private func constrainContentContainer() {
let contentContainer = coordinator.contentContainer!
let toolbar = coordinator.toolbar!
let notificationBarContainer = coordinator.notificationBarContainer!

coordinator.constraints.contentContainerTop = contentContainer.constrainView(notificationBarContainer, by: .top, to: .bottom)

NSLayoutConstraint.activate([
contentContainer.constrainView(superview, by: .leading),
contentContainer.constrainView(superview, by: .trailing),
contentContainer.constrainView(toolbar, by: .bottom, to: .top),
coordinator.constraints.contentContainerTop,
])
}

private func constrainToolbar() {
let toolbar = coordinator.toolbar!
coordinator.constraints.toolbarBottom = toolbar.constrainView(superview.safeAreaLayoutGuide, by: .bottom)
NSLayoutConstraint.activate([
toolbar.constrainView(superview, by: .width),
toolbar.constrainView(superview, by: .centerX),
toolbar.constrainAttribute(.height, to: 49),
coordinator.constraints.toolbarBottom,
])
}

private func constrainSuggestionTrayContainer() {
let suggestionTrayContainer = coordinator.suggestionTrayContainer!
let contentContainer = coordinator.contentContainer!
NSLayoutConstraint.activate([
suggestionTrayContainer.constrainView(contentContainer, by: .width),
suggestionTrayContainer.constrainView(contentContainer, by: .height),
suggestionTrayContainer.constrainView(contentContainer, by: .centerX),
suggestionTrayContainer.constrainView(contentContainer, by: .centerY),
])
}

private func constrainLogoBackground() {
let logoContainer = coordinator.logoContainer!
let logo = coordinator.logo!
let text = coordinator.logoText!
NSLayoutConstraint.activate([
logoContainer.constrainView(superview, by: .width),
logoContainer.constrainView(superview, by: .height),
logoContainer.constrainView(superview, by: .centerX),
logoContainer.constrainView(superview, by: .centerY),
logo.constrainView(logoContainer, by: .centerX),
logo.constrainView(logoContainer, by: .centerY, constant: -72),
logo.constrainAttribute(.width, to: 96),
logo.constrainAttribute(.height, to: 96),
text.constrainView(logo, by: .top, to: .bottom, constant: 12),
text.constrainView(logo, by: .centerX),
])
}

}

class MainViewCoordinator {

let superview: UIView

var logoContainer: UIView!
var logo: UIImageView!
var logoText: UIImageView!
var toolbar: UIToolbar!
var suggestionTrayContainer: UIView!
var contentContainer: UIView!
var notificationBarContainer: UIView!
var statusBackground: UIView!
var tabBarContainer: UIView!
var navigationBarContainer: UIView!
var progress: ProgressView!
var toolbarBackButton: UIBarButtonItem!
var toolbarForwardButton: UIBarButtonItem!
var toolbarFireButton: UIBarButtonItem!
var toolbarTabSwitcherButton: UIBarButtonItem!
var lastToolbarButton: UIBarButtonItem!

let constraints = Constraints()

fileprivate init(superview: UIView) {
self.superview = superview
}

func decorateWithTheme(_ theme: Theme) {
superview.backgroundColor = theme.mainViewBackgroundColor
logoText.tintColor = theme.ddgTextTintColor
}

func hideSuggestionTray() {
suggestionTrayContainer.isHidden = true
suggestionTrayContainer.backgroundColor = .clear
}

class Constraints {

var navigationBarContainerTop: NSLayoutConstraint!
var toolbarBottom: NSLayoutConstraint!
var contentContainerTop: NSLayoutConstraint!
var tabBarContainerTop: NSLayoutConstraint!
var notificationContainerTop: NSLayoutConstraint!
var notificationContainerHeight: NSLayoutConstraint!

}

}
Loading

0 comments on commit 02783fc

Please sign in to comment.