ssap_app/node_modules/react-native-screens/ios/gamma/split-view/RNSSplitViewAppearanceAppli...

192 lines
7.9 KiB
Swift

///
/// @brief - Class responsible for applying all upcoming updates to SplitView.
///
/// This class is synchronizing UISplitViewController configuration props which are affecting the SplitView appearance with props passed to RNSSplitViewHostComponentView from the ElementTree.
///
class RNSSplitViewAppearanceApplicator {
///
/// @brief Function responsible for applying all updates to SplitView in correct order
///
/// It requests calling proper callbacks with batched SplitView updates on the AppearanceCoordinator object
///
/// @param splitView The view representing JS component which is sending updates.
/// @param splitViewController The controller associated with the SplitView component which receives updates and manages the native layer.
/// @param appearanceCoordinator The coordinator which is checking whether the update needs to be applied and if so, it executes the callback passed by this class.
///
public func updateAppearanceIfNeeded(
_ splitView: RNSSplitViewHostComponentView,
_ splitViewController: RNSSplitViewHostController,
_ appearanceCoordinator: RNSSplitViewAppearanceCoordinator
) {
appearanceCoordinator.updateIfNeeded(.generalUpdate) { [weak self] in
guard let self = self
else {
return
}
self.updateSplitViewConfiguration(for: splitView, withController: splitViewController)
}
appearanceCoordinator.updateIfNeeded(.secondaryScreenNavBarUpdate) { [weak self] in
guard let self = self
else {
return
}
splitViewController.refreshSecondaryNavBar()
}
appearanceCoordinator.updateIfNeeded(.displayModeUpdate) { [weak self] in
guard let self = self
else {
return
}
self.updateSplitViewDisplayMode(for: splitView, withController: splitViewController)
}
appearanceCoordinator.updateIfNeeded(.orientationUpdate) { [] in
RNSScreenWindowTraits.enforceDesiredDeviceOrientation()
}
}
///
/// @brief Function that applies all basic updates.
///
/// It calls all setters on RNSSplitViewHostController that doesn't require any custom logic and conditions to be met.
///
/// @param splitView The view representing JS component which is sending updates.
/// @param splitViewController The controller associated with the SplitView component which receives updates and manages the native layer.
///
private func updateSplitViewConfiguration(
for splitView: RNSSplitViewHostComponentView,
withController splitViewController: RNSSplitViewHostController
) {
// Step 1 - general settings
splitViewController.displayModeButtonVisibility = splitView.displayModeButtonVisibility
splitViewController.preferredSplitBehavior = splitView.preferredSplitBehavior
splitViewController.presentsWithGesture = splitView.presentsWithGesture
splitViewController.primaryEdge = splitView.primaryEdge
splitViewController.showsSecondaryOnlyButton = splitView.showSecondaryToggleButton
// Step 2.1 - validating column constraints
validateColumnConstraints(
minWidth: splitView.minimumPrimaryColumnWidth,
maxWidth: splitView.maximumPrimaryColumnWidth)
validateColumnConstraints(
minWidth: splitView.minimumSupplementaryColumnWidth,
maxWidth: splitView.maximumSupplementaryColumnWidth)
#if compiler(>=6.2)
if #available(iOS 26.0, *) {
validateColumnConstraints(
minWidth: splitView.minimumInspectorColumnWidth,
maxWidth: splitView.maximumInspectorColumnWidth)
}
#endif
// Step 2.2 - applying updates to columns
if splitView.minimumPrimaryColumnWidth >= 0 {
splitViewController.minimumPrimaryColumnWidth = splitView.minimumPrimaryColumnWidth
}
if splitView.maximumPrimaryColumnWidth >= 0 {
splitViewController.maximumPrimaryColumnWidth = splitView.maximumPrimaryColumnWidth
}
if splitView.preferredPrimaryColumnWidthOrFraction >= 0
&& splitView.preferredPrimaryColumnWidthOrFraction < 1
{
splitViewController.preferredPrimaryColumnWidthFraction =
splitView.preferredPrimaryColumnWidthOrFraction
} else if splitView.preferredPrimaryColumnWidthOrFraction >= 1 {
splitViewController.preferredPrimaryColumnWidth =
splitView.preferredPrimaryColumnWidthOrFraction
}
if splitView.minimumSupplementaryColumnWidth >= 0 {
splitViewController.minimumSupplementaryColumnWidth =
splitView.minimumSupplementaryColumnWidth
}
if splitView.maximumSupplementaryColumnWidth >= 0 {
splitViewController.maximumSupplementaryColumnWidth =
splitView.maximumSupplementaryColumnWidth
}
if splitView.preferredSupplementaryColumnWidthOrFraction >= 0
&& splitView.preferredSupplementaryColumnWidthOrFraction < 1
{
splitViewController.preferredSupplementaryColumnWidthFraction =
splitView.preferredSupplementaryColumnWidthOrFraction
} else if splitView.preferredSupplementaryColumnWidthOrFraction >= 1 {
splitViewController.preferredSupplementaryColumnWidth =
splitView.preferredSupplementaryColumnWidthOrFraction
}
#if compiler(>=6.2)
if #available(iOS 26.0, *) {
if splitView.minimumSecondaryColumnWidth >= 0 {
splitViewController.minimumSecondaryColumnWidth = splitView.minimumSecondaryColumnWidth
}
if splitView.preferredSecondaryColumnWidthOrFraction >= 0
&& splitView.preferredSecondaryColumnWidthOrFraction < 1
{
splitViewController.preferredSecondaryColumnWidthFraction =
splitView.preferredSecondaryColumnWidthOrFraction
} else if splitView.preferredSecondaryColumnWidthOrFraction >= 1 {
splitViewController.preferredSecondaryColumnWidth =
splitView.preferredSecondaryColumnWidthOrFraction
}
if splitView.minimumInspectorColumnWidth >= 0 {
splitViewController.minimumInspectorColumnWidth = splitView.minimumInspectorColumnWidth
}
if splitView.maximumInspectorColumnWidth >= 0 {
splitViewController.maximumInspectorColumnWidth = splitView.maximumInspectorColumnWidth
}
if splitView.preferredInspectorColumnWidthOrFraction >= 0
&& splitView.preferredInspectorColumnWidthOrFraction < 1
{
splitViewController.preferredInspectorColumnWidthFraction =
splitView.preferredInspectorColumnWidthOrFraction
} else if splitView.preferredInspectorColumnWidthOrFraction >= 1 {
splitViewController.preferredInspectorColumnWidth =
splitView.preferredInspectorColumnWidthOrFraction
}
}
#endif
// Step 2.3 - manipulating with inspector column
splitViewController.toggleSplitViewInspector(splitView.showInspector)
}
///
/// @brief Function that updates `preferredDisplayMode` property on SplitView.
///
/// `preferredDisplayMode` needs to have a dedicated flag to prevent updates from the JS, when other props updates the appearance.
/// It is crucial in the case, when `preferredDisplayMode` has changed due to some transition that was executed natively, e. g. after showing/hiding a column by a swipe.
/// In that case, any prop update incoming, would reset `preferredDisplayMode` to the state from JS, what doesn't look good.
///
/// @param splitView The view representing JS component which is sending updates.
/// @param splitViewController The controller associated with the SplitView component which receives updates and manages the native layer.
///
func updateSplitViewDisplayMode(
for splitView: RNSSplitViewHostComponentView,
withController splitViewController: RNSSplitViewHostController
) {
splitViewController.preferredDisplayMode = splitView.preferredDisplayMode
}
func validateColumnConstraints(minWidth: CGFloat, maxWidth: CGFloat) {
assert(
minWidth <= maxWidth,
"[RNScreens] SplitView column constraints are invalid: minWidth \(minWidth) cannot be greater than maxWidth \(maxWidth)"
)
}
}