diff --git a/ios/FluentUI/Bottom Commanding/BottomCommandingController.swift b/ios/FluentUI/Bottom Commanding/BottomCommandingController.swift index 21ec92a50c..8c56d62cae 100644 --- a/ios/FluentUI/Bottom Commanding/BottomCommandingController.swift +++ b/ios/FluentUI/Bottom Commanding/BottomCommandingController.swift @@ -277,6 +277,7 @@ open class BottomCommandingController: UIViewController, TokenizedControlInterna } } + @available(iOS, deprecated: 17.0) public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) diff --git a/ios/FluentUI/Button/Button.swift b/ios/FluentUI/Button/Button.swift index a2b172cddf..fb84110133 100644 --- a/ios/FluentUI/Button/Button.swift +++ b/ios/FluentUI/Button/Button.swift @@ -162,6 +162,7 @@ open class Button: UIButton, Shadowable, TokenizedControlInternal { initialize() } + @available(iOS, deprecated: 17.0) public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) diff --git a/ios/FluentUI/Card/CardView.swift b/ios/FluentUI/Card/CardView.swift index b5e834285c..d39c8ad54b 100644 --- a/ios/FluentUI/Card/CardView.swift +++ b/ios/FluentUI/Card/CardView.swift @@ -378,6 +378,7 @@ open class CardView: UIView, Shadowable, TokenizedControlInternal { preconditionFailure("init(coder:) has not been implemented") } + @available(iOS, deprecated: 17.0) open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if let previousTraitCollection = previousTraitCollection { diff --git a/ios/FluentUI/Core/SwiftUI+ViewModifiers.swift b/ios/FluentUI/Core/SwiftUI+ViewModifiers.swift index 3bfa7bb348..a61d5d43c8 100644 --- a/ios/FluentUI/Core/SwiftUI+ViewModifiers.swift +++ b/ios/FluentUI/Core/SwiftUI+ViewModifiers.swift @@ -43,7 +43,7 @@ extension View { /// Adds a large content viewer for the view. If the text and image are both nil, /// the default large content viewer will be used. - /// - Parameters + /// - Parameters: /// - text: Optional String to display in the large content viewer. /// - image: Optional UIImage to display in the large content viewer. /// - Returns: The modified view. @@ -52,12 +52,29 @@ extension View { } /// Applies multiple shadows on a View - /// - Parameters + /// - Parameters: /// - shadowInfo: The values of the two shadows to be applied /// - Returns: The modified view. func applyShadow(shadowInfo: ShadowInfo) -> some View { modifier(ShadowModifier(shadowInfo: shadowInfo)) } + + /// Abstracts away differences in pre-iOS 17 `onChange(of:perform:)` versus post-iOS 17 `onChange(of:_:)`. + /// + /// This function will be removed once FluentUI moves to iOS 17 as a minimum target. + /// - Parameters: + /// - value: The value to check against when determining whether to run the closure. + /// - action: A closure to run when the value changes. + /// - Returns: A view that fires an action when the specified value changes. + func onChange_iOS17(of value: V, _ action: @escaping (V) -> Void) -> some View where V: Equatable { + if #available(iOS 17, *) { + return self.onChange(of: value) { _, newValue in + return action(newValue) + } + } else { + return self.onChange(of: value, perform: action) + } + } } /// PreferenceKey that will store the measured size of the view diff --git a/ios/FluentUI/Date Time Pickers/Date Picker/DatePickerController.swift b/ios/FluentUI/Date Time Pickers/Date Picker/DatePickerController.swift index a52f6b58a3..406cc9cbe0 100644 --- a/ios/FluentUI/Date Time Pickers/Date Picker/DatePickerController.swift +++ b/ios/FluentUI/Date Time Pickers/Date Picker/DatePickerController.swift @@ -224,6 +224,7 @@ class DatePickerController: UIViewController, GenericDateTimePicker { navigationItem.leftBarButtonItem?.tintColor = view.fluentTheme.color(.foreground2) } + @available(iOS, deprecated: 17.0) public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) diff --git a/ios/FluentUI/Drawer/DrawerPresentationController.swift b/ios/FluentUI/Drawer/DrawerPresentationController.swift index dcd5d1a014..4affeb871b 100644 --- a/ios/FluentUI/Drawer/DrawerPresentationController.swift +++ b/ios/FluentUI/Drawer/DrawerPresentationController.swift @@ -225,7 +225,7 @@ class DrawerPresentationController: UIPresentationController { } case .up: if actualPresentationOrigin == containerView.bounds.maxY { - return containerView.safeAreaInsets.bottom + keyboardHeight + return keyboardHeight == 0 ? containerView.safeAreaInsets.bottom : keyboardHeight } case .fromLeading: if actualPresentationOrigin == containerView.bounds.minX { @@ -344,6 +344,9 @@ class DrawerPresentationController: UIPresentationController { } private func frameForContentView(in bounds: CGRect) -> CGRect { + guard let containerView = containerView else { + return .zero + } var contentFrame = bounds.inset(by: marginsForContentView()) var contentSize = presentedViewController.preferredContentSize @@ -380,7 +383,8 @@ class DrawerPresentationController: UIPresentationController { contentFrame.origin.x += (contentFrame.width - contentSize.width) / 2 if presentationDirection == .up { - contentFrame.origin.y = contentFrame.maxY - contentSize.height + contentFrame.origin.y = keyboardHeight != 0 ? max(landscapeMode ? 0 : sourceViewController.view.safeAreaInsets.top, + containerView.frame.maxY - keyboardHeight - contentSize.height) : contentFrame.maxY - contentSize.height } } else { if actualPresentationOffset == 0 { @@ -510,7 +514,7 @@ class DrawerPresentationController: UIPresentationController { keyboardAnimationDuration = (notificationInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue keyboardFrame = containerView.convert(keyboardFrame, from: nil) - keyboardHeight = max(0, containerView.bounds.maxY - containerView.safeAreaInsets.bottom - keyboardFrame.minY) + keyboardHeight = max(0, containerView.bounds.maxY - keyboardFrame.minY) } } diff --git a/ios/FluentUI/Extensions/UIColor+Extensions.swift b/ios/FluentUI/Extensions/UIColor+Extensions.swift index 4722539ffa..98b1ae0af4 100644 --- a/ios/FluentUI/Extensions/UIColor+Extensions.swift +++ b/ios/FluentUI/Extensions/UIColor+Extensions.swift @@ -217,10 +217,19 @@ extension UIColor { private func resolvedColorValue(userInterfaceStyle: UIUserInterfaceStyle, accessibilityContrast: UIAccessibilityContrast = .unspecified, userInterfaceLevel: UIUserInterfaceLevel = .unspecified) -> UIColor { - let traitCollectionStyle = UITraitCollection(userInterfaceStyle: userInterfaceStyle) - let traitCollectionContrast = UITraitCollection(accessibilityContrast: accessibilityContrast) - let traitCollectionLevel = UITraitCollection(userInterfaceLevel: userInterfaceLevel) - let traitCollection = UITraitCollection(traitsFrom: [traitCollectionStyle, traitCollectionContrast, traitCollectionLevel]) + let traitCollection: UITraitCollection + if #available(iOS 17, *) { + traitCollection = UITraitCollection { mutableTraits in + mutableTraits.userInterfaceStyle = userInterfaceStyle + mutableTraits.accessibilityContrast = accessibilityContrast + mutableTraits.userInterfaceLevel = userInterfaceLevel + } + } else { + let traitCollectionStyle = UITraitCollection(userInterfaceStyle: userInterfaceStyle) + let traitCollectionContrast = UITraitCollection(accessibilityContrast: accessibilityContrast) + let traitCollectionLevel = UITraitCollection(userInterfaceLevel: userInterfaceLevel) + traitCollection = UITraitCollection(traitsFrom: [traitCollectionStyle, traitCollectionContrast, traitCollectionLevel]) + } let resolvedColor = self.resolvedColor(with: traitCollection) return resolvedColor } diff --git a/ios/FluentUI/MultilineCommandBar/MultilineCommandBar.swift b/ios/FluentUI/MultilineCommandBar/MultilineCommandBar.swift index f206b9ad56..0751222a7c 100644 --- a/ios/FluentUI/MultilineCommandBar/MultilineCommandBar.swift +++ b/ios/FluentUI/MultilineCommandBar/MultilineCommandBar.swift @@ -68,6 +68,7 @@ public class MultilineCommandBar: UIViewController { bottomSheetController = sheetController } + @available(iOS, deprecated: 17.0) public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) diff --git a/ios/FluentUI/Navigation/NavigationBar.swift b/ios/FluentUI/Navigation/NavigationBar.swift index 82881f87ca..19735531a9 100644 --- a/ios/FluentUI/Navigation/NavigationBar.swift +++ b/ios/FluentUI/Navigation/NavigationBar.swift @@ -564,6 +564,7 @@ open class NavigationBar: UINavigationBar, TokenizedControlInternal, TwoLineTitl contentStackView.point(inside: convert(point, to: contentStackView), with: event) } + @available(iOS, deprecated: 17.0) open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if traitCollection.verticalSizeClass != previousTraitCollection?.verticalSizeClass { diff --git a/ios/FluentUI/Navigation/Shy Header/ShyHeaderView.swift b/ios/FluentUI/Navigation/Shy Header/ShyHeaderView.swift index 0c6f50e7be..5b953b5160 100644 --- a/ios/FluentUI/Navigation/Shy Header/ShyHeaderView.swift +++ b/ios/FluentUI/Navigation/Shy Header/ShyHeaderView.swift @@ -213,6 +213,7 @@ class ShyHeaderView: UIView, TokenizedControlInternal { /// e.g. should cancel a search on scroll private var cancelsContentFirstRespondingOnHide: Bool = false + @available(iOS, deprecated: 17.0) override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) updateContentInsets() diff --git a/ios/FluentUI/Notification/FluentNotification.swift b/ios/FluentUI/Notification/FluentNotification.swift index 4e8908ac91..96f94c86fa 100644 --- a/ios/FluentUI/Notification/FluentNotification.swift +++ b/ios/FluentUI/Notification/FluentNotification.swift @@ -313,13 +313,13 @@ public struct FluentNotification: View, TokenizedControlView { notification .frame(idealWidth: isFlexibleWidthToast ? innerContentsSize.width - horizontalPadding : calculatedNotificationWidth, maxWidth: isFlexibleWidthToast ? proposedWidth : calculatedNotificationWidth, alignment: .center) - .onChange(of: isPresented, perform: { present in - if present { + .onChange_iOS17(of: isPresented) { newPresent in + if newPresent { presentAnimated() } else { dismissAnimated() } - }) + } .padding(.bottom, tokenSet[.bottomPresentationPadding].float) .onSizeChange { newSize in bottomOffsetForDismissedState = newSize.height + (tokenSet[.shadow].shadowInfo.yKey / 2) diff --git a/ios/FluentUI/Popup Menu/PopupMenuController.swift b/ios/FluentUI/Popup Menu/PopupMenuController.swift index 754798e8d8..cb76a2a443 100644 --- a/ios/FluentUI/Popup Menu/PopupMenuController.swift +++ b/ios/FluentUI/Popup Menu/PopupMenuController.swift @@ -257,7 +257,7 @@ open class PopupMenuController: DrawerController { } private func initTableView() { - tableView.backgroundColor = backgroundColor + tableView.backgroundColor = .clear tableView.separatorStyle = .none tableView.alwaysBounceVertical = false tableView.isAccessibilityElement = true diff --git a/ios/FluentUI/Popup Menu/PopupMenuItemTokenSet.swift b/ios/FluentUI/Popup Menu/PopupMenuItemTokenSet.swift index 30282cbe06..d34ae2a170 100644 --- a/ios/FluentUI/Popup Menu/PopupMenuItemTokenSet.swift +++ b/ios/FluentUI/Popup Menu/PopupMenuItemTokenSet.swift @@ -20,7 +20,7 @@ class PopupMenuItemTokenSet: TableViewCellTokenSet { self.fluentTheme.color(.foreground3) }, .cellBackgroundColor: .uiColor { - self.fluentTheme.color(.background1) + .clear } ]) } diff --git a/ios/FluentUI/SegmentedControl/SegmentedControl.swift b/ios/FluentUI/SegmentedControl/SegmentedControl.swift index b53aa9e897..69dea7b31e 100644 --- a/ios/FluentUI/SegmentedControl/SegmentedControl.swift +++ b/ios/FluentUI/SegmentedControl/SegmentedControl.swift @@ -369,6 +369,7 @@ open class SegmentedControl: UIView, TokenizedControlInternal { height: CGFloat.greatestFiniteMagnitude)) } + @available(iOS, deprecated: 17.0) open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) invalidateIntrinsicContentSize() diff --git a/ios/FluentUI/Tab Bar/TabBarItemView.swift b/ios/FluentUI/Tab Bar/TabBarItemView.swift index d8807f2667..5decb889bd 100644 --- a/ios/FluentUI/Tab Bar/TabBarItemView.swift +++ b/ios/FluentUI/Tab Bar/TabBarItemView.swift @@ -158,6 +158,7 @@ class TabBarItemView: UIControl, TokenizedControlInternal { return size } + @available(iOS, deprecated: 17.0) override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if previousTraitCollection?.horizontalSizeClass != traitCollection.horizontalSizeClass || previousTraitCollection?.verticalSizeClass != traitCollection.verticalSizeClass { diff --git a/ios/FluentUI/Tab Bar/TabBarView.swift b/ios/FluentUI/Tab Bar/TabBarView.swift index 888a3f2bc3..05ba1584b2 100644 --- a/ios/FluentUI/Tab Bar/TabBarView.swift +++ b/ios/FluentUI/Tab Bar/TabBarView.swift @@ -122,6 +122,7 @@ open class TabBarView: UIView, TokenizedControlInternal { preconditionFailure("init(coder:) has not been implemented") } + @available(iOS, deprecated: 17.0) open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) if previousTraitCollection?.horizontalSizeClass != traitCollection.horizontalSizeClass || previousTraitCollection?.verticalSizeClass != traitCollection.verticalSizeClass { diff --git a/ios/FluentUI/Tooltip/TooltipViewController.swift b/ios/FluentUI/Tooltip/TooltipViewController.swift index 33d9b337c0..4fa4b00f14 100644 --- a/ios/FluentUI/Tooltip/TooltipViewController.swift +++ b/ios/FluentUI/Tooltip/TooltipViewController.swift @@ -49,6 +49,7 @@ class TooltipViewController: UIViewController { } } + @available(iOS, deprecated: 17.0) override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection)