Skip to content

Commit dcd98cd

Browse files
committed
View Controllers: make ViewController conform to TraitEnvironment
`ViewController` provides a trait environment. Add a protocol conformance for this.
1 parent f094dab commit dcd98cd

File tree

3 files changed

+248
-34
lines changed

3 files changed

+248
-34
lines changed

Sources/SwiftWin32/App and Environment/TraitCollection.swift

+4
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ private func GetCurrentDisplayGamut() -> DisplayGamut {
242242
}
243243

244244
public class TraitCollection {
245+
/// Creates an empty trait collection.
246+
internal init() {
247+
}
248+
245249
// MARK - Creating a Trait Collection
246250

247251
/// Creates a trait collection that consists of traits merged from a specified

Sources/SwiftWin32/CMakeLists.txt

+27-34
Original file line numberDiff line numberDiff line change
@@ -24,48 +24,47 @@ target_sources(SwiftWin32 PRIVATE
2424
UI/Interaction.swift
2525
UI/SceneSizeRestrictions.swift)
2626
target_sources(SwiftWin32 PRIVATE
27-
"App Extensions/InputViewController.swift")
28-
target_sources(SwiftWin32 PRIVATE
27+
"App Extensions/InputViewController.swift"
2928
"Animation and Haptics/ViewControllerContextTransitioning.swift"
29+
"Animation and Haptics/Property-Based Animations/CubicTimingParameters.swift"
30+
"Animation and Haptics/Property-Based Animations/SpringTimingParameters.swift"
31+
"Animation and Haptics/Property-Based Animations/TimingCurveProvider.swift"
32+
"Animation and Haptics/Property-Based Animations/ViewAnimating.swift"
33+
"Animation and Haptics/Property-Based Animations/ViewImplicitlyAnimating.swift"
34+
"Animation and Haptics/View Controller Transitions/ViewControllerAnimatedTransitioning.swift"
35+
"Animation and Haptics/View Controller Transitions/ViewControllerInteractiveTransitioning.swift"
3036
"Animation and Haptics/View Controller Transitions/ViewControllerTransitionCoordinator.swift"
31-
"Animation and Haptics/View Controller Transitions/ViewControllerTransitionCoordinatorContext.swift")
32-
target_sources(SwiftWin32 PRIVATE
37+
"Animation and Haptics/View Controller Transitions/ViewControllerTransitionCoordinatorContext.swift"
38+
"Animation and Haptics/View Controller Transitions/ViewControllerTransitioningDelegate.swift"
39+
"App and Environment/AdaptivePresentationControllerDelegate.swift"
3340
"App and Environment/Application.swift"
3441
"App and Environment/ApplicationDelegate.swift"
3542
"App and Environment/ApplicationMain.swift"
3643
"App and Environment/Device.swift"
3744
"App and Environment/TraitCollection.swift"
38-
"App and Environment/TraitEnvironment.swift")
39-
target_sources(SwiftWin32 PRIVATE
45+
"App and Environment/TraitEnvironment.swift"
4046
"App and Environment/Scenes/Scene.swift"
4147
"App and Environment/Scenes/SceneConfiguration.swift"
4248
"App and Environment/Scenes/SceneDelegate.swift"
4349
"App and Environment/Scenes/SceneSession.swift"
4450
"App and Environment/Scenes/WindowScene.swift"
45-
"App and Environment/Scenes/WindowSceneDelegate.swift")
46-
target_sources(SwiftWin32 PRIVATE
51+
"App and Environment/Scenes/WindowSceneDelegate.swift"
4752
"Appearance Customization/Configurations/BackgroundConfiguration.swift"
4853
"Appearance Customization/Configurations/CellConfigurationState.swift"
4954
"Appearance Customization/Configurations/ConfigurationColorTransformer.swift"
5055
"Appearance Customization/Configurations/ConfigurationState.swift"
51-
"Appearance Customization/Configurations/ConfigurationStateCustomKey.swift")
52-
target_sources(SwiftWin32 PRIVATE
53-
"Drag and Drop/SpringLoadedInteractionContext.swift")
54-
target_sources(SwiftWin32 PRIVATE
56+
"Appearance Customization/Configurations/ConfigurationStateCustomKey.swift"
57+
"Drag and Drop/SpringLoadedInteractionContext.swift"
5558
"Drawing/BezierPath.swift"
56-
"Drawing/Color.swift")
57-
target_sources(SwiftWin32 PRIVATE
59+
"Drawing/Color.swift"
5860
"Focus-Based Navigation/FocusAnimationCoordinator.swift"
5961
"Focus-Based Navigation/FocusEnvironment.swift"
6062
"Focus-Based Navigation/FocusItem.swift"
6163
"Focus-Based Navigation/FocusItemContainer.swift"
6264
"Focus-Based Navigation/FocusMovementHint.swift"
63-
"Focus-Based Navigation/FocusUpdateContext.swift")
64-
target_sources(SwiftWin32 PRIVATE
65-
"Images and PDF/Image.swift")
66-
target_sources(SwiftWin32 PRIVATE
67-
"Keyboards and Input/TextInputTraits.swift")
68-
target_sources(SwiftWin32 PRIVATE
65+
"Focus-Based Navigation/FocusUpdateContext.swift"
66+
"Images and PDF/Image.swift"
67+
"Keyboards and Input/TextInputTraits.swift"
6968
"Menus and Shortcuts/Action.swift"
7069
"Menus and Shortcuts/Command.swift"
7170
"Menus and Shortcuts/ContextMenuConfiguration.swift"
@@ -79,30 +78,26 @@ target_sources(SwiftWin32 PRIVATE
7978
"Menus and Shortcuts/MenuSystem.swift"
8079
"Menus and Shortcuts/PreviewParameters.swift"
8180
"Menus and Shortcuts/PreviewTarget.swift"
82-
"Menus and Shortcuts/TargetedPreview.swift")
83-
target_sources(SwiftWin32 PRIVATE
81+
"Menus and Shortcuts/TargetedPreview.swift"
8482
"Pointer Interactions/PointerInteraction.swift"
8583
"Pointer Interactions/PointerInteractionAnimating.swift"
8684
"Pointer Interactions/PointerInteractionDelegate.swift"
8785
"Pointer Interactions/PointerRegion.swift"
8886
"Pointer Interactions/PointerRegionRequest.swift"
89-
"Pointer Interactions/PointerStyle.swift")
90-
target_sources(SwiftWin32 PRIVATE
87+
"Pointer Interactions/PointerStyle.swift"
9188
"Text Display and Fonts/Font.swift"
9289
"Text Display and Fonts/FontDescriptor.swift"
93-
"Text Display and Fonts/FontMetrics.swift")
94-
target_sources(SwiftWin32 PRIVATE
90+
"Text Display and Fonts/FontMetrics.swift"
9591
"Touches, Presses, and Gestures/Event.swift"
9692
"Touches, Presses, and Gestures/GestureRecognizer.swift"
9793
"Touches, Presses, and Gestures/GestureRecognizerDelegate.swift"
9894
"Touches, Presses, and Gestures/Responder.swift"
9995
"Touches, Presses, and Gestures/Touch.swift"
10096
"Touches, Presses, and Gestures/Press.swift"
101-
"Touches, Presses, and Gestures/PressesEvent.swift")
102-
target_sources(SwiftWin32 PRIVATE
97+
"Touches, Presses, and Gestures/PressesEvent.swift"
10398
"View Controllers/ContentContainer.swift"
104-
"View Controllers/ViewController.swift")
105-
target_sources(SwiftWin32 PRIVATE
99+
"View Controllers/PresentationController.swift"
100+
"View Controllers/ViewController.swift"
106101
"Views and Controls/Axis.swift"
107102
"Views and Controls/Button.swift"
108103
"Views and Controls/Control.swift"
@@ -119,16 +114,14 @@ target_sources(SwiftWin32 PRIVATE
119114
"Views and Controls/TextField.swift"
120115
"Views and Controls/TextView.swift"
121116
"Views and Controls/View.swift"
122-
"Views and Controls/VisualEffect.swift")
123-
target_sources(SwiftWin32 PRIVATE
117+
"Views and Controls/VisualEffect.swift"
124118
"Views and Controls/Table Views/ContextualAction.swift"
125119
"Views and Controls/Table Views/SwipeActionsConfiguration.swift"
126120
"Views and Controls/Table Views/TableView.swift"
127121
"Views and Controls/Table Views/TableViewCell.swift"
128122
"Views and Controls/Table Views/TableViewDataSource.swift"
129123
"Views and Controls/Table Views/TableViewDelegate.swift"
130-
"Views and Controls/Table Views/TableViewFocusUpdateContext.swift")
131-
target_sources(SwiftWin32 PRIVATE
124+
"Views and Controls/Table Views/TableViewFocusUpdateContext.swift"
132125
"Windows and Screens/AlertAction.swift"
133126
"Windows and Screens/AlertController.swift"
134127
"Windows and Screens/CoordinateSpace.swift"

Sources/SwiftWin32/View Controllers/ViewController.swift

+217
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
import WinSDK
55
import class Foundation.NSNotification
6+
import struct Foundation.NSExceptionName
7+
import struct Foundation.TimeInterval
68

79
/// Transition styles available when presenting view controllers.
810
public enum ModalTransitionStyle: Int {
@@ -708,6 +710,99 @@ public class ViewController: Responder {
708710
NSNotification.Name(rawValue: "UIViewControllerShowDetailTargetDidChangeNotification")
709711
}
710712

713+
// MARK - Adding a Custom Transition or Presentation
714+
715+
/// The delegate object that provides transition animator, interactive
716+
/// controller, and custom presentation controller objects.
717+
///
718+
/// When the view controller's `modalPresentationStyle` property is
719+
/// `ModalPresentationStyle.custom`, the framework uses the object in this
720+
/// property to facilitate transitions and presentations for the view
721+
/// controller. The transitioning delegate object is a custom object that you
722+
/// provide and that conforms to the `ViewControllerTransitioningDelegate`
723+
/// protocol. Its job is to vend the animator objects used to animate this
724+
/// view controller's view onscreen and an optional presentation controller
725+
/// to provide any additional chrome and animations.
726+
public weak var transitioningDelegate: ViewControllerTransitioningDelegate?
727+
728+
/// Returns the active transition coordinator object.
729+
///
730+
/// When a presentation or dismissal is in progress, this method returns the
731+
/// transition coordinator object associated with that transition. If there is
732+
/// no in-progress transition associated with the current view controller,
733+
/// the framework checks the view controller's ancestors for a transition
734+
/// coordinator object and returns that object if it exists. You can use this
735+
/// object to create additional animations and synchronize them with the
736+
/// transition animations.
737+
///
738+
/// Container view controllers can override this method but in most cases
739+
/// should not need to. If you do override this method, first call `super` to
740+
/// see if there is an appropriate transition coordinator to return, and, if
741+
/// there is, return it.
742+
///
743+
/// For more information about the role of transition coordinators, see
744+
/// `ViewControllerTransitionCoordinator`.
745+
public private(set) var transitionCoordinator: ViewControllerTransitionCoordinator?
746+
747+
/// Returns the view controller that responds to the action.
748+
///
749+
/// This method returns the current view controller if that view controller
750+
/// overrides the method indicated by the action parameter. If the current
751+
/// view controller does not override that method, the framework walks up the
752+
/// view hierarchy and returns the first view controller that does override
753+
/// it. If no view controller handles the action, this method returns `nil`.
754+
///
755+
/// A view controller can selectively respond to an action by returning an
756+
/// appropriate value from its `canPerformAction(_:withSender:)` method.
757+
public func targetViewController<Target: AnyObject>(forAction action: (Target) -> () -> Void,
758+
sender: Any?) -> ViewController? {
759+
fatalError("\(#function) not yet implemented")
760+
}
761+
762+
public func targetViewController<Target: AnyObject>(forAction action: (Target) -> (_: Any?) -> Void,
763+
sender: Any?) -> ViewController? {
764+
fatalError("\(#function) not yet implemented")
765+
}
766+
767+
/// The presentation controller that's managing the current view controller.
768+
///
769+
/// If the view controller is managed by a presentation controller, this
770+
/// property contains that object. This property is `nil` if the view
771+
/// controller isn't managed by a presentation controller.
772+
///
773+
/// If you've not yet presented the current view controller, accessing this
774+
/// property creates a presentation controller based on the current value in
775+
/// the `modalPresentationStyle` property. Always set the value of that
776+
/// property before accessing any presentation controllers.
777+
public private(set) var presentationController: PresentationController?
778+
779+
/// The nearest popover presentation controller that is managing the current view controller.
780+
///
781+
/// If the view controller or one of its ancestors is managed by a popover
782+
/// presentation controller, this property contains that object. This property
783+
/// is `nil` if the view controller is not managed by a popover presentation
784+
/// controller.
785+
///
786+
/// If you created the view controller but have not yet presented it, accessing
787+
/// this property creates a popover presentation controller when the value in
788+
/// the `modalPresentationStyle` property is `ModalPresentationStyle.popover`.
789+
/// If the modal presentation style is a different value, this property is `nil`.
790+
#if false
791+
public private(set) var popoverPresentationController: PopoverPresentationController?
792+
#endif
793+
794+
/// A boolean value that indicates whether an item that previously was focused
795+
/// should again become focused when the item's view controller becomes
796+
/// visible and focusable.
797+
///
798+
/// When the value of this property is true, the item that was last focused
799+
/// automatically becomes focused when its view controller becomes visible and
800+
/// focusable. For example, if an item in the view controller is focused and a
801+
/// second view controller is presented, the original item becomes focused
802+
/// again when the second view controller is dismissed. The default value of
803+
/// this property is `true`.
804+
public var restoresFocusAfterTransition: Bool = true
805+
711806
// MARK - Responding to Containment Events
712807

713808
/// Called just before the view controller is added or removed from a
@@ -758,6 +853,101 @@ public class ViewController: Responder {
758853
self.parent = nil
759854
}
760855

856+
/// Transitions between two of the view controller's child view controllers.
857+
///
858+
/// This method adds the second view controller's view to the view hierarchy
859+
/// and then performs the animations defined in your animations block. After
860+
/// the animation completes, it removes the first view controller's view from
861+
/// the view hierarchy.
862+
///
863+
/// This method is only intended to be called by an implementation of a custom
864+
/// container view controller. If you override this method, you must call
865+
/// `super` in your implementation.
866+
public func transition(from source: ViewController,
867+
to destination: ViewController, duration: TimeInterval,
868+
options: View.AnimationOptions = [],
869+
animations: (() -> Void)?,
870+
completion: ((Bool) -> Void)? = nil) {
871+
fatalError("\(#function) not yet implemented")
872+
}
873+
874+
/// Returns a boolean value indicating whether appearance methods are
875+
/// forwarded to child view controllers.
876+
///
877+
/// This method is called to determine whether to automatically forward
878+
/// appearance-related containment callbacks to child view controllers.
879+
///
880+
/// The default implementation returns true. Subclasses of the `ViewController`
881+
/// class that implement containment logic may override this method to control
882+
/// how these methods are forwarded. If you override this method and return
883+
/// `false`, you are responsible for telling the child when its views are going
884+
/// to appear or disappear. You do this by calling the child view controller's
885+
/// `beginAppearanceTransition(_:animated:)` and `endAppearanceTransition()`
886+
/// methods.
887+
public private(set) var shouldAutomaticallyForwardAppearanceMethods: Bool = true
888+
889+
/// Tells a child controller its appearance is about to change.
890+
///
891+
/// If you are implementing a custom container controller, use this method to
892+
/// tell the child that its views are about to appear or disappear. Do not
893+
/// invoke `viewWillAppear(_:)`, `viewWillDisappear(_:)`, `viewDidAppear(_:)`,
894+
/// or `viewDidDisappear(_:)` directly.
895+
public func beginAppearanceTransition(_ isAppearing: Bool, animated: Bool) {
896+
fatalError("\(#function) not yet implemented")
897+
}
898+
899+
/// Tells a child controller its appearance has changed.
900+
///
901+
/// If you are implementing a custom container controller, use this method to
902+
/// tell the child that the view transition is complete.
903+
public func endAppearanceTransition() {
904+
fatalError("\(#function) not yet implemented")
905+
}
906+
907+
/// Changes the traits assigned to the specified child view controller.
908+
///
909+
/// Usually, traits are passed unmodified from the parent view controller to
910+
/// its child view controllers. When implementing a custom container view
911+
/// controller, you can use this method to change the traits of any embedded
912+
/// child view controllers to something more appropriate for your layout.
913+
/// Making such a change alters other view controller behaviors associated
914+
/// with that child. For example, modal presentations behave differently in a
915+
/// horizontally compact versus horizontally regular environment. You might
916+
/// also make such a change to force the same set of traits on the child view
917+
/// controller regardless of the actual trait environment.
918+
public func setOverrideTraitCollection(_ collection: TraitCollection?,
919+
forChild childViewController: ViewController) {
920+
fatalError("\(#function) not yet implemented")
921+
}
922+
923+
/// Retrieves the trait collection for a child view controller.
924+
///
925+
/// Use this method to retrieve the trait collection for a child view
926+
/// controller. You can then modify the trait collection for the designated
927+
/// child view controller and set it using the
928+
/// `setOverrideTraitCollection(_:forChild:)` method.
929+
public func overrideTraitCollection(forChild childViewController: ViewController)
930+
-> TraitCollection? {
931+
fatalError("\(#function) not yet implemented")
932+
}
933+
934+
/// Raised if the view controller hierarchy is inconsistent with the view
935+
/// hierarchy.
936+
///
937+
/// When a view controller's view is added to the view hierarchy, the system
938+
/// walks up the view hierarchy to find the first parent view that has a view
939+
/// controller. That view controller must be the parent of the view controller
940+
/// whose view is being added. Otherwise, this exception is raised. This
941+
/// consistency check is also performed when a view controller is added as a
942+
/// child by calling the `addChild(_:)` method.
943+
///
944+
/// It is also allowed for a view controller that has no parent to add its
945+
/// view to the view hierarchy. This is generally not recommended, but is
946+
/// useful in some special cases.
947+
public class var hierarchyInconsistencyException: NSExceptionName {
948+
NSExceptionName(rawValue: "UIViewControllerHierarchyInconsistencyException")
949+
}
950+
761951
// MARK - Getting Other Related View Controllers
762952

763953
/// The view controller that presented this view controller.
@@ -844,3 +1034,30 @@ extension ViewController: ContentContainer {
8441034
public func systemLayoutFittingSizeDidChange(forChildContentContainer container: ContentContainer) {
8451035
}
8461036
}
1037+
1038+
extension ViewController: TraitEnvironment {
1039+
public var traitCollection: TraitCollection {
1040+
// The first item in the chain provides the base trait collection.
1041+
var traits: TraitCollection =
1042+
self.parent?.traitCollection
1043+
?? self.view.superview?.traitCollection
1044+
?? (self.view as? Window)?.traitCollection
1045+
?? TraitCollection()
1046+
1047+
// The parent view controller may provide overrides for the controller.
1048+
if let overrides = self.parent?.overrideTraitCollection(forChild: self) {
1049+
traits = TraitCollection(traitsFrom: [traits, overrides])
1050+
}
1051+
1052+
// The presentation controller may further override the traits.
1053+
if let overrides = self.presentationController?.overrideTraitCollection {
1054+
traits = TraitCollection(traitsFrom: [traits, overrides])
1055+
}
1056+
1057+
return traits
1058+
}
1059+
1060+
public func traitCollectionDidChange(_ previousTraitCollection: TraitCollection?) {
1061+
// extension point for derived types
1062+
}
1063+
}

0 commit comments

Comments
 (0)