1. Instead of overriding updateTableContents(shouldReload:) in every subclass let the base class to do the reloading and subclasses will just provide contents for the OWSTableViewController2. 2. Remove unnecessary rebuilding of the OWSTableViewContents in didLayoutSubviews(). Do not reload if content doesn't change (it does not in any of the subclasses). 3. Instead of keeping a pre-configured UIStackView in case there's footer content to show - keep a UIView which is more lightweight. Subclasses just add their own footer content to that.
125 lines
4.8 KiB
Swift
125 lines
4.8 KiB
Swift
//
|
|
// Copyright 2022 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
|
|
open class OWSTableSheetViewController: InteractiveSheetViewController {
|
|
open var tableViewController = OWSTableViewController2()
|
|
open override var interactiveScrollViews: [UIScrollView] { [tableViewController.tableView] }
|
|
|
|
open override var sheetBackgroundColor: UIColor {
|
|
OWSTableViewController2.tableBackgroundColor(isUsingPresentedStyle: true, forceDarkMode: tableViewController.forceDarkMode)
|
|
}
|
|
|
|
open var bottomSafeAreaContentPadding: CGFloat {
|
|
var padding = view.safeAreaInsets.bottom
|
|
if padding == 0 {
|
|
// For home button devices, add generous bottom padding
|
|
// so it isn't right up on the edge.
|
|
padding = 36
|
|
} else {
|
|
// For other devices, just add a touch extra.
|
|
padding += 12
|
|
}
|
|
return padding
|
|
}
|
|
|
|
private var contentSizeHeight: CGFloat {
|
|
let tableView = tableViewController.tableView
|
|
// The `adjustedContentInset` property diverges from its stable value during
|
|
// interactive dismiss operations. This causes weird drag/height jump behavior.
|
|
// Instead, compute the height using `view.safeAreaInsets`, which remains stable
|
|
// during animations. (Note that `.top` isn't considered here since
|
|
// `maximumHeight` prevents the view's height from extending into top safe area.)
|
|
return tableView.contentSize.height
|
|
+ tableView.contentInset.totalHeight
|
|
+ footerView.frame.height
|
|
+ bottomSafeAreaContentPadding
|
|
}
|
|
|
|
public init() {
|
|
super.init()
|
|
|
|
tableViewController.shouldDeferInitialLoad = false
|
|
|
|
super.allowsExpansion = false
|
|
}
|
|
|
|
public func updateMinimizedHeight() {
|
|
self.minimizedHeight = self.contentSizeHeight
|
|
}
|
|
|
|
private var footerView = UIView.container()
|
|
private var footerViewConstraints = [NSLayoutConstraint]()
|
|
|
|
public override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
addChild(tableViewController)
|
|
contentView.addSubview(tableViewController.view)
|
|
tableViewController.didMove(toParent: self)
|
|
|
|
contentView.addSubview(footerView)
|
|
|
|
tableViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
|
footerView.translatesAutoresizingMaskIntoConstraints = false
|
|
NSLayoutConstraint.activate([
|
|
tableViewController.view.topAnchor.constraint(equalTo: contentView.topAnchor),
|
|
tableViewController.view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
|
tableViewController.view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
|
|
|
footerView.topAnchor.constraint(equalTo: tableViewController.view.bottomAnchor),
|
|
footerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
|
footerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
|
footerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
|
])
|
|
|
|
updateTableContents(shouldReload: true)
|
|
}
|
|
|
|
public override func viewDidLayoutSubviews() {
|
|
super.viewDidLayoutSubviews()
|
|
|
|
// The table view might not have its final size when this method is called.
|
|
// Run a layout pass so that we compute the correct height constraints.
|
|
self.tableViewController.tableView.layoutIfNeeded()
|
|
self.updateMinimizedHeight()
|
|
}
|
|
|
|
public func updateTableContents(shouldReload: Bool = true) {
|
|
// Update table view.
|
|
tableViewController.setContents(tableContents(), shouldReload: shouldReload)
|
|
|
|
// Update footer.
|
|
footerView.removeAllSubviews()
|
|
NSLayoutConstraint.deactivate(footerViewConstraints)
|
|
if let footerContentView = tableFooterView() {
|
|
footerView.addSubview(footerContentView)
|
|
footerContentView.translatesAutoresizingMaskIntoConstraints = false
|
|
footerViewConstraints = [
|
|
footerContentView.topAnchor.constraint(equalTo: footerView.topAnchor),
|
|
footerContentView.leadingAnchor.constraint(equalTo: footerView.leadingAnchor),
|
|
footerContentView.trailingAnchor.constraint(equalTo: footerView.trailingAnchor),
|
|
footerContentView.bottomAnchor.constraint(equalTo: footerView.bottomAnchor),
|
|
]
|
|
} else {
|
|
footerViewConstraints = [footerView.heightAnchor.constraint(equalToConstant: 0)]
|
|
}
|
|
NSLayoutConstraint.activate(footerViewConstraints)
|
|
|
|
// Update height.
|
|
updateMinimizedHeight()
|
|
}
|
|
|
|
open func tableContents() -> OWSTableContents {
|
|
return OWSTableContents()
|
|
}
|
|
|
|
open func tableFooterView() -> UIView? {
|
|
return nil
|
|
}
|
|
}
|