mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-17 03:40:18 +00:00
no message
This commit is contained in:
parent
a4de6e5fb6
commit
124e621ee2
@ -44,7 +44,7 @@
|
|||||||
D05CC26E1B69316F00E235A3 /* Display.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D05CC2631B69316F00E235A3 /* Display.framework */; };
|
D05CC26E1B69316F00E235A3 /* Display.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D05CC2631B69316F00E235A3 /* Display.framework */; };
|
||||||
D05CC2731B69316F00E235A3 /* DisplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2721B69316F00E235A3 /* DisplayTests.swift */; };
|
D05CC2731B69316F00E235A3 /* DisplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2721B69316F00E235A3 /* DisplayTests.swift */; };
|
||||||
D05CC2A01B69326400E235A3 /* NavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC29F1B69326400E235A3 /* NavigationController.swift */; };
|
D05CC2A01B69326400E235A3 /* NavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC29F1B69326400E235A3 /* NavigationController.swift */; };
|
||||||
D05CC2A21B69326C00E235A3 /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2A11B69326C00E235A3 /* Window.swift */; };
|
D05CC2A21B69326C00E235A3 /* WindowContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2A11B69326C00E235A3 /* WindowContent.swift */; };
|
||||||
D05CC2E31B69552C00E235A3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2E21B69552C00E235A3 /* ViewController.swift */; };
|
D05CC2E31B69552C00E235A3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2E21B69552C00E235A3 /* ViewController.swift */; };
|
||||||
D05CC2E71B69555800E235A3 /* CAAnimationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2E41B69555800E235A3 /* CAAnimationUtils.swift */; };
|
D05CC2E71B69555800E235A3 /* CAAnimationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2E41B69555800E235A3 /* CAAnimationUtils.swift */; };
|
||||||
D05CC2EC1B69558A00E235A3 /* RuntimeUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2EA1B69558A00E235A3 /* RuntimeUtils.m */; };
|
D05CC2EC1B69558A00E235A3 /* RuntimeUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = D05CC2EA1B69558A00E235A3 /* RuntimeUtils.m */; };
|
||||||
@ -82,10 +82,12 @@
|
|||||||
D08E903C1D2417E000533158 /* ActionSheetButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E903B1D2417E000533158 /* ActionSheetButtonItem.swift */; };
|
D08E903C1D2417E000533158 /* ActionSheetButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E903B1D2417E000533158 /* ActionSheetButtonItem.swift */; };
|
||||||
D08E903E1D24187900533158 /* ActionSheetItemGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E903D1D24187900533158 /* ActionSheetItemGroup.swift */; };
|
D08E903E1D24187900533158 /* ActionSheetItemGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E903D1D24187900533158 /* ActionSheetItemGroup.swift */; };
|
||||||
D08E90471D243C2F00533158 /* HighlightTrackingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E90461D243C2F00533158 /* HighlightTrackingButton.swift */; };
|
D08E90471D243C2F00533158 /* HighlightTrackingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08E90461D243C2F00533158 /* HighlightTrackingButton.swift */; };
|
||||||
|
D096A4501EA64F580000A7AE /* ActionSheetCheckboxItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D096A44F1EA64F580000A7AE /* ActionSheetCheckboxItem.swift */; };
|
||||||
D0A749951E3A9E7B00AD786E /* SwitchNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A749941E3A9E7B00AD786E /* SwitchNode.swift */; };
|
D0A749951E3A9E7B00AD786E /* SwitchNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A749941E3A9E7B00AD786E /* SwitchNode.swift */; };
|
||||||
D0AE2CA61C94548900F2FD3C /* GenerateImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE2CA51C94548900F2FD3C /* GenerateImage.swift */; };
|
D0AE2CA61C94548900F2FD3C /* GenerateImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE2CA51C94548900F2FD3C /* GenerateImage.swift */; };
|
||||||
D0AE3D4D1D25C816001CCE13 /* NavigationBarTransitionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE3D4C1D25C816001CCE13 /* NavigationBarTransitionState.swift */; };
|
D0AE3D4D1D25C816001CCE13 /* NavigationBarTransitionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE3D4C1D25C816001CCE13 /* NavigationBarTransitionState.swift */; };
|
||||||
D0B367201C94A53A00346D2E /* StatusBarProxyNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B3671F1C94A53A00346D2E /* StatusBarProxyNode.swift */; };
|
D0B367201C94A53A00346D2E /* StatusBarProxyNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B3671F1C94A53A00346D2E /* StatusBarProxyNode.swift */; };
|
||||||
|
D0BE93191E8ED71100DCC1E6 /* NativeWindowHostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE93181E8ED71100DCC1E6 /* NativeWindowHostView.swift */; };
|
||||||
D0C0D28F1C997110001D2851 /* FBAnimationPerformanceTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C0D28D1C997110001D2851 /* FBAnimationPerformanceTracker.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D0C0D28F1C997110001D2851 /* FBAnimationPerformanceTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C0D28D1C997110001D2851 /* FBAnimationPerformanceTracker.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
D0C0D2901C997110001D2851 /* FBAnimationPerformanceTracker.mm in Sources */ = {isa = PBXBuildFile; fileRef = D0C0D28E1C997110001D2851 /* FBAnimationPerformanceTracker.mm */; };
|
D0C0D2901C997110001D2851 /* FBAnimationPerformanceTracker.mm in Sources */ = {isa = PBXBuildFile; fileRef = D0C0D28E1C997110001D2851 /* FBAnimationPerformanceTracker.mm */; };
|
||||||
D0C2DFC61CC4431D0044FF83 /* ASTransformLayerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C2DFBB1CC4431D0044FF83 /* ASTransformLayerNode.swift */; };
|
D0C2DFC61CC4431D0044FF83 /* ASTransformLayerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C2DFBB1CC4431D0044FF83 /* ASTransformLayerNode.swift */; };
|
||||||
@ -102,7 +104,6 @@
|
|||||||
D0C85DD01D1C082E00124894 /* ActionSheetItemGroupsContainerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C85DCF1D1C082E00124894 /* ActionSheetItemGroupsContainerNode.swift */; };
|
D0C85DD01D1C082E00124894 /* ActionSheetItemGroupsContainerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C85DCF1D1C082E00124894 /* ActionSheetItemGroupsContainerNode.swift */; };
|
||||||
D0C85DD21D1C08AE00124894 /* ActionSheetItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C85DD11D1C08AE00124894 /* ActionSheetItemNode.swift */; };
|
D0C85DD21D1C08AE00124894 /* ActionSheetItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C85DD11D1C08AE00124894 /* ActionSheetItemNode.swift */; };
|
||||||
D0C85DD41D1C1E6A00124894 /* ActionSheetItemGroupNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C85DD31D1C1E6A00124894 /* ActionSheetItemGroupNode.swift */; };
|
D0C85DD41D1C1E6A00124894 /* ActionSheetItemGroupNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C85DD31D1C1E6A00124894 /* ActionSheetItemGroupNode.swift */; };
|
||||||
D0C85DD61D1C600D00124894 /* ActionSheetButtonNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C85DD51D1C600D00124894 /* ActionSheetButtonNode.swift */; };
|
|
||||||
D0CD12161CCFEB4E000DE7BC /* ScrollToTopProxyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CD12151CCFEB4E000DE7BC /* ScrollToTopProxyView.swift */; };
|
D0CD12161CCFEB4E000DE7BC /* ScrollToTopProxyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CD12151CCFEB4E000DE7BC /* ScrollToTopProxyView.swift */; };
|
||||||
D0D94A171D3814F900740E02 /* UniversalTapRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D94A161D3814F900740E02 /* UniversalTapRecognizer.swift */; };
|
D0D94A171D3814F900740E02 /* UniversalTapRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D94A161D3814F900740E02 /* UniversalTapRecognizer.swift */; };
|
||||||
D0DA444C1E4DCA4A005FDCA7 /* AlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DA444B1E4DCA4A005FDCA7 /* AlertController.swift */; };
|
D0DA444C1E4DCA4A005FDCA7 /* AlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DA444B1E4DCA4A005FDCA7 /* AlertController.swift */; };
|
||||||
@ -171,7 +172,7 @@
|
|||||||
D05CC2721B69316F00E235A3 /* DisplayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayTests.swift; sourceTree = "<group>"; };
|
D05CC2721B69316F00E235A3 /* DisplayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayTests.swift; sourceTree = "<group>"; };
|
||||||
D05CC2741B69316F00E235A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
D05CC2741B69316F00E235A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
D05CC29F1B69326400E235A3 /* NavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationController.swift; sourceTree = "<group>"; };
|
D05CC29F1B69326400E235A3 /* NavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationController.swift; sourceTree = "<group>"; };
|
||||||
D05CC2A11B69326C00E235A3 /* Window.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Window.swift; sourceTree = "<group>"; };
|
D05CC2A11B69326C00E235A3 /* WindowContent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WindowContent.swift; sourceTree = "<group>"; };
|
||||||
D05CC2E21B69552C00E235A3 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
D05CC2E21B69552C00E235A3 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||||
D05CC2E41B69555800E235A3 /* CAAnimationUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAAnimationUtils.swift; sourceTree = "<group>"; };
|
D05CC2E41B69555800E235A3 /* CAAnimationUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAAnimationUtils.swift; sourceTree = "<group>"; };
|
||||||
D05CC2EA1B69558A00E235A3 /* RuntimeUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuntimeUtils.m; sourceTree = "<group>"; };
|
D05CC2EA1B69558A00E235A3 /* RuntimeUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuntimeUtils.m; sourceTree = "<group>"; };
|
||||||
@ -209,10 +210,12 @@
|
|||||||
D08E903B1D2417E000533158 /* ActionSheetButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetButtonItem.swift; sourceTree = "<group>"; };
|
D08E903B1D2417E000533158 /* ActionSheetButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetButtonItem.swift; sourceTree = "<group>"; };
|
||||||
D08E903D1D24187900533158 /* ActionSheetItemGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetItemGroup.swift; sourceTree = "<group>"; };
|
D08E903D1D24187900533158 /* ActionSheetItemGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetItemGroup.swift; sourceTree = "<group>"; };
|
||||||
D08E90461D243C2F00533158 /* HighlightTrackingButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighlightTrackingButton.swift; sourceTree = "<group>"; };
|
D08E90461D243C2F00533158 /* HighlightTrackingButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighlightTrackingButton.swift; sourceTree = "<group>"; };
|
||||||
|
D096A44F1EA64F580000A7AE /* ActionSheetCheckboxItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetCheckboxItem.swift; sourceTree = "<group>"; };
|
||||||
D0A749941E3A9E7B00AD786E /* SwitchNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwitchNode.swift; sourceTree = "<group>"; };
|
D0A749941E3A9E7B00AD786E /* SwitchNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwitchNode.swift; sourceTree = "<group>"; };
|
||||||
D0AE2CA51C94548900F2FD3C /* GenerateImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenerateImage.swift; sourceTree = "<group>"; };
|
D0AE2CA51C94548900F2FD3C /* GenerateImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenerateImage.swift; sourceTree = "<group>"; };
|
||||||
D0AE3D4C1D25C816001CCE13 /* NavigationBarTransitionState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationBarTransitionState.swift; sourceTree = "<group>"; };
|
D0AE3D4C1D25C816001CCE13 /* NavigationBarTransitionState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationBarTransitionState.swift; sourceTree = "<group>"; };
|
||||||
D0B3671F1C94A53A00346D2E /* StatusBarProxyNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarProxyNode.swift; sourceTree = "<group>"; };
|
D0B3671F1C94A53A00346D2E /* StatusBarProxyNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarProxyNode.swift; sourceTree = "<group>"; };
|
||||||
|
D0BE93181E8ED71100DCC1E6 /* NativeWindowHostView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NativeWindowHostView.swift; sourceTree = "<group>"; };
|
||||||
D0C0D28D1C997110001D2851 /* FBAnimationPerformanceTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBAnimationPerformanceTracker.h; sourceTree = "<group>"; };
|
D0C0D28D1C997110001D2851 /* FBAnimationPerformanceTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBAnimationPerformanceTracker.h; sourceTree = "<group>"; };
|
||||||
D0C0D28E1C997110001D2851 /* FBAnimationPerformanceTracker.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FBAnimationPerformanceTracker.mm; sourceTree = "<group>"; };
|
D0C0D28E1C997110001D2851 /* FBAnimationPerformanceTracker.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FBAnimationPerformanceTracker.mm; sourceTree = "<group>"; };
|
||||||
D0C2DFBB1CC4431D0044FF83 /* ASTransformLayerNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASTransformLayerNode.swift; sourceTree = "<group>"; };
|
D0C2DFBB1CC4431D0044FF83 /* ASTransformLayerNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASTransformLayerNode.swift; sourceTree = "<group>"; };
|
||||||
@ -229,7 +232,6 @@
|
|||||||
D0C85DCF1D1C082E00124894 /* ActionSheetItemGroupsContainerNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetItemGroupsContainerNode.swift; sourceTree = "<group>"; };
|
D0C85DCF1D1C082E00124894 /* ActionSheetItemGroupsContainerNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetItemGroupsContainerNode.swift; sourceTree = "<group>"; };
|
||||||
D0C85DD11D1C08AE00124894 /* ActionSheetItemNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetItemNode.swift; sourceTree = "<group>"; };
|
D0C85DD11D1C08AE00124894 /* ActionSheetItemNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetItemNode.swift; sourceTree = "<group>"; };
|
||||||
D0C85DD31D1C1E6A00124894 /* ActionSheetItemGroupNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetItemGroupNode.swift; sourceTree = "<group>"; };
|
D0C85DD31D1C1E6A00124894 /* ActionSheetItemGroupNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetItemGroupNode.swift; sourceTree = "<group>"; };
|
||||||
D0C85DD51D1C600D00124894 /* ActionSheetButtonNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetButtonNode.swift; sourceTree = "<group>"; };
|
|
||||||
D0CD12151CCFEB4E000DE7BC /* ScrollToTopProxyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollToTopProxyView.swift; sourceTree = "<group>"; };
|
D0CD12151CCFEB4E000DE7BC /* ScrollToTopProxyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollToTopProxyView.swift; sourceTree = "<group>"; };
|
||||||
D0D94A161D3814F900740E02 /* UniversalTapRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalTapRecognizer.swift; sourceTree = "<group>"; };
|
D0D94A161D3814F900740E02 /* UniversalTapRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalTapRecognizer.swift; sourceTree = "<group>"; };
|
||||||
D0DA444B1E4DCA4A005FDCA7 /* AlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertController.swift; sourceTree = "<group>"; };
|
D0DA444B1E4DCA4A005FDCA7 /* AlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertController.swift; sourceTree = "<group>"; };
|
||||||
@ -272,7 +274,8 @@
|
|||||||
D015F7501D1ADC6800E269B5 /* Window */ = {
|
D015F7501D1ADC6800E269B5 /* Window */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D05CC2A11B69326C00E235A3 /* Window.swift */,
|
D05CC2A11B69326C00E235A3 /* WindowContent.swift */,
|
||||||
|
D0BE93181E8ED71100DCC1E6 /* NativeWindowHostView.swift */,
|
||||||
);
|
);
|
||||||
name = Window;
|
name = Window;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -298,7 +301,7 @@
|
|||||||
D08E90391D24159200533158 /* ActionSheetItem.swift */,
|
D08E90391D24159200533158 /* ActionSheetItem.swift */,
|
||||||
D08E903D1D24187900533158 /* ActionSheetItemGroup.swift */,
|
D08E903D1D24187900533158 /* ActionSheetItemGroup.swift */,
|
||||||
D08E903B1D2417E000533158 /* ActionSheetButtonItem.swift */,
|
D08E903B1D2417E000533158 /* ActionSheetButtonItem.swift */,
|
||||||
D0C85DD51D1C600D00124894 /* ActionSheetButtonNode.swift */,
|
D096A44F1EA64F580000A7AE /* ActionSheetCheckboxItem.swift */,
|
||||||
);
|
);
|
||||||
name = "Action Sheet";
|
name = "Action Sheet";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -737,6 +740,7 @@
|
|||||||
D05CC2A01B69326400E235A3 /* NavigationController.swift in Sources */,
|
D05CC2A01B69326400E235A3 /* NavigationController.swift in Sources */,
|
||||||
D06EE8451B7140FF00837186 /* Font.swift in Sources */,
|
D06EE8451B7140FF00837186 /* Font.swift in Sources */,
|
||||||
D0C2DFCB1CC4431D0044FF83 /* ListViewAnimation.swift in Sources */,
|
D0C2DFCB1CC4431D0044FF83 /* ListViewAnimation.swift in Sources */,
|
||||||
|
D0BE93191E8ED71100DCC1E6 /* NativeWindowHostView.swift in Sources */,
|
||||||
D05CC3251B695B0700E235A3 /* NavigationBarProxy.m in Sources */,
|
D05CC3251B695B0700E235A3 /* NavigationBarProxy.m in Sources */,
|
||||||
D03E7DE61C96B96E00C07816 /* NavigationBarTransitionContainer.swift in Sources */,
|
D03E7DE61C96B96E00C07816 /* NavigationBarTransitionContainer.swift in Sources */,
|
||||||
D0C85DD01D1C082E00124894 /* ActionSheetItemGroupsContainerNode.swift in Sources */,
|
D0C85DD01D1C082E00124894 /* ActionSheetItemGroupsContainerNode.swift in Sources */,
|
||||||
@ -746,7 +750,6 @@
|
|||||||
D05CC31D1B695A9600E235A3 /* UIBarButtonItem+Proxy.m in Sources */,
|
D05CC31D1B695A9600E235A3 /* UIBarButtonItem+Proxy.m in Sources */,
|
||||||
D01E2BDE1D9049620066BF65 /* GridNode.swift in Sources */,
|
D01E2BDE1D9049620066BF65 /* GridNode.swift in Sources */,
|
||||||
D01E2BE01D90498E0066BF65 /* GridNodeScroller.swift in Sources */,
|
D01E2BE01D90498E0066BF65 /* GridNodeScroller.swift in Sources */,
|
||||||
D0C85DD61D1C600D00124894 /* ActionSheetButtonNode.swift in Sources */,
|
|
||||||
D0C2DFD01CC4431D0044FF83 /* ListViewAccessoryItemNode.swift in Sources */,
|
D0C2DFD01CC4431D0044FF83 /* ListViewAccessoryItemNode.swift in Sources */,
|
||||||
D0DA44501E4DCBDE005FDCA7 /* AlertContentNode.swift in Sources */,
|
D0DA44501E4DCBDE005FDCA7 /* AlertContentNode.swift in Sources */,
|
||||||
D0D94A171D3814F900740E02 /* UniversalTapRecognizer.swift in Sources */,
|
D0D94A171D3814F900740E02 /* UniversalTapRecognizer.swift in Sources */,
|
||||||
@ -772,6 +775,7 @@
|
|||||||
D00C7CD21E3657570080C3D5 /* TextFieldNode.swift in Sources */,
|
D00C7CD21E3657570080C3D5 /* TextFieldNode.swift in Sources */,
|
||||||
D0DC485F1BF949FB00F672FD /* TabBarContollerNode.swift in Sources */,
|
D0DC485F1BF949FB00F672FD /* TabBarContollerNode.swift in Sources */,
|
||||||
D05CC2FA1B6955D000E235A3 /* UINavigationItem+Proxy.m in Sources */,
|
D05CC2FA1B6955D000E235A3 /* UINavigationItem+Proxy.m in Sources */,
|
||||||
|
D096A4501EA64F580000A7AE /* ActionSheetCheckboxItem.swift in Sources */,
|
||||||
D0C2DFCE1CC4431D0044FF83 /* ListViewAccessoryItem.swift in Sources */,
|
D0C2DFCE1CC4431D0044FF83 /* ListViewAccessoryItem.swift in Sources */,
|
||||||
D0A749951E3A9E7B00AD786E /* SwitchNode.swift in Sources */,
|
D0A749951E3A9E7B00AD786E /* SwitchNode.swift in Sources */,
|
||||||
D03725C51D6DF8B9007FC290 /* ContextMenuController.swift in Sources */,
|
D03725C51D6DF8B9007FC290 /* ContextMenuController.swift in Sources */,
|
||||||
@ -806,7 +810,7 @@
|
|||||||
D02383861DE0E3B4004018B6 /* ListViewIntermediateState.swift in Sources */,
|
D02383861DE0E3B4004018B6 /* ListViewIntermediateState.swift in Sources */,
|
||||||
D0DA444E1E4DCA6E005FDCA7 /* AlertControllerNode.swift in Sources */,
|
D0DA444E1E4DCA6E005FDCA7 /* AlertControllerNode.swift in Sources */,
|
||||||
D0B367201C94A53A00346D2E /* StatusBarProxyNode.swift in Sources */,
|
D0B367201C94A53A00346D2E /* StatusBarProxyNode.swift in Sources */,
|
||||||
D05CC2A21B69326C00E235A3 /* Window.swift in Sources */,
|
D05CC2A21B69326C00E235A3 /* WindowContent.swift in Sources */,
|
||||||
D015F7541D1B0F6C00E269B5 /* SystemContainedControllerTransitionCoordinator.swift in Sources */,
|
D015F7541D1B0F6C00E269B5 /* SystemContainedControllerTransitionCoordinator.swift in Sources */,
|
||||||
D05CC3151B695A9600E235A3 /* NavigationTransitionCoordinator.swift in Sources */,
|
D05CC3151B695A9600E235A3 /* NavigationTransitionCoordinator.swift in Sources */,
|
||||||
D03B0E701D6331FB00955575 /* StatusBarHost.swift in Sources */,
|
D03B0E701D6331FB00955575 /* StatusBarHost.swift in Sources */,
|
||||||
|
|||||||
@ -1,24 +1,116 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
import AsyncDisplayKit
|
||||||
|
|
||||||
public enum ActionSheetButtonColor {
|
public enum ActionSheetButtonColor {
|
||||||
case accent
|
case accent
|
||||||
case destructive
|
case destructive
|
||||||
|
case disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ActionSheetButtonItem: ActionSheetItem {
|
public class ActionSheetButtonItem: ActionSheetItem {
|
||||||
public let title: String
|
public let title: String
|
||||||
public let color: ActionSheetButtonColor
|
public let color: ActionSheetButtonColor
|
||||||
|
public let enabled: Bool
|
||||||
public let action: () -> Void
|
public let action: () -> Void
|
||||||
|
|
||||||
public init(title: String, color: ActionSheetButtonColor = .accent, action: @escaping () -> Void) {
|
public init(title: String, color: ActionSheetButtonColor = .accent, enabled: Bool = true, action: @escaping () -> Void) {
|
||||||
self.title = title
|
self.title = title
|
||||||
self.color = color
|
self.color = color
|
||||||
|
self.enabled = enabled
|
||||||
self.action = action
|
self.action = action
|
||||||
}
|
}
|
||||||
|
|
||||||
public func node() -> ActionSheetItemNode {
|
public func node() -> ActionSheetItemNode {
|
||||||
let textColorIsAccent = self.color == ActionSheetButtonColor.accent
|
let node = ActionSheetButtonNode()
|
||||||
let textColor = textColorIsAccent ? UIColor(0x007ee5) : UIColor.red
|
node.setItem(self)
|
||||||
return ActionSheetButtonNode(title: NSAttributedString(string: title, font: ActionSheetButtonNode.defaultFont, textColor: textColor), action: self.action)
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateNode(_ node: ActionSheetItemNode) {
|
||||||
|
guard let node = node as? ActionSheetButtonNode else {
|
||||||
|
assertionFailure()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
node.setItem(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ActionSheetButtonNode: ActionSheetItemNode {
|
||||||
|
public static let defaultFont: UIFont = Font.regular(20.0)
|
||||||
|
|
||||||
|
private var item: ActionSheetButtonItem?
|
||||||
|
|
||||||
|
private let button: HighlightTrackingButton
|
||||||
|
private let label: ASTextNode
|
||||||
|
|
||||||
|
override public init() {
|
||||||
|
self.button = HighlightTrackingButton()
|
||||||
|
|
||||||
|
self.label = ASTextNode()
|
||||||
|
self.label.isLayerBacked = true
|
||||||
|
self.label.maximumNumberOfLines = 1
|
||||||
|
self.label.displaysAsynchronously = false
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.view.addSubview(self.button)
|
||||||
|
|
||||||
|
self.label.isUserInteractionEnabled = false
|
||||||
|
self.addSubnode(self.label)
|
||||||
|
|
||||||
|
self.button.highligthedChanged = { [weak self] highlighted in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if highlighted {
|
||||||
|
strongSelf.backgroundNode.backgroundColor = ActionSheetItemNode.highlightedBackgroundColor
|
||||||
|
} else {
|
||||||
|
UIView.animate(withDuration: 0.3, animations: {
|
||||||
|
strongSelf.backgroundNode.backgroundColor = ActionSheetItemNode.defaultBackgroundColor
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.button.addTarget(self, action: #selector(self.buttonPressed), for: .touchUpInside)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setItem(_ item: ActionSheetButtonItem) {
|
||||||
|
self.item = item
|
||||||
|
|
||||||
|
let textColor: UIColor
|
||||||
|
switch item.color {
|
||||||
|
case .accent:
|
||||||
|
textColor = UIColor(0x007ee5)
|
||||||
|
case .destructive:
|
||||||
|
textColor = .red
|
||||||
|
case .disabled:
|
||||||
|
textColor = .gray
|
||||||
|
}
|
||||||
|
self.label.attributedText = NSAttributedString(string: item.title, font: ActionSheetButtonNode.defaultFont, textColor: textColor)
|
||||||
|
|
||||||
|
self.button.isEnabled = item.enabled
|
||||||
|
|
||||||
|
self.setNeedsLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
||||||
|
return CGSize(width: constrainedSize.width, height: 57.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func layout() {
|
||||||
|
super.layout()
|
||||||
|
|
||||||
|
let size = self.bounds.size
|
||||||
|
|
||||||
|
self.button.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
|
|
||||||
|
let labelSize = self.label.measure(size)
|
||||||
|
self.label.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - labelSize.width) / 2.0), y: floorToScreenPixels((size.height - labelSize.height) / 2.0)), size: labelSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func buttonPressed() {
|
||||||
|
if let item = self.item {
|
||||||
|
item.action()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,63 +0,0 @@
|
|||||||
import UIKit
|
|
||||||
import AsyncDisplayKit
|
|
||||||
|
|
||||||
public class ActionSheetButtonNode: ActionSheetItemNode {
|
|
||||||
public static let defaultFont: UIFont = Font.regular(20.0)
|
|
||||||
|
|
||||||
private let action: () -> Void
|
|
||||||
|
|
||||||
private let button: HighlightTrackingButton
|
|
||||||
private let label: UILabel
|
|
||||||
private var calculatedLabelSize: CGSize?
|
|
||||||
|
|
||||||
public init(title: NSAttributedString, action: @escaping () -> Void) {
|
|
||||||
self.action = action
|
|
||||||
|
|
||||||
self.button = HighlightTrackingButton()
|
|
||||||
self.label = UILabel()
|
|
||||||
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
self.view.addSubview(self.button)
|
|
||||||
|
|
||||||
self.label.attributedText = title
|
|
||||||
self.label.numberOfLines = 1
|
|
||||||
self.label.isUserInteractionEnabled = false
|
|
||||||
self.view.addSubview(self.label)
|
|
||||||
|
|
||||||
self.button.highligthedChanged = { [weak self] highlighted in
|
|
||||||
if let strongSelf = self {
|
|
||||||
if highlighted {
|
|
||||||
strongSelf.backgroundNode.backgroundColor = ActionSheetItemNode.highlightedBackgroundColor
|
|
||||||
} else {
|
|
||||||
UIView.animate(withDuration: 0.3, animations: {
|
|
||||||
strongSelf.backgroundNode.backgroundColor = ActionSheetItemNode.defaultBackgroundColor
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.button.addTarget(self, action: #selector(self.buttonPressed), for: .touchUpInside)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
|
||||||
self.label.sizeToFit()
|
|
||||||
self.calculatedLabelSize = self.label.frame.size
|
|
||||||
|
|
||||||
return CGSize(width: constrainedSize.width, height: 57.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
public override func layout() {
|
|
||||||
super.layout()
|
|
||||||
|
|
||||||
self.button.frame = CGRect(origin: CGPoint(), size: self.calculatedSize)
|
|
||||||
|
|
||||||
if let calculatedLabelSize = self.calculatedLabelSize {
|
|
||||||
self.label.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((self.calculatedSize.width - calculatedLabelSize.width) / 2.0), y: floorToScreenPixels((self.calculatedSize.height - calculatedLabelSize.height) / 2.0)), size: calculatedLabelSize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func buttonPressed() {
|
|
||||||
self.action()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
130
Display/ActionSheetCheckboxItem.swift
Normal file
130
Display/ActionSheetCheckboxItem.swift
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import Foundation
|
||||||
|
import AsyncDisplayKit
|
||||||
|
|
||||||
|
private let checkIcon = generateImage(CGSize(width: 14.0, height: 11.0), rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
context.setStrokeColor(UIColor(0x007ee5).cgColor)
|
||||||
|
context.setLineWidth(2.0)
|
||||||
|
context.move(to: CGPoint(x: 12.0, y: 1.0))
|
||||||
|
context.addLine(to: CGPoint(x: 4.16482734, y: 9.0))
|
||||||
|
context.addLine(to: CGPoint(x: 1.0, y: 5.81145833))
|
||||||
|
context.strokePath()
|
||||||
|
})
|
||||||
|
|
||||||
|
public class ActionSheetCheckboxItem: ActionSheetItem {
|
||||||
|
public let title: String
|
||||||
|
public let label: String
|
||||||
|
public let value: Bool
|
||||||
|
public let action: (Bool) -> Void
|
||||||
|
|
||||||
|
public init(title: String, label: String, value: Bool, action: @escaping (Bool) -> Void) {
|
||||||
|
self.title = title
|
||||||
|
self.label = label
|
||||||
|
self.value = value
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
|
||||||
|
public func node() -> ActionSheetItemNode {
|
||||||
|
let node = ActionSheetCheckboxItemNode()
|
||||||
|
node.setItem(self)
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateNode(_ node: ActionSheetItemNode) {
|
||||||
|
guard let node = node as? ActionSheetCheckboxItemNode else {
|
||||||
|
assertionFailure()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
node.setItem(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ActionSheetCheckboxItemNode: ActionSheetItemNode {
|
||||||
|
public static let defaultFont: UIFont = Font.regular(20.0)
|
||||||
|
|
||||||
|
private var item: ActionSheetCheckboxItem?
|
||||||
|
|
||||||
|
private let button: HighlightTrackingButton
|
||||||
|
private let titleNode: ASTextNode
|
||||||
|
private let labelNode: ASTextNode
|
||||||
|
private let checkNode: ASImageNode
|
||||||
|
|
||||||
|
public override init() {
|
||||||
|
self.button = HighlightTrackingButton()
|
||||||
|
|
||||||
|
self.titleNode = ASTextNode()
|
||||||
|
self.titleNode.maximumNumberOfLines = 1
|
||||||
|
self.titleNode.isUserInteractionEnabled = false
|
||||||
|
self.titleNode.displaysAsynchronously = false
|
||||||
|
|
||||||
|
self.labelNode = ASTextNode()
|
||||||
|
self.labelNode.maximumNumberOfLines = 1
|
||||||
|
self.labelNode.isUserInteractionEnabled = false
|
||||||
|
self.labelNode.displaysAsynchronously = false
|
||||||
|
|
||||||
|
self.checkNode = ASImageNode()
|
||||||
|
self.checkNode.isUserInteractionEnabled = false
|
||||||
|
self.checkNode.displayWithoutProcessing = true
|
||||||
|
self.checkNode.displaysAsynchronously = false
|
||||||
|
self.checkNode.image = checkIcon
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.view.addSubview(self.button)
|
||||||
|
self.addSubnode(self.titleNode)
|
||||||
|
self.addSubnode(self.labelNode)
|
||||||
|
self.addSubnode(self.checkNode)
|
||||||
|
|
||||||
|
self.button.highligthedChanged = { [weak self] highlighted in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if highlighted {
|
||||||
|
strongSelf.backgroundNode.backgroundColor = ActionSheetItemNode.highlightedBackgroundColor
|
||||||
|
} else {
|
||||||
|
UIView.animate(withDuration: 0.3, animations: {
|
||||||
|
strongSelf.backgroundNode.backgroundColor = ActionSheetItemNode.defaultBackgroundColor
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.button.addTarget(self, action: #selector(self.buttonPressed), for: .touchUpInside)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setItem(_ item: ActionSheetCheckboxItem) {
|
||||||
|
self.item = item
|
||||||
|
|
||||||
|
self.titleNode.attributedText = NSAttributedString(string: item.title, font: ActionSheetCheckboxItemNode.defaultFont, textColor: .black)
|
||||||
|
self.labelNode.attributedText = NSAttributedString(string: item.label, font: ActionSheetCheckboxItemNode.defaultFont, textColor: UIColor(0x8e8e93))
|
||||||
|
self.checkNode.isHidden = !item.value
|
||||||
|
|
||||||
|
self.setNeedsLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
||||||
|
return CGSize(width: constrainedSize.width, height: 57.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func layout() {
|
||||||
|
super.layout()
|
||||||
|
|
||||||
|
let size = self.bounds.size
|
||||||
|
|
||||||
|
self.button.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
|
|
||||||
|
let labelSize = self.labelNode.measure(CGSize(width: size.width - 44.0 - 15.0 - 8.0, height: size.height))
|
||||||
|
let titleSize = self.titleNode.measure(CGSize(width: size.width - 44.0 - labelSize.width - 15.0 - 8.0, height: size.height))
|
||||||
|
self.titleNode.frame = CGRect(origin: CGPoint(x: 44.0, y: floorToScreenPixels((size.height - titleSize.height) / 2.0)), size: titleSize)
|
||||||
|
self.labelNode.frame = CGRect(origin: CGPoint(x: size.width - 15.0 - labelSize.width, y: floorToScreenPixels((size.height - labelSize.height) / 2.0)), size: labelSize)
|
||||||
|
|
||||||
|
if let image = self.checkNode.image {
|
||||||
|
self.checkNode.frame = CGRect(origin: CGPoint(x: floor((44.0 - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func buttonPressed() {
|
||||||
|
if let item = self.item {
|
||||||
|
item.action(!item.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -49,4 +49,10 @@ open class ActionSheetController: ViewController {
|
|||||||
self.actionSheetNode.setGroups(groups)
|
self.actionSheetNode.setGroups(groups)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func updateItem(groupIndex: Int, itemIndex: Int, _ f: (ActionSheetItem) -> ActionSheetItem) {
|
||||||
|
if self.isViewLoaded {
|
||||||
|
self.actionSheetNode.updateItem(groupIndex: groupIndex, itemIndex: itemIndex, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -155,4 +155,8 @@ final class ActionSheetControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
func setGroups(_ groups: [ActionSheetItemGroup]) {
|
func setGroups(_ groups: [ActionSheetItemGroup]) {
|
||||||
self.itemGroupsContainerNode.setGroups(groups)
|
self.itemGroupsContainerNode.setGroups(groups)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func updateItem(groupIndex: Int, itemIndex: Int, _ f: (ActionSheetItem) -> ActionSheetItem) {
|
||||||
|
self.itemGroupsContainerNode.updateItem(groupIndex: groupIndex, itemIndex: itemIndex, f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,4 +2,5 @@ import Foundation
|
|||||||
|
|
||||||
public protocol ActionSheetItem {
|
public protocol ActionSheetItem {
|
||||||
func node() -> ActionSheetItemNode
|
func node() -> ActionSheetItemNode
|
||||||
|
func updateNode(_ node: ActionSheetItemNode) -> Void
|
||||||
}
|
}
|
||||||
|
|||||||
@ -209,4 +209,8 @@ final class ActionSheetItemGroupNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
node.layer.animateAlpha(from: from, to: to, duration: duration)
|
node.layer.animateAlpha(from: from, to: to, duration: duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func itemNode(at index: Int) -> ActionSheetItemNode {
|
||||||
|
return self.itemNodes[index]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import AsyncDisplayKit
|
|||||||
private let groupSpacing: CGFloat = 16.0
|
private let groupSpacing: CGFloat = 16.0
|
||||||
|
|
||||||
final class ActionSheetItemGroupsContainerNode: ASDisplayNode {
|
final class ActionSheetItemGroupsContainerNode: ASDisplayNode {
|
||||||
|
private var groups: [ActionSheetItemGroup] = []
|
||||||
private var groupNodes: [ActionSheetItemGroupNode] = []
|
private var groupNodes: [ActionSheetItemGroupNode] = []
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
@ -11,6 +12,8 @@ final class ActionSheetItemGroupsContainerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setGroups(_ groups: [ActionSheetItemGroup]) {
|
func setGroups(_ groups: [ActionSheetItemGroup]) {
|
||||||
|
self.groups = groups
|
||||||
|
|
||||||
for groupNode in self.groupNodes {
|
for groupNode in self.groupNodes {
|
||||||
groupNode.removeFromSupernode()
|
groupNode.removeFromSupernode()
|
||||||
}
|
}
|
||||||
@ -72,4 +75,16 @@ final class ActionSheetItemGroupsContainerNode: ASDisplayNode {
|
|||||||
node.animateDimViewsAlpha(from: from, to: to, duration: duration)
|
node.animateDimViewsAlpha(from: from, to: to, duration: duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func updateItem(groupIndex: Int, itemIndex: Int, _ f: (ActionSheetItem) -> ActionSheetItem) {
|
||||||
|
var item = self.groups[groupIndex].items[itemIndex]
|
||||||
|
let itemNode = self.groupNodes[groupIndex].itemNode(at: itemIndex)
|
||||||
|
item = f(item)
|
||||||
|
item.updateNode(itemNode)
|
||||||
|
|
||||||
|
var groupItems = self.groups[groupIndex].items
|
||||||
|
groupItems[itemIndex] = item
|
||||||
|
|
||||||
|
self.groups[groupIndex] = ActionSheetItemGroup(items: groupItems)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,8 +45,8 @@ open class AlertController: ViewController {
|
|||||||
self.controllerNode.containerLayoutUpdated(layout, transition: transition)
|
self.controllerNode.containerLayoutUpdated(layout, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func dismiss() {
|
override open func dismiss(completion: (() -> Void)? = nil) {
|
||||||
self.presentingViewController?.dismiss(animated: false, completion: nil)
|
self.presentingViewController?.dismiss(animated: false, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func dismissAnimated() {
|
public func dismissAnimated() {
|
||||||
|
|||||||
@ -134,8 +134,8 @@ public extension CALayer {
|
|||||||
self.add(animation, forKey: keyPath)
|
self.add(animation, forKey: keyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func animateSpring(from: AnyObject, to: AnyObject, keyPath: String, duration: Double, initialVelocity: CGFloat = 0.0, removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
public func animateSpring(from: AnyObject, to: AnyObject, keyPath: String, duration: Double, initialVelocity: CGFloat = 0.0, damping: CGFloat = 88.0, removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||||
let animation = makeSpringBounceAnimation(keyPath, initialVelocity)
|
let animation = makeSpringBounceAnimation(keyPath, initialVelocity, damping)
|
||||||
animation.fromValue = from
|
animation.fromValue = from
|
||||||
animation.toValue = to
|
animation.toValue = to
|
||||||
animation.isRemovedOnCompletion = removeOnCompletion
|
animation.isRemovedOnCompletion = removeOnCompletion
|
||||||
@ -187,8 +187,8 @@ public extension CALayer {
|
|||||||
self.animate(from: NSNumber(value: Float(from)), to: NSNumber(value: Float(to)), keyPath: "transform.scale", timingFunction: timingFunction, duration: duration, removeOnCompletion: removeOnCompletion, completion: completion)
|
self.animate(from: NSNumber(value: Float(from)), to: NSNumber(value: Float(to)), keyPath: "transform.scale", timingFunction: timingFunction, duration: duration, removeOnCompletion: removeOnCompletion, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func animatePosition(from: CGPoint, to: CGPoint, duration: Double, timingFunction: String = kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
func animatePosition(from: CGPoint, to: CGPoint, duration: Double, timingFunction: String = kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: Bool = true, additive: Bool = false, force: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||||
if from == to {
|
if from == to && !force {
|
||||||
if let completion = completion {
|
if let completion = completion {
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
@ -197,8 +197,8 @@ public extension CALayer {
|
|||||||
self.animate(from: NSValue(cgPoint: from), to: NSValue(cgPoint: to), keyPath: "position", timingFunction: timingFunction, duration: duration, removeOnCompletion: removeOnCompletion, additive: additive, completion: completion)
|
self.animate(from: NSValue(cgPoint: from), to: NSValue(cgPoint: to), keyPath: "position", timingFunction: timingFunction, duration: duration, removeOnCompletion: removeOnCompletion, additive: additive, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateBounds(from: CGRect, to: CGRect, duration: Double, timingFunction: String, removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
func animateBounds(from: CGRect, to: CGRect, duration: Double, timingFunction: String, removeOnCompletion: Bool = true, additive: Bool = false, force: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||||
if from == to {
|
if from == to && !force {
|
||||||
if let completion = completion {
|
if let completion = completion {
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
@ -219,8 +219,8 @@ public extension CALayer {
|
|||||||
self.animateKeyframes(values: values.map { NSValue(cgPoint: $0) }, duration: duration, keyPath: "position")
|
self.animateKeyframes(values: values.map { NSValue(cgPoint: $0) }, duration: duration, keyPath: "position")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func animateFrame(from: CGRect, to: CGRect, duration: Double, timingFunction: String, removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
public func animateFrame(from: CGRect, to: CGRect, duration: Double, timingFunction: String, removeOnCompletion: Bool = true, additive: Bool = false, force: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||||
if from == to {
|
if from == to && !force {
|
||||||
if let completion = completion {
|
if let completion = completion {
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
@ -236,14 +236,14 @@ public extension CALayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.animatePosition(from: CGPoint(x: from.midX, y: from.midY), to: CGPoint(x: to.midX, y: to.midY), duration: duration, timingFunction: timingFunction, removeOnCompletion: removeOnCompletion, additive: additive, completion: { value in
|
self.animatePosition(from: CGPoint(x: from.midX, y: from.midY), to: CGPoint(x: to.midX, y: to.midY), duration: duration, timingFunction: timingFunction, removeOnCompletion: removeOnCompletion, additive: additive, force: force, completion: { value in
|
||||||
if !value {
|
if !value {
|
||||||
interrupted = true
|
interrupted = true
|
||||||
}
|
}
|
||||||
completedPosition = true
|
completedPosition = true
|
||||||
partialCompletion()
|
partialCompletion()
|
||||||
})
|
})
|
||||||
self.animateBounds(from: CGRect(origin: self.bounds.origin, size: from.size), to: CGRect(origin: self.bounds.origin, size: to.size), duration: duration, timingFunction: timingFunction, removeOnCompletion: removeOnCompletion, additive: additive, completion: { value in
|
self.animateBounds(from: CGRect(origin: self.bounds.origin, size: from.size), to: CGRect(origin: self.bounds.origin, size: to.size), duration: duration, timingFunction: timingFunction, removeOnCompletion: removeOnCompletion, additive: additive, force: force, completion: { value in
|
||||||
if !value {
|
if !value {
|
||||||
interrupted = true
|
interrupted = true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -231,7 +231,41 @@ static void traceLayerSurfaces(int32_t tracingTag, int depth, CALayer * _Nonnull
|
|||||||
|
|
||||||
- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key {
|
- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key {
|
||||||
if ([anim isKindOfClass:[CABasicAnimation class]]) {
|
if ([anim isKindOfClass:[CABasicAnimation class]]) {
|
||||||
if ([key isEqualToString:@"position"]) {
|
if (false && [key isEqualToString:@"bounds.origin.y"]) {
|
||||||
|
CABasicAnimation *animCopy = [anim copy];
|
||||||
|
CGFloat from = [animCopy.fromValue floatValue];
|
||||||
|
CGFloat to = [animCopy.toValue floatValue];
|
||||||
|
|
||||||
|
animCopy.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0.0, to - from, 0.0f)];
|
||||||
|
animCopy.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
|
||||||
|
animCopy.keyPath = @"sublayerTransform";
|
||||||
|
|
||||||
|
__weak CATracingLayer *weakSelf = self;
|
||||||
|
anim.delegate = [[CATracingLayerAnimationDelegate alloc] initWithDelegate:anim.delegate animationStopped:^{
|
||||||
|
__strong CATracingLayer *strongSelf = weakSelf;
|
||||||
|
if (strongSelf != nil) {
|
||||||
|
[strongSelf invalidateUpTheTree];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[super addAnimation:anim forKey:key];
|
||||||
|
|
||||||
|
CABasicAnimation *positionAnimCopy = [animCopy copy];
|
||||||
|
positionAnimCopy.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0.0, 0.0, 0.0f)];
|
||||||
|
positionAnimCopy.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
|
||||||
|
positionAnimCopy.additive = true;
|
||||||
|
positionAnimCopy.delegate = [[CATracingLayerAnimationDelegate alloc] initWithDelegate:anim.delegate animationStopped:^{
|
||||||
|
__strong CATracingLayer *strongSelf = weakSelf;
|
||||||
|
if (strongSelf != nil) {
|
||||||
|
[strongSelf invalidateUpTheTree];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[self invalidateUpTheTree];
|
||||||
|
|
||||||
|
[self mirrorAnimationDownTheTree:animCopy key:@"sublayerTransform"];
|
||||||
|
[self mirrorPositionAnimationDownTheTree:positionAnimCopy key:@"sublayerTransform"];
|
||||||
|
} else if ([key isEqualToString:@"position"]) {
|
||||||
CABasicAnimation *animCopy = [anim copy];
|
CABasicAnimation *animCopy = [anim copy];
|
||||||
CGPoint from = [animCopy.fromValue CGPointValue];
|
CGPoint from = [animCopy.fromValue CGPointValue];
|
||||||
CGPoint to = [animCopy.toValue CGPointValue];
|
CGPoint to = [animCopy.toValue CGPointValue];
|
||||||
|
|||||||
@ -31,8 +31,8 @@ public enum ContainedViewLayoutTransition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public extension ContainedViewLayoutTransition {
|
public extension ContainedViewLayoutTransition {
|
||||||
func updateFrame(node: ASDisplayNode, frame: CGRect, completion: ((Bool) -> Void)? = nil) {
|
func updateFrame(node: ASDisplayNode, frame: CGRect, force: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||||
if node.frame.equalTo(frame) {
|
if node.frame.equalTo(frame) && !force {
|
||||||
completion?(true)
|
completion?(true)
|
||||||
} else {
|
} else {
|
||||||
switch self {
|
switch self {
|
||||||
@ -44,7 +44,7 @@ public extension ContainedViewLayoutTransition {
|
|||||||
case let .animated(duration, curve):
|
case let .animated(duration, curve):
|
||||||
let previousFrame = node.frame
|
let previousFrame = node.frame
|
||||||
node.frame = frame
|
node.frame = frame
|
||||||
node.layer.animateFrame(from: previousFrame, to: frame, duration: duration, timingFunction: curve.timingFunction, completion: { result in
|
node.layer.animateFrame(from: previousFrame, to: frame, duration: duration, timingFunction: curve.timingFunction, force: force, completion: { result in
|
||||||
if let completion = completion {
|
if let completion = completion {
|
||||||
completion(result)
|
completion(result)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,14 @@ public struct Font {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func semibold(_ size: CGFloat) -> UIFont {
|
||||||
|
if #available(iOS 8.2, *) {
|
||||||
|
return UIFont.systemFont(ofSize: size, weight: UIFontWeightSemibold)
|
||||||
|
} else {
|
||||||
|
return CTFontCreateWithName("HelveticaNeue-Medium" as CFString, size, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static func bold(_ size: CGFloat) -> UIFont {
|
public static func bold(_ size: CGFloat) -> UIFont {
|
||||||
if #available(iOS 8.2, *) {
|
if #available(iOS 8.2, *) {
|
||||||
return UIFont.boldSystemFont(ofSize: size)
|
return UIFont.boldSystemFont(ofSize: size)
|
||||||
|
|||||||
@ -12,4 +12,11 @@ public protocol GridItem {
|
|||||||
var section: GridSection? { get }
|
var section: GridSection? { get }
|
||||||
func node(layout: GridNodeLayout) -> GridItemNode
|
func node(layout: GridNodeLayout) -> GridItemNode
|
||||||
func update(node: GridItemNode)
|
func update(node: GridItemNode)
|
||||||
|
var aspectRatio: CGFloat { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension GridItem {
|
||||||
|
var aspectRatio: CGFloat {
|
||||||
|
return 1.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,5 +2,16 @@ import Foundation
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
|
|
||||||
open class GridItemNode: ASDisplayNode {
|
open class GridItemNode: ASDisplayNode {
|
||||||
|
open var isVisibleInGrid = false
|
||||||
|
open var isGridScrolling = false
|
||||||
|
|
||||||
|
final var cachedFrame: CGRect = CGRect()
|
||||||
|
override open var frame: CGRect {
|
||||||
|
get {
|
||||||
|
return self.cachedFrame
|
||||||
|
} set(value) {
|
||||||
|
self.cachedFrame = value
|
||||||
|
super.frame = value
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,21 +47,43 @@ public struct GridNodeScrollToItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum GridNodeLayoutType: Equatable {
|
||||||
|
case fixed(itemSize: CGSize)
|
||||||
|
case balanced(idealHeight: CGFloat)
|
||||||
|
|
||||||
|
public static func ==(lhs: GridNodeLayoutType, rhs: GridNodeLayoutType) -> Bool {
|
||||||
|
switch lhs {
|
||||||
|
case let .fixed(itemSize):
|
||||||
|
if case .fixed(itemSize) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .balanced(idealHeight):
|
||||||
|
if case .balanced(idealHeight) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct GridNodeLayout: Equatable {
|
public struct GridNodeLayout: Equatable {
|
||||||
public let size: CGSize
|
public let size: CGSize
|
||||||
public let insets: UIEdgeInsets
|
public let insets: UIEdgeInsets
|
||||||
public let preloadSize: CGFloat
|
public let preloadSize: CGFloat
|
||||||
public let itemSize: CGSize
|
public let type: GridNodeLayoutType
|
||||||
|
|
||||||
public init(size: CGSize, insets: UIEdgeInsets, preloadSize: CGFloat, itemSize: CGSize) {
|
public init(size: CGSize, insets: UIEdgeInsets, preloadSize: CGFloat, type: GridNodeLayoutType) {
|
||||||
self.size = size
|
self.size = size
|
||||||
self.insets = insets
|
self.insets = insets
|
||||||
self.preloadSize = preloadSize
|
self.preloadSize = preloadSize
|
||||||
self.itemSize = itemSize
|
self.type = type
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: GridNodeLayout, rhs: GridNodeLayout) -> Bool {
|
public static func ==(lhs: GridNodeLayout, rhs: GridNodeLayout) -> Bool {
|
||||||
return lhs.size.equalTo(rhs.size) && lhs.insets == rhs.insets && lhs.preloadSize.isEqual(to: rhs.preloadSize) && lhs.itemSize.equalTo(rhs.itemSize)
|
return lhs.size.equalTo(rhs.size) && lhs.insets == rhs.insets && lhs.preloadSize.isEqual(to: rhs.preloadSize) && lhs.type == rhs.type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +245,7 @@ private struct WrappedGridItemNode: Hashable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
||||||
private var gridLayout = GridNodeLayout(size: CGSize(), insets: UIEdgeInsets(), preloadSize: 0.0, itemSize: CGSize())
|
private var gridLayout = GridNodeLayout(size: CGSize(), insets: UIEdgeInsets(), preloadSize: 0.0, type: .fixed(itemSize: CGSize()))
|
||||||
private var firstIndexInSectionOffset: Int = 0
|
private var firstIndexInSectionOffset: Int = 0
|
||||||
private var items: [GridItem] = []
|
private var items: [GridItem] = []
|
||||||
private var itemNodes: [Int: GridItemNode] = [:]
|
private var itemNodes: [Int: GridItemNode] = [:]
|
||||||
@ -235,6 +257,8 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
public var visibleItemsUpdated: ((GridNodeVisibleItems) -> Void)?
|
public var visibleItemsUpdated: ((GridNodeVisibleItems) -> Void)?
|
||||||
public var presentationLayoutUpdated: ((GridNodeCurrentPresentationLayout, ContainedViewLayoutTransition) -> Void)?
|
public var presentationLayoutUpdated: ((GridNodeCurrentPresentationLayout, ContainedViewLayoutTransition) -> Void)?
|
||||||
|
|
||||||
|
public final var floatingSections = false
|
||||||
|
|
||||||
public override init() {
|
public override init() {
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -315,10 +339,12 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
self.items.insert(insertedItem.item, at: insertedItem.index)
|
self.items.insert(insertedItem.item, at: insertedItem.index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sortedInsertItems = transaction.insertItems.sorted(by: { $0.index < $1.index })
|
||||||
|
|
||||||
var remappedInsertionItemNodes: [Int: GridItemNode] = [:]
|
var remappedInsertionItemNodes: [Int: GridItemNode] = [:]
|
||||||
for (index, itemNode) in remappedDeletionItemNodes {
|
for (index, itemNode) in remappedDeletionItemNodes {
|
||||||
var indexOffset = 0
|
var indexOffset = 0
|
||||||
for insertedItem in transaction.insertItems {
|
for insertedItem in sortedInsertItems {
|
||||||
if insertedItem.index <= index + indexOffset {
|
if insertedItem.index <= index + indexOffset {
|
||||||
indexOffset += 1
|
indexOffset += 1
|
||||||
}
|
}
|
||||||
@ -343,14 +369,26 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
generatedScrollToItem = nil
|
generatedScrollToItem = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.applyPresentaionLayoutTransition(self.generatePresentationLayoutTransition(stationaryItems: transaction.stationaryItems, layoutTransactionOffset: layoutTransactionOffset, scrollToItem: generatedScrollToItem), removedNodes: removedNodes, updateLayoutTransition: transaction.updateLayout?.transition)
|
self.applyPresentaionLayoutTransition(self.generatePresentationLayoutTransition(stationaryItems: transaction.stationaryItems, layoutTransactionOffset: layoutTransactionOffset, scrollToItem: generatedScrollToItem), removedNodes: removedNodes, updateLayoutTransition: transaction.updateLayout?.transition, completion: completion)
|
||||||
|
}
|
||||||
|
|
||||||
completion(self.displayedItemRange())
|
public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
||||||
|
self.updateItemNodeVisibilititesAndScrolling()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||||
|
if !decelerate {
|
||||||
|
self.updateItemNodeVisibilititesAndScrolling()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||||
|
self.updateItemNodeVisibilititesAndScrolling()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
if !self.applyingContentOffset {
|
if !self.applyingContentOffset {
|
||||||
self.applyPresentaionLayoutTransition(self.generatePresentationLayoutTransition(layoutTransactionOffset: 0.0), removedNodes: [], updateLayoutTransition: nil)
|
self.applyPresentaionLayoutTransition(self.generatePresentationLayoutTransition(layoutTransactionOffset: 0.0), removedNodes: [], updateLayoutTransition: nil, completion: { _ in })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,8 +417,10 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
var items: [GridNodePresentationItem] = []
|
var items: [GridNodePresentationItem] = []
|
||||||
var sections: [GridNodePresentationSection] = []
|
var sections: [GridNodePresentationSection] = []
|
||||||
|
|
||||||
let itemsInRow = Int(gridLayout.size.width / gridLayout.itemSize.width)
|
switch gridLayout.type {
|
||||||
let itemsInRowWidth = CGFloat(itemsInRow) * gridLayout.itemSize.width
|
case let .fixed(itemSize):
|
||||||
|
let itemsInRow = Int(gridLayout.size.width / itemSize.width)
|
||||||
|
let itemsInRowWidth = CGFloat(itemsInRow) * itemSize.width
|
||||||
let remainingWidth = gridLayout.size.width - itemsInRowWidth
|
let remainingWidth = gridLayout.size.width - itemsInRowWidth
|
||||||
|
|
||||||
let itemSpacing = floorToScreenPixels(remainingWidth / CGFloat(itemsInRow + 1))
|
let itemSpacing = floorToScreenPixels(remainingWidth / CGFloat(itemsInRow + 1))
|
||||||
@ -401,7 +441,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
if !keepSection {
|
if !keepSection {
|
||||||
if incrementedCurrentRow {
|
if incrementedCurrentRow {
|
||||||
nextItemOrigin.x = itemSpacing
|
nextItemOrigin.x = itemSpacing
|
||||||
nextItemOrigin.y += gridLayout.itemSize.height
|
nextItemOrigin.y += itemSize.height
|
||||||
incrementedCurrentRow = false
|
incrementedCurrentRow = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,25 +455,107 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
|
|
||||||
if !incrementedCurrentRow {
|
if !incrementedCurrentRow {
|
||||||
incrementedCurrentRow = true
|
incrementedCurrentRow = true
|
||||||
contentSize.height += gridLayout.itemSize.height
|
contentSize.height += itemSize.height
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
let itemsInRow = Int(gridLayout.size.width) / Int(gridLayout.itemSize.width)
|
let itemsInRow = Int(gridLayout.size.width) / Int(itemSize.width)
|
||||||
let normalizedIndexOffset = self.firstIndexInSectionOffset % itemsInRow
|
let normalizedIndexOffset = self.firstIndexInSectionOffset % itemsInRow
|
||||||
nextItemOrigin.x += (gridLayout.itemSize.width + itemSpacing) * CGFloat(normalizedIndexOffset)
|
nextItemOrigin.x += (itemSize.width + itemSpacing) * CGFloat(normalizedIndexOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
items.append(GridNodePresentationItem(index: index, frame: CGRect(origin: nextItemOrigin, size: gridLayout.itemSize)))
|
items.append(GridNodePresentationItem(index: index, frame: CGRect(origin: nextItemOrigin, size: itemSize)))
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
nextItemOrigin.x += gridLayout.itemSize.width + itemSpacing
|
nextItemOrigin.x += itemSize.width + itemSpacing
|
||||||
if nextItemOrigin.x + gridLayout.itemSize.width > gridLayout.size.width {
|
if nextItemOrigin.x + itemSize.width > gridLayout.size.width {
|
||||||
nextItemOrigin.x = itemSpacing
|
nextItemOrigin.x = itemSpacing
|
||||||
nextItemOrigin.y += gridLayout.itemSize.height
|
nextItemOrigin.y += itemSize.height
|
||||||
incrementedCurrentRow = false
|
incrementedCurrentRow = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case let .balanced(idealHeight):
|
||||||
|
var weights: [Int] = []
|
||||||
|
for item in self.items {
|
||||||
|
weights.append(Int(item.aspectRatio * 100))
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalItemSize: CGFloat = 0.0
|
||||||
|
for i in 0 ..< self.items.count {
|
||||||
|
totalItemSize += self.items[i].aspectRatio * idealHeight
|
||||||
|
}
|
||||||
|
let numberOfRows = max(Int(round(totalItemSize / gridLayout.size.width)), 1)
|
||||||
|
|
||||||
|
let partition = linearPartitionForWeights(weights, numberOfPartitions:numberOfRows)
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
var offset = CGPoint(x: 0.0, y: 0.0)
|
||||||
|
var previousItemSize: CGFloat = 0.0
|
||||||
|
var contentMaxValueInScrollDirection: CGFloat = 0.0
|
||||||
|
let maxWidth = gridLayout.size.width
|
||||||
|
|
||||||
|
let minimumInteritemSpacing: CGFloat = 1.0
|
||||||
|
let minimumLineSpacing: CGFloat = 1.0
|
||||||
|
|
||||||
|
let viewportWidth: CGFloat = gridLayout.size.width
|
||||||
|
|
||||||
|
let preferredRowSize = idealHeight
|
||||||
|
|
||||||
|
var rowIndex = -1
|
||||||
|
for row in partition {
|
||||||
|
rowIndex += 1
|
||||||
|
|
||||||
|
var summedRatios: CGFloat = 0.0
|
||||||
|
|
||||||
|
var j = i
|
||||||
|
var n = i + row.count
|
||||||
|
|
||||||
|
while j < n {
|
||||||
|
summedRatios += self.items[j].aspectRatio
|
||||||
|
|
||||||
|
j += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var rowSize = gridLayout.size.width - (CGFloat(row.count - 1) * minimumInteritemSpacing)
|
||||||
|
|
||||||
|
if rowIndex == partition.count - 1 {
|
||||||
|
if row.count < 2 {
|
||||||
|
rowSize = floor(viewportWidth / 3.0) - (CGFloat(row.count - 1) * minimumInteritemSpacing)
|
||||||
|
} else if row.count < 3 {
|
||||||
|
rowSize = floor(viewportWidth * 2.0 / 3.0) - (CGFloat(row.count - 1) * minimumInteritemSpacing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
j = i
|
||||||
|
n = i + row.count
|
||||||
|
|
||||||
|
while j < n {
|
||||||
|
let preferredAspectRatio = self.items[j].aspectRatio
|
||||||
|
|
||||||
|
let actualSize = CGSize(width: round(rowSize / summedRatios * (preferredAspectRatio)), height: preferredRowSize)
|
||||||
|
|
||||||
|
var frame = CGRect(x: offset.x, y: offset.y, width: actualSize.width, height: actualSize.height)
|
||||||
|
if frame.origin.x + frame.size.width >= maxWidth - 2.0 {
|
||||||
|
frame.size.width = max(1.0, maxWidth - frame.origin.x)
|
||||||
|
}
|
||||||
|
|
||||||
|
items.append(GridNodePresentationItem(index: j, frame: frame))
|
||||||
|
|
||||||
|
offset.x += actualSize.width + minimumInteritemSpacing
|
||||||
|
previousItemSize = actualSize.height
|
||||||
|
contentMaxValueInScrollDirection = frame.maxY
|
||||||
|
|
||||||
|
j += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if row.count > 0 {
|
||||||
|
offset = CGPoint(x: 0.0, y: offset.y + previousItemSize + minimumLineSpacing)
|
||||||
|
}
|
||||||
|
|
||||||
|
i += row.count
|
||||||
|
}
|
||||||
|
contentSize = CGSize(width: gridLayout.size.width, height: contentMaxValueInScrollDirection)
|
||||||
|
}
|
||||||
|
|
||||||
return GridNodeItemLayout(contentSize: contentSize, items: items, sections: sections)
|
return GridNodeItemLayout(contentSize: contentSize, items: items, sections: sections)
|
||||||
} else {
|
} else {
|
||||||
@ -446,15 +568,17 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
var transitionDirectionHint: GridNodePreviousItemsTransitionDirectionHint = .up
|
var transitionDirectionHint: GridNodePreviousItemsTransitionDirectionHint = .up
|
||||||
var transition: ContainedViewLayoutTransition = .immediate
|
var transition: ContainedViewLayoutTransition = .immediate
|
||||||
let contentOffset: CGPoint
|
let contentOffset: CGPoint
|
||||||
switch stationaryItems {
|
var updatedStationaryItems = stationaryItems
|
||||||
|
if scrollToItem != nil {
|
||||||
|
updatedStationaryItems = .none
|
||||||
|
}
|
||||||
|
switch updatedStationaryItems {
|
||||||
case .none:
|
case .none:
|
||||||
if let scrollToItem = scrollToItem {
|
if let scrollToItem = scrollToItem {
|
||||||
let itemFrame = self.itemLayout.items[scrollToItem.index]
|
let itemFrame = self.itemLayout.items[scrollToItem.index]
|
||||||
|
|
||||||
var additionalOffset: CGFloat = 0.0
|
var additionalOffset: CGFloat = 0.0
|
||||||
if scrollToItem.adjustForTopInset {
|
if scrollToItem.adjustForSection {
|
||||||
additionalOffset = -gridLayout.insets.top
|
|
||||||
} else if scrollToItem.adjustForSection {
|
|
||||||
var adjustForSection: GridSection?
|
var adjustForSection: GridSection?
|
||||||
if scrollToItem.index == 0 {
|
if scrollToItem.index == 0 {
|
||||||
if let itemSection = self.items[scrollToItem.index].section {
|
if let itemSection = self.items[scrollToItem.index].section {
|
||||||
@ -475,6 +599,12 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
if let adjustForSection = adjustForSection {
|
if let adjustForSection = adjustForSection {
|
||||||
additionalOffset = -adjustForSection.height
|
additionalOffset = -adjustForSection.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if scrollToItem.adjustForTopInset {
|
||||||
|
additionalOffset += -gridLayout.insets.top
|
||||||
|
}
|
||||||
|
} else if scrollToItem.adjustForTopInset {
|
||||||
|
additionalOffset = -gridLayout.insets.top
|
||||||
}
|
}
|
||||||
|
|
||||||
let displayHeight = max(0.0, self.gridLayout.size.height - self.gridLayout.insets.top - self.gridLayout.insets.bottom)
|
let displayHeight = max(0.0, self.gridLayout.size.height - self.gridLayout.insets.top - self.gridLayout.insets.bottom)
|
||||||
@ -518,7 +648,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
var selectedContentOffset: CGPoint?
|
var selectedContentOffset: CGPoint?
|
||||||
for (index, itemNode) in self.itemNodes {
|
for (index, itemNode) in self.itemNodes {
|
||||||
if stationaryItemIndices.contains(index) {
|
if stationaryItemIndices.contains(index) {
|
||||||
let currentScreenOffset = itemNode.frame.origin.y - self.scrollView.contentOffset.y
|
//let currentScreenOffset = itemNode.frame.origin.y - self.scrollView.contentOffset.y
|
||||||
selectedContentOffset = CGPoint(x: 0.0, y: self.itemLayout.items[index].frame.origin.y - itemNode.frame.origin.y + self.scrollView.contentOffset.y)
|
selectedContentOffset = CGPoint(x: 0.0, y: self.itemLayout.items[index].frame.origin.y - itemNode.frame.origin.y + self.scrollView.contentOffset.y)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -532,7 +662,7 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
case .all:
|
case .all:
|
||||||
var selectedContentOffset: CGPoint?
|
var selectedContentOffset: CGPoint?
|
||||||
for (index, itemNode) in self.itemNodes {
|
for (index, itemNode) in self.itemNodes {
|
||||||
let currentScreenOffset = itemNode.frame.origin.y - self.scrollView.contentOffset.y
|
//let currentScreenOffset = itemNode.frame.origin.y - self.scrollView.contentOffset.y
|
||||||
selectedContentOffset = CGPoint(x: 0.0, y: self.itemLayout.items[index].frame.origin.y - itemNode.frame.origin.y + self.scrollView.contentOffset.y)
|
selectedContentOffset = CGPoint(x: 0.0, y: self.itemLayout.items[index].frame.origin.y - itemNode.frame.origin.y + self.scrollView.contentOffset.y)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -548,6 +678,8 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
let upperDisplayBound = contentOffset.y + self.gridLayout.size.height + self.gridLayout.preloadSize
|
let upperDisplayBound = contentOffset.y + self.gridLayout.size.height + self.gridLayout.preloadSize
|
||||||
|
|
||||||
var presentationItems: [GridNodePresentationItem] = []
|
var presentationItems: [GridNodePresentationItem] = []
|
||||||
|
|
||||||
|
var validSections = Set<WrappedGridSection>()
|
||||||
for item in self.itemLayout.items {
|
for item in self.itemLayout.items {
|
||||||
if item.frame.origin.y < lowerDisplayBound {
|
if item.frame.origin.y < lowerDisplayBound {
|
||||||
continue
|
continue
|
||||||
@ -556,13 +688,20 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
presentationItems.append(item)
|
presentationItems.append(item)
|
||||||
|
if self.floatingSections {
|
||||||
|
if let section = self.items[item.index].section {
|
||||||
|
validSections.insert(WrappedGridSection(section))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var presentationSections: [GridNodePresentationSection] = []
|
var presentationSections: [GridNodePresentationSection] = []
|
||||||
for section in self.itemLayout.sections {
|
for section in self.itemLayout.sections {
|
||||||
if section.frame.origin.y < lowerDisplayBound {
|
if section.frame.origin.y < lowerDisplayBound {
|
||||||
|
if !validSections.contains(WrappedGridSection(section.section)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if section.frame.origin.y + section.frame.size.height > upperDisplayBound {
|
if section.frame.origin.y + section.frame.size.height > upperDisplayBound {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -575,7 +714,21 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func applyPresentaionLayoutTransition(_ presentationLayoutTransition: GridNodePresentationLayoutTransition, removedNodes: [GridItemNode], updateLayoutTransition: ContainedViewLayoutTransition?) {
|
private func lowestSectionNode() -> ASDisplayNode? {
|
||||||
|
var lowestHeaderNode: ASDisplayNode?
|
||||||
|
var lowestHeaderNodeIndex: Int?
|
||||||
|
for (_, headerNode) in self.sectionNodes {
|
||||||
|
if let index = self.subnodes.index(of: headerNode) {
|
||||||
|
if lowestHeaderNodeIndex == nil || index < lowestHeaderNodeIndex! {
|
||||||
|
lowestHeaderNodeIndex = index
|
||||||
|
lowestHeaderNode = headerNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lowestHeaderNode
|
||||||
|
}
|
||||||
|
|
||||||
|
private func applyPresentaionLayoutTransition(_ presentationLayoutTransition: GridNodePresentationLayoutTransition, removedNodes: [GridItemNode], updateLayoutTransition: ContainedViewLayoutTransition?, completion: (GridNodeDisplayedItemRange) -> Void) {
|
||||||
var previousItemFrames: ([WrappedGridItemNode: CGRect])?
|
var previousItemFrames: ([WrappedGridItemNode: CGRect])?
|
||||||
switch presentationLayoutTransition.transition {
|
switch presentationLayoutTransition.transition {
|
||||||
case .animated:
|
case .animated:
|
||||||
@ -603,29 +756,44 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
applyingContentOffset = false
|
applyingContentOffset = false
|
||||||
|
|
||||||
|
let lowestSectionNode: ASDisplayNode? = self.lowestSectionNode()
|
||||||
|
|
||||||
var existingItemIndices = Set<Int>()
|
var existingItemIndices = Set<Int>()
|
||||||
for item in presentationLayoutTransition.layout.items {
|
for item in presentationLayoutTransition.layout.items {
|
||||||
existingItemIndices.insert(item.index)
|
existingItemIndices.insert(item.index)
|
||||||
|
|
||||||
if let itemNode = self.itemNodes[item.index] {
|
if let itemNode = self.itemNodes[item.index] {
|
||||||
|
if itemNode.frame != item.frame {
|
||||||
itemNode.frame = item.frame
|
itemNode.frame = item.frame
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let itemNode = self.items[item.index].node(layout: presentationLayoutTransition.layout.layout)
|
let itemNode = self.items[item.index].node(layout: presentationLayoutTransition.layout.layout)
|
||||||
itemNode.frame = item.frame
|
itemNode.frame = item.frame
|
||||||
self.addItemNode(index: item.index, itemNode: itemNode)
|
self.addItemNode(index: item.index, itemNode: itemNode, lowestSectionNode: lowestSectionNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var existingSections = Set<WrappedGridSection>()
|
var existingSections = Set<WrappedGridSection>()
|
||||||
for section in presentationLayoutTransition.layout.sections {
|
for i in 0 ..< presentationLayoutTransition.layout.sections.count {
|
||||||
|
let section = presentationLayoutTransition.layout.sections[i]
|
||||||
|
|
||||||
let wrappedSection = WrappedGridSection(section.section)
|
let wrappedSection = WrappedGridSection(section.section)
|
||||||
existingSections.insert(wrappedSection)
|
existingSections.insert(wrappedSection)
|
||||||
|
|
||||||
|
var sectionFrame = section.frame
|
||||||
|
if self.floatingSections {
|
||||||
|
var maxY = CGFloat.greatestFiniteMagnitude
|
||||||
|
if i != presentationLayoutTransition.layout.sections.count - 1 {
|
||||||
|
maxY = presentationLayoutTransition.layout.sections[i + 1].frame.minY - sectionFrame.height
|
||||||
|
}
|
||||||
|
sectionFrame.origin.y = max(sectionFrame.minY, min(maxY, presentationLayoutTransition.layout.contentOffset.y + presentationLayoutTransition.layout.layout.insets.top))
|
||||||
|
}
|
||||||
|
|
||||||
if let sectionNode = self.sectionNodes[wrappedSection] {
|
if let sectionNode = self.sectionNodes[wrappedSection] {
|
||||||
sectionNode.frame = section.frame
|
sectionNode.frame = sectionFrame
|
||||||
} else {
|
} else {
|
||||||
let sectionNode = section.section.node()
|
let sectionNode = section.section.node()
|
||||||
sectionNode.frame = section.frame
|
sectionNode.frame = sectionFrame
|
||||||
self.addSectionNode(section: wrappedSection, sectionNode: sectionNode)
|
self.addSectionNode(section: wrappedSection, sectionNode: sectionNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -698,7 +866,6 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
itemNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: duration, timingFunction: timingFunction, additive: true)
|
itemNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: duration, timingFunction: timingFunction, additive: true)
|
||||||
}
|
}
|
||||||
for (wrappedSection, sectionNode) in self.sectionNodes where existingSections.contains(wrappedSection) {
|
for (wrappedSection, sectionNode) in self.sectionNodes where existingSections.contains(wrappedSection) {
|
||||||
let position = sectionNode.layer.position
|
|
||||||
sectionNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: duration, timingFunction: timingFunction, additive: true)
|
sectionNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: duration, timingFunction: timingFunction, additive: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -777,16 +944,20 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
completion(self.displayedItemRange())
|
||||||
|
|
||||||
|
self.updateItemNodeVisibilititesAndScrolling()
|
||||||
|
|
||||||
if let visibleItemsUpdated = self.visibleItemsUpdated {
|
if let visibleItemsUpdated = self.visibleItemsUpdated {
|
||||||
if presentationLayoutTransition.layout.items.count != 0 {
|
if presentationLayoutTransition.layout.items.count != 0 {
|
||||||
let topIndex = presentationLayoutTransition.layout.items.first!.index
|
let topIndex = presentationLayoutTransition.layout.items.first!.index
|
||||||
let bottomIndex = presentationLayoutTransition.layout.items.last!.index
|
let bottomIndex = presentationLayoutTransition.layout.items.last!.index
|
||||||
|
|
||||||
var topVisible: (Int, GridItem) = (topIndex, self.items[topIndex])
|
var topVisible: (Int, GridItem) = (topIndex, self.items[topIndex])
|
||||||
var bottomVisible: (Int, GridItem) = (bottomIndex, self.items[bottomIndex])
|
let bottomVisible: (Int, GridItem) = (bottomIndex, self.items[bottomIndex])
|
||||||
|
|
||||||
let lowerDisplayBound = presentationLayoutTransition.layout.contentOffset.y
|
let lowerDisplayBound = presentationLayoutTransition.layout.contentOffset.y
|
||||||
let upperDisplayBound = presentationLayoutTransition.layout.contentOffset.y + self.gridLayout.size.height
|
//let upperDisplayBound = presentationLayoutTransition.layout.contentOffset.y + self.gridLayout.size.height
|
||||||
|
|
||||||
for item in presentationLayoutTransition.layout.items {
|
for item in presentationLayoutTransition.layout.items {
|
||||||
if lowerDisplayBound.isLess(than: item.frame.maxY) {
|
if lowerDisplayBound.isLess(than: item.frame.maxY) {
|
||||||
@ -816,13 +987,17 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addItemNode(index: Int, itemNode: GridItemNode) {
|
private func addItemNode(index: Int, itemNode: GridItemNode, lowestSectionNode: ASDisplayNode?) {
|
||||||
assert(self.itemNodes[index] == nil)
|
assert(self.itemNodes[index] == nil)
|
||||||
self.itemNodes[index] = itemNode
|
self.itemNodes[index] = itemNode
|
||||||
if itemNode.supernode == nil {
|
if itemNode.supernode == nil {
|
||||||
|
if let lowestSectionNode = lowestSectionNode {
|
||||||
|
self.insertSubnode(itemNode, belowSubnode: lowestSectionNode)
|
||||||
|
} else {
|
||||||
self.addSubnode(itemNode)
|
self.addSubnode(itemNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func addSectionNode(section: WrappedGridSection, sectionNode: ASDisplayNode) {
|
private func addSectionNode(section: WrappedGridSection, sectionNode: ASDisplayNode) {
|
||||||
assert(self.sectionNodes[section] == nil)
|
assert(self.sectionNodes[section] == nil)
|
||||||
@ -848,6 +1023,20 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func updateItemNodeVisibilititesAndScrolling() {
|
||||||
|
let visibleRect = self.scrollView.bounds
|
||||||
|
let isScrolling = self.scrollView.isDragging || self.scrollView.isDecelerating
|
||||||
|
for (_, itemNode) in self.itemNodes {
|
||||||
|
let visible = itemNode.frame.intersects(visibleRect)
|
||||||
|
if itemNode.isVisibleInGrid != visible {
|
||||||
|
itemNode.isVisibleInGrid = visible
|
||||||
|
}
|
||||||
|
if itemNode.isGridScrolling != isScrolling {
|
||||||
|
itemNode.isGridScrolling = isScrolling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func forEachItemNode(_ f: (ASDisplayNode) -> Void) {
|
public func forEachItemNode(_ f: (ASDisplayNode) -> Void) {
|
||||||
for (_, node) in self.itemNodes {
|
for (_, node) in self.itemNodes {
|
||||||
f(node)
|
f(node)
|
||||||
@ -872,4 +1061,127 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
f(row)
|
f(row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func itemNodeAtPoint(_ point: CGPoint) -> ASDisplayNode? {
|
||||||
|
for (_, node) in self.itemNodes {
|
||||||
|
if node.frame.contains(point) {
|
||||||
|
return node
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func NH_LP_TABLE_LOOKUP(_ table: inout [Int], _ i: Int, _ j: Int, _ rowsize: Int) -> Int {
|
||||||
|
return table[i * rowsize + j]
|
||||||
|
}
|
||||||
|
|
||||||
|
private func NH_LP_TABLE_LOOKUP_SET(_ table: inout [Int], _ i: Int, _ j: Int, _ rowsize: Int, _ value: Int) {
|
||||||
|
table[i * rowsize + j] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
private func linearPartitionTable(_ weights: [Int], numberOfPartitions: Int) -> [Int] {
|
||||||
|
let n = weights.count
|
||||||
|
let k = numberOfPartitions
|
||||||
|
|
||||||
|
let tableSize = n * k;
|
||||||
|
var tmpTable = Array<Int>(repeatElement(0, count: tableSize))
|
||||||
|
|
||||||
|
let solutionSize = (n - 1) * (k - 1)
|
||||||
|
var solution = Array<Int>(repeatElement(0, count: solutionSize))
|
||||||
|
|
||||||
|
for i in 0 ..< n {
|
||||||
|
let offset = i != 0 ? NH_LP_TABLE_LOOKUP(&tmpTable, i - 1, 0, k) : 0
|
||||||
|
NH_LP_TABLE_LOOKUP_SET(&tmpTable, i, 0, k, Int(weights[i]) + offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
for j in 0 ..< k {
|
||||||
|
NH_LP_TABLE_LOOKUP_SET(&tmpTable, 0, j, k, Int(weights[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 1 ..< n {
|
||||||
|
for j in 1 ..< k {
|
||||||
|
var currentMin = 0
|
||||||
|
var minX = Int.max
|
||||||
|
|
||||||
|
for x in 0 ..< i {
|
||||||
|
let c1 = NH_LP_TABLE_LOOKUP(&tmpTable, x, j - 1, k)
|
||||||
|
let c2 = NH_LP_TABLE_LOOKUP(&tmpTable, i, 0, k) - NH_LP_TABLE_LOOKUP(&tmpTable, x, 0, k)
|
||||||
|
let cost = max(c1, c2)
|
||||||
|
|
||||||
|
if x == 0 || cost < currentMin {
|
||||||
|
currentMin = cost;
|
||||||
|
minX = x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NH_LP_TABLE_LOOKUP_SET(&tmpTable, i, j, k, currentMin)
|
||||||
|
NH_LP_TABLE_LOOKUP_SET(&solution, i - 1, j - 1, k - 1, minX)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return solution
|
||||||
|
}
|
||||||
|
|
||||||
|
private func linearPartitionForWeights(_ weights: [Int], numberOfPartitions: Int) -> [[Int]] {
|
||||||
|
var n = weights.count
|
||||||
|
var k = numberOfPartitions
|
||||||
|
|
||||||
|
if k <= 0 {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
if k >= n {
|
||||||
|
var partition: [[Int]] = []
|
||||||
|
for weight in weights {
|
||||||
|
partition.append([weight])
|
||||||
|
}
|
||||||
|
return partition
|
||||||
|
}
|
||||||
|
|
||||||
|
if n == 1 {
|
||||||
|
return [weights]
|
||||||
|
}
|
||||||
|
|
||||||
|
var solution = linearPartitionTable(weights, numberOfPartitions: numberOfPartitions)
|
||||||
|
let solutionRowSize = numberOfPartitions - 1
|
||||||
|
|
||||||
|
k = k - 2;
|
||||||
|
n = n - 1;
|
||||||
|
|
||||||
|
var answer: [[Int]] = []
|
||||||
|
|
||||||
|
while k >= 0 {
|
||||||
|
if n < 1 {
|
||||||
|
answer.insert([], at: 0)
|
||||||
|
} else {
|
||||||
|
var currentAnswer: [Int] = []
|
||||||
|
|
||||||
|
var i = NH_LP_TABLE_LOOKUP(&solution, n - 1, k, solutionRowSize) + 1
|
||||||
|
let range = n + 1
|
||||||
|
while i < range {
|
||||||
|
currentAnswer.append(weights[i])
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
answer.insert(currentAnswer, at: 0)
|
||||||
|
|
||||||
|
n = NH_LP_TABLE_LOOKUP(&solution, n - 1, k, solutionRowSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
k = k - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentAnswer: [Int] = []
|
||||||
|
var i = 0
|
||||||
|
let range = n + 1
|
||||||
|
while i < range {
|
||||||
|
currentAnswer.append(weights[i])
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
answer.insert(currentAnswer, at: 0)
|
||||||
|
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -126,7 +126,7 @@ open class LegacyPresentedController: ViewController {
|
|||||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
|
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func dismiss() {
|
override open func dismiss(completion: (() -> Void)? = nil) {
|
||||||
switch self.presentation {
|
switch self.presentation {
|
||||||
case .modal:
|
case .modal:
|
||||||
self.controllerNode.animateModalOut { [weak self] in
|
self.controllerNode.animateModalOut { [weak self] in
|
||||||
@ -135,7 +135,7 @@ open class LegacyPresentedController: ViewController {
|
|||||||
} else if let controller = self?.legacyController as? TGNavigationController {
|
} else if let controller = self?.legacyController as? TGNavigationController {
|
||||||
controller.didDismiss()
|
controller.didDismiss()
|
||||||
}*/
|
}*/
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
self?.presentingViewController?.dismiss(animated: false, completion: completion)
|
||||||
}
|
}
|
||||||
case .custom:
|
case .custom:
|
||||||
/*if let controller = self.legacyController as? TGViewController {
|
/*if let controller = self.legacyController as? TGViewController {
|
||||||
@ -143,7 +143,7 @@ open class LegacyPresentedController: ViewController {
|
|||||||
} else if let controller = self.legacyController as? TGNavigationController {
|
} else if let controller = self.legacyController as? TGNavigationController {
|
||||||
controller.didDismiss()
|
controller.didDismiss()
|
||||||
}*/
|
}*/
|
||||||
self.presentingViewController?.dismiss(animated: false, completion: nil)
|
self.presentingViewController?.dismiss(animated: false, completion: completion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -459,7 +459,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
|||||||
|
|
||||||
self.updateItemHeaders()
|
self.updateItemHeaders()
|
||||||
|
|
||||||
for (headerId, headerNode) in self.itemHeaderNodes {
|
for (_, headerNode) in self.itemHeaderNodes {
|
||||||
//let position = headerNode.position
|
//let position = headerNode.position
|
||||||
//headerNode.position = CGPoint(x: position.x, y: position.y - deltaY)
|
//headerNode.position = CGPoint(x: position.x, y: position.y - deltaY)
|
||||||
|
|
||||||
@ -490,6 +490,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
|||||||
|
|
||||||
self.updateVisibleContentOffset()
|
self.updateVisibleContentOffset()
|
||||||
self.updateVisibleItemRange()
|
self.updateVisibleItemRange()
|
||||||
|
self.updateItemNodesVisibilities()
|
||||||
|
|
||||||
//CATransaction.commit()
|
//CATransaction.commit()
|
||||||
}
|
}
|
||||||
@ -2104,6 +2105,8 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.updateItemNodesVisibilities()
|
||||||
|
|
||||||
self.updateScroller()
|
self.updateScroller()
|
||||||
self.setNeedsAnimations()
|
self.setNeedsAnimations()
|
||||||
|
|
||||||
@ -2117,6 +2120,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
|||||||
completion()
|
completion()
|
||||||
} else {
|
} else {
|
||||||
self.updateItemHeaders(headerNodesTransition, animateInsertion: animated || !requestItemInsertionAnimationsIndices.isEmpty)
|
self.updateItemHeaders(headerNodesTransition, animateInsertion: animated || !requestItemInsertionAnimationsIndices.isEmpty)
|
||||||
|
self.updateItemNodesVisibilities()
|
||||||
|
|
||||||
if animated {
|
if animated {
|
||||||
self.setNeedsAnimations()
|
self.setNeedsAnimations()
|
||||||
@ -2280,7 +2284,7 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
|||||||
addHeader(previousHeaderId, previousUpperBound, previousLowerBound, previousHeaderItem, hasValidNodes)
|
addHeader(previousHeaderId, previousUpperBound, previousLowerBound, previousHeaderItem, hasValidNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentIds = Set(self.itemHeaderNodes.keys)
|
let currentIds = Set(self.itemHeaderNodes.keys)
|
||||||
for id in currentIds.subtracting(visibleHeaderNodes) {
|
for id in currentIds.subtracting(visibleHeaderNodes) {
|
||||||
if let headerNode = self.itemHeaderNodes.removeValue(forKey: id) {
|
if let headerNode = self.itemHeaderNodes.removeValue(forKey: id) {
|
||||||
headerNode.removeFromSupernode()
|
headerNode.removeFromSupernode()
|
||||||
@ -2288,6 +2292,20 @@ open class ListView: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func updateItemNodesVisibilities() {
|
||||||
|
let visibilityRect = CGRect(origin: CGPoint(x: 0.0, y: self.insets.top), size: CGSize(width: self.visibleSize.width, height: self.visibleSize.height - self.insets.top - self.insets.bottom))
|
||||||
|
for itemNode in self.itemNodes {
|
||||||
|
let itemFrame = itemNode.apparentFrame
|
||||||
|
var visibility: ListViewItemNodeVisibility = .none
|
||||||
|
if visibilityRect.intersects(itemFrame) {
|
||||||
|
visibility = .visible
|
||||||
|
}
|
||||||
|
if visibility != itemNode.visibility {
|
||||||
|
itemNode.visibility = visibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func updateAccessoryNodes(animated: Bool, currentTimestamp: Double) {
|
private func updateAccessoryNodes(animated: Bool, currentTimestamp: Double) {
|
||||||
var index = -1
|
var index = -1
|
||||||
let count = self.itemNodes.count
|
let count = self.itemNodes.count
|
||||||
|
|||||||
@ -52,6 +52,12 @@ public struct ListViewItemNodeLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ListViewItemNodeVisibility {
|
||||||
|
case none
|
||||||
|
case nearlyVisible
|
||||||
|
case visible
|
||||||
|
}
|
||||||
|
|
||||||
open class ListViewItemNode: ASDisplayNode {
|
open class ListViewItemNode: ASDisplayNode {
|
||||||
let rotated: Bool
|
let rotated: Bool
|
||||||
final var index: Int?
|
final var index: Int?
|
||||||
@ -85,6 +91,8 @@ open class ListViewItemNode: ASDisplayNode {
|
|||||||
|
|
||||||
public final var canBeUsedAsScrollToItemAnchor: Bool = true
|
public final var canBeUsedAsScrollToItemAnchor: Bool = true
|
||||||
|
|
||||||
|
open var visibility: ListViewItemNodeVisibility = .none
|
||||||
|
|
||||||
open var canBeSelected: Bool {
|
open var canBeSelected: Bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
149
Display/NativeWindowHostView.swift
Normal file
149
Display/NativeWindowHostView.swift
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
private let defaultOrientations: UIInterfaceOrientationMask = {
|
||||||
|
if UIDevice.current.userInterfaceIdiom == .pad {
|
||||||
|
return .all
|
||||||
|
} else {
|
||||||
|
return .allButUpsideDown
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
private class WindowRootViewController: UIViewController {
|
||||||
|
var presentController: ((UIViewController, Bool, (() -> Void)?) -> Void)?
|
||||||
|
var orientations: UIInterfaceOrientationMask = defaultOrientations {
|
||||||
|
didSet {
|
||||||
|
if oldValue != self.orientations {
|
||||||
|
if self.orientations == .portrait {
|
||||||
|
if UIDevice.current.orientation != .portrait {
|
||||||
|
let value = UIInterfaceOrientation.portrait.rawValue
|
||||||
|
UIDevice.current.setValue(value, forKey: "orientation")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UIViewController.attemptRotationToDeviceOrientation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||||
|
return .default
|
||||||
|
}
|
||||||
|
|
||||||
|
override var prefersStatusBarHidden: Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||||
|
return orientations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class NativeWindow: UIWindow, WindowHost {
|
||||||
|
var updateSize: ((CGSize) -> Void)?
|
||||||
|
var layoutSubviewsEvent: (() -> Void)?
|
||||||
|
var updateIsUpdatingOrientationLayout: ((Bool) -> Void)?
|
||||||
|
var updateToInterfaceOrientation: (() -> Void)?
|
||||||
|
var presentController: ((ViewController) -> Void)?
|
||||||
|
var hitTestImpl: ((CGPoint, UIEvent?) -> UIView?)?
|
||||||
|
|
||||||
|
override var frame: CGRect {
|
||||||
|
get {
|
||||||
|
return super.frame
|
||||||
|
} set(value) {
|
||||||
|
let sizeUpdated = super.frame.size != value.size
|
||||||
|
super.frame = value
|
||||||
|
|
||||||
|
if sizeUpdated {
|
||||||
|
self.updateSize?(value.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override var bounds: CGRect {
|
||||||
|
get {
|
||||||
|
return super.bounds
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
let sizeUpdated = super.bounds.size != value.size
|
||||||
|
super.bounds = value
|
||||||
|
|
||||||
|
if sizeUpdated {
|
||||||
|
self.updateSize?(value.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func layoutSubviews() {
|
||||||
|
super.layoutSubviews()
|
||||||
|
|
||||||
|
self.layoutSubviewsEvent?()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func _update(toInterfaceOrientation arg1: Int32, duration arg2: Double, force arg3: Bool) {
|
||||||
|
self.updateIsUpdatingOrientationLayout?(true)
|
||||||
|
super._update(toInterfaceOrientation: arg1, duration: arg2, force: arg3)
|
||||||
|
self.updateIsUpdatingOrientationLayout?(false)
|
||||||
|
|
||||||
|
self.updateToInterfaceOrientation?()
|
||||||
|
}
|
||||||
|
|
||||||
|
func present(_ controller: ViewController) {
|
||||||
|
self.presentController?(controller)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
return self.hitTestImpl?(point, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func nativeWindowHostView() -> WindowHostView {
|
||||||
|
let window = NativeWindow(frame: UIScreen.main.bounds)
|
||||||
|
|
||||||
|
let rootViewController = WindowRootViewController()
|
||||||
|
window.rootViewController = rootViewController
|
||||||
|
rootViewController.viewWillAppear(false)
|
||||||
|
rootViewController.viewDidAppear(false)
|
||||||
|
rootViewController.view.isHidden = true
|
||||||
|
|
||||||
|
let hostView = WindowHostView(view: window, isRotating: {
|
||||||
|
return window.isRotating()
|
||||||
|
}, updateSupportedInterfaceOrientations: { orientations in
|
||||||
|
rootViewController.orientations = orientations
|
||||||
|
})
|
||||||
|
|
||||||
|
window.updateSize = { [weak hostView] size in
|
||||||
|
hostView?.updateSize?(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.layoutSubviewsEvent = { [weak hostView] in
|
||||||
|
hostView?.layoutSubviews?()
|
||||||
|
}
|
||||||
|
|
||||||
|
window.updateIsUpdatingOrientationLayout = { [weak hostView] value in
|
||||||
|
hostView?.isUpdatingOrientationLayout = value
|
||||||
|
}
|
||||||
|
|
||||||
|
window.updateToInterfaceOrientation = { [weak hostView] in
|
||||||
|
hostView?.updateToInterfaceOrientation?()
|
||||||
|
}
|
||||||
|
|
||||||
|
window.presentController = { [weak hostView] controller in
|
||||||
|
hostView?.present?(controller)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.hitTestImpl = { [weak hostView] point, event in
|
||||||
|
return hostView?.hitTest?(point, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
rootViewController.presentController = { [weak hostView] controller, animated, completion in
|
||||||
|
if let strongSelf = hostView {
|
||||||
|
strongSelf.present?(LegacyPresentedController(legacyController: controller, presentation: .custom))
|
||||||
|
if let completion = completion {
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hostView
|
||||||
|
}
|
||||||
@ -35,7 +35,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
open var foregroundColor: UIColor = UIColor.black {
|
open var foregroundColor: UIColor = UIColor.black {
|
||||||
didSet {
|
didSet {
|
||||||
if let title = self.title {
|
if let title = self.title {
|
||||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(17.0), textColor: self.foregroundColor)
|
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: self.foregroundColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
|
|
||||||
private var collapsed: Bool {
|
private var collapsed: Bool {
|
||||||
get {
|
get {
|
||||||
return self.frame.size.height < (20.0 + 44.0)
|
return self.frame.size.height.isLess(than: 44.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +173,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
private var title: String? {
|
private var title: String? {
|
||||||
didSet {
|
didSet {
|
||||||
if let title = self.title {
|
if let title = self.title {
|
||||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(17.0), textColor: self.foregroundColor)
|
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: self.foregroundColor)
|
||||||
if self.titleNode.supernode == nil {
|
if self.titleNode.supernode == nil {
|
||||||
self.clippingNode.addSubnode(self.titleNode)
|
self.clippingNode.addSubnode(self.titleNode)
|
||||||
}
|
}
|
||||||
@ -544,7 +544,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
public func makeTransitionTitleNode(foregroundColor: UIColor) -> ASDisplayNode? {
|
public func makeTransitionTitleNode(foregroundColor: UIColor) -> ASDisplayNode? {
|
||||||
if let title = self.title {
|
if let title = self.title {
|
||||||
let node = ASTextNode()
|
let node = ASTextNode()
|
||||||
node.attributedText = NSAttributedString(string: title, font: Font.medium(17.0), textColor: foregroundColor)
|
node.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: foregroundColor)
|
||||||
return node
|
return node
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -504,4 +504,17 @@ open class NavigationController: NavigationControllerProxy, ContainableControlle
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final var window: WindowHost? {
|
||||||
|
if let window = self.view.window as? WindowHost {
|
||||||
|
return window
|
||||||
|
} else if let superwindow = self.view.window {
|
||||||
|
for subview in superwindow.subviews {
|
||||||
|
if let subview = subview as? WindowHost {
|
||||||
|
return subview
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,8 @@ final class PresentationContext {
|
|||||||
|
|
||||||
private var presentationDisposables = DisposableSet()
|
private var presentationDisposables = DisposableSet()
|
||||||
|
|
||||||
|
var topLevelSubview: UIView?
|
||||||
|
|
||||||
public func present(_ controller: ViewController) {
|
public func present(_ controller: ViewController) {
|
||||||
let controllerReady = controller.ready.get()
|
let controllerReady = controller.ready.get()
|
||||||
|> filter({ $0 })
|
|> filter({ $0 })
|
||||||
@ -40,7 +42,7 @@ final class PresentationContext {
|
|||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(true))
|
|> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(true))
|
||||||
|
|
||||||
if let view = self.view, let initialLayout = self.layout {
|
if let _ = self.view, let initialLayout = self.layout {
|
||||||
controller.view.frame = CGRect(origin: CGPoint(), size: initialLayout.size)
|
controller.view.frame = CGRect(origin: CGPoint(), size: initialLayout.size)
|
||||||
controller.containerLayoutUpdated(initialLayout, transition: .immediate)
|
controller.containerLayoutUpdated(initialLayout, transition: .immediate)
|
||||||
|
|
||||||
@ -60,11 +62,19 @@ final class PresentationContext {
|
|||||||
controller.setIgnoreAppearanceMethodInvocations(true)
|
controller.setIgnoreAppearanceMethodInvocations(true)
|
||||||
if layout != initialLayout {
|
if layout != initialLayout {
|
||||||
controller.view.frame = CGRect(origin: CGPoint(), size: layout.size)
|
controller.view.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
view.addSubview(controller.view)
|
if let topLevelSubview = strongSelf.topLevelSubview {
|
||||||
controller.containerLayoutUpdated(layout, transition: .immediate)
|
view.insertSubview(controller.view, belowSubview: topLevelSubview)
|
||||||
} else {
|
} else {
|
||||||
view.addSubview(controller.view)
|
view.addSubview(controller.view)
|
||||||
}
|
}
|
||||||
|
controller.containerLayoutUpdated(layout, transition: .immediate)
|
||||||
|
} else {
|
||||||
|
if let topLevelSubview = strongSelf.topLevelSubview {
|
||||||
|
view.insertSubview(controller.view, belowSubview: topLevelSubview)
|
||||||
|
} else {
|
||||||
|
view.addSubview(controller.view)
|
||||||
|
}
|
||||||
|
}
|
||||||
controller.setIgnoreAppearanceMethodInvocations(false)
|
controller.setIgnoreAppearanceMethodInvocations(false)
|
||||||
view.layer.invalidateUpTheTree()
|
view.layer.invalidateUpTheTree()
|
||||||
controller.viewWillAppear(false)
|
controller.viewWillAppear(false)
|
||||||
@ -115,7 +125,11 @@ final class PresentationContext {
|
|||||||
if let view = self.view, let layout = self.layout {
|
if let view = self.view, let layout = self.layout {
|
||||||
for controller in self.controllers {
|
for controller in self.controllers {
|
||||||
controller.viewWillAppear(false)
|
controller.viewWillAppear(false)
|
||||||
|
if let topLevelSubview = self.topLevelSubview {
|
||||||
|
view.insertSubview(controller.view, belowSubview: topLevelSubview)
|
||||||
|
} else {
|
||||||
view.addSubview(controller.view)
|
view.addSubview(controller.view)
|
||||||
|
}
|
||||||
controller.view.frame = CGRect(origin: CGPoint(), size: layout.size)
|
controller.view.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
controller.containerLayoutUpdated(layout, transition: .immediate)
|
controller.containerLayoutUpdated(layout, transition: .immediate)
|
||||||
controller.viewDidAppear(false)
|
controller.viewDidAppear(false)
|
||||||
@ -141,4 +155,14 @@ final class PresentationContext {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func combinedSupportedOrientations() -> UIInterfaceOrientationMask {
|
||||||
|
var mask: UIInterfaceOrientationMask = .all
|
||||||
|
|
||||||
|
for controller in self.controllers {
|
||||||
|
mask = mask.intersection(controller.supportedInterfaceOrientations)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public class StatusBarSurface {
|
|||||||
public class StatusBar: ASDisplayNode {
|
public class StatusBar: ASDisplayNode {
|
||||||
public var statusBarStyle: StatusBarStyle = .Black {
|
public var statusBarStyle: StatusBarStyle = .Black {
|
||||||
didSet {
|
didSet {
|
||||||
if self.statusBarStyle != statusBarStyle {
|
if self.statusBarStyle != oldValue {
|
||||||
self.layer.invalidateUpTheTree()
|
self.layer.invalidateUpTheTree()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ public class StatusBar: ASDisplayNode {
|
|||||||
return UITracingLayerView()
|
return UITracingLayerView()
|
||||||
}, didLoad: nil)
|
}, didLoad: nil)
|
||||||
|
|
||||||
self.layer.setTraceableInfo(CATracingLayerInfo(shouldBeAdjustedToInverseTransform: true, userData: self, tracingTag: Window.statusBarTracingTag))
|
self.layer.setTraceableInfo(CATracingLayerInfo(shouldBeAdjustedToInverseTransform: true, userData: self, tracingTag: WindowTracingTags.statusBar))
|
||||||
|
|
||||||
self.clipsToBounds = true
|
self.clipsToBounds = true
|
||||||
self.isUserInteractionEnabled = false
|
self.isUserInteractionEnabled = false
|
||||||
|
|||||||
@ -18,7 +18,13 @@ private func mapStatusBar(_ statusBar: StatusBar) -> MappedStatusBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func mappedSurface(_ surface: StatusBarSurface) -> MappedStatusBarSurface {
|
private func mappedSurface(_ surface: StatusBarSurface) -> MappedStatusBarSurface {
|
||||||
return MappedStatusBarSurface(statusBars: surface.statusBars.map(mapStatusBar), surface: surface)
|
var statusBars: [MappedStatusBar] = []
|
||||||
|
for statusBar in surface.statusBars {
|
||||||
|
if statusBar.statusBarStyle != .Ignore {
|
||||||
|
statusBars.append(mapStatusBar(statusBar))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MappedStatusBarSurface(statusBars: statusBars, surface: surface)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func optimizeMappedSurface(statusBarSize: CGSize, surface: MappedStatusBarSurface) -> MappedStatusBarSurface {
|
private func optimizeMappedSurface(statusBarSize: CGSize, surface: MappedStatusBarSurface) -> MappedStatusBarSurface {
|
||||||
@ -70,12 +76,36 @@ class StatusBarManager {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var mappedSurfaces = self.surfaces.map({ optimizeMappedSurface(statusBarSize: statusBarFrame.size, surface: mappedSurface($0)) })
|
var mappedSurfaces: [MappedStatusBarSurface] = []
|
||||||
|
var mapIndex = 0
|
||||||
|
var doNotOptimize = false
|
||||||
|
for surface in self.surfaces {
|
||||||
|
inner: for statusBar in surface.statusBars {
|
||||||
|
if statusBar.statusBarStyle == .Hide {
|
||||||
|
doNotOptimize = true
|
||||||
|
break inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mapped = mappedSurface(surface)
|
||||||
|
|
||||||
|
if doNotOptimize {
|
||||||
|
mappedSurfaces.append(mapped)
|
||||||
|
} else {
|
||||||
|
mappedSurfaces.append(optimizeMappedSurface(statusBarSize: statusBarFrame.size, surface: mapped))
|
||||||
|
}
|
||||||
|
mapIndex += 1
|
||||||
|
}
|
||||||
|
|
||||||
var reduceSurfaces = true
|
var reduceSurfaces = true
|
||||||
var reduceSurfacesStatusBarStyleAndAlpha: (StatusBarStyle, CGFloat)?
|
var reduceSurfacesStatusBarStyleAndAlpha: (StatusBarStyle, CGFloat)?
|
||||||
|
var reduceIndex = 0
|
||||||
outer: for surface in mappedSurfaces {
|
outer: for surface in mappedSurfaces {
|
||||||
for mappedStatusBar in surface.statusBars {
|
for mappedStatusBar in surface.statusBars {
|
||||||
|
if reduceIndex == 0 && mappedStatusBar.style == .Hide {
|
||||||
|
reduceSurfaces = false
|
||||||
|
break outer
|
||||||
|
}
|
||||||
if mappedStatusBar.frame.origin.equalTo(CGPoint()) {
|
if mappedStatusBar.frame.origin.equalTo(CGPoint()) {
|
||||||
let statusBarAlpha = mappedStatusBar.statusBar?.alpha ?? 1.0
|
let statusBarAlpha = mappedStatusBar.statusBar?.alpha ?? 1.0
|
||||||
if let reduceSurfacesStatusBarStyleAndAlpha = reduceSurfacesStatusBarStyleAndAlpha {
|
if let reduceSurfacesStatusBarStyleAndAlpha = reduceSurfacesStatusBarStyleAndAlpha {
|
||||||
@ -92,6 +122,7 @@ class StatusBarManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
reduceIndex += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if reduceSurfaces {
|
if reduceSurfaces {
|
||||||
@ -112,29 +143,33 @@ class StatusBarManager {
|
|||||||
var globalStatusBar: (StatusBarStyle, CGFloat)?
|
var globalStatusBar: (StatusBarStyle, CGFloat)?
|
||||||
|
|
||||||
var coveredIdentity = false
|
var coveredIdentity = false
|
||||||
|
var statusBarIndex = 0
|
||||||
for i in 0 ..< mappedSurfaces.count {
|
for i in 0 ..< mappedSurfaces.count {
|
||||||
for mappedStatusBar in mappedSurfaces[i].statusBars {
|
for mappedStatusBar in mappedSurfaces[i].statusBars {
|
||||||
if let statusBar = mappedStatusBar.statusBar {
|
if let statusBar = mappedStatusBar.statusBar {
|
||||||
if mappedStatusBar.frame.origin.equalTo(CGPoint()) && !statusBar.layer.hasPositionOrOpacityAnimations() {
|
if mappedStatusBar.frame.origin.equalTo(CGPoint()) && !statusBar.layer.hasPositionOrOpacityAnimations() {
|
||||||
if !coveredIdentity {
|
if !coveredIdentity {
|
||||||
|
if statusBar.statusBarStyle != .Hide {
|
||||||
coveredIdentity = CGFloat(1.0).isLessThanOrEqualTo(statusBar.alpha)
|
coveredIdentity = CGFloat(1.0).isLessThanOrEqualTo(statusBar.alpha)
|
||||||
if i == 0 && globalStatusBar == nil {
|
if statusBarIndex == 0 && globalStatusBar == nil {
|
||||||
globalStatusBar = (mappedStatusBar.style, statusBar.alpha)
|
globalStatusBar = (mappedStatusBar.style, statusBar.alpha)
|
||||||
} else {
|
} else {
|
||||||
visibleStatusBars.append(statusBar)
|
visibleStatusBars.append(statusBar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
visibleStatusBars.append(statusBar)
|
visibleStatusBars.append(statusBar)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !coveredIdentity {
|
if !coveredIdentity {
|
||||||
coveredIdentity = true
|
coveredIdentity = true
|
||||||
if i == 0 && globalStatusBar == nil {
|
if statusBarIndex == 0 && globalStatusBar == nil {
|
||||||
globalStatusBar = (mappedStatusBar.style, 1.0)
|
globalStatusBar = (mappedStatusBar.style, 1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
statusBarIndex += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import AsyncDisplayKit
|
|||||||
public enum StatusBarStyle {
|
public enum StatusBarStyle {
|
||||||
case Black
|
case Black
|
||||||
case White
|
case White
|
||||||
|
case Ignore
|
||||||
|
case Hide
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum StatusBarItemType {
|
private enum StatusBarItemType {
|
||||||
@ -142,7 +144,7 @@ private func tintStatusBarItem(_ context: DrawingContext, type: StatusBarItemTyp
|
|||||||
|
|
||||||
let baseColor: UInt32
|
let baseColor: UInt32
|
||||||
switch style {
|
switch style {
|
||||||
case .Black:
|
case .Black, .Ignore, .Hide:
|
||||||
baseColor = 0x000000
|
baseColor = 0x000000
|
||||||
case .White:
|
case .White:
|
||||||
baseColor = 0xffffff
|
baseColor = 0xffffff
|
||||||
@ -193,7 +195,7 @@ private func tintStatusBarItem(_ context: DrawingContext, type: StatusBarItemTyp
|
|||||||
|
|
||||||
let baseColor: UInt32
|
let baseColor: UInt32
|
||||||
switch style {
|
switch style {
|
||||||
case .Black:
|
case .Black, .Ignore, .Hide:
|
||||||
baseColor = 0x000000
|
baseColor = 0x000000
|
||||||
case .White:
|
case .White:
|
||||||
baseColor = 0xffffff
|
baseColor = 0xffffff
|
||||||
|
|||||||
@ -27,6 +27,8 @@ open class SwitchNode: ASDisplayNode {
|
|||||||
override open func didLoad() {
|
override open func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
|
(self.view as! UISwitch).backgroundColor = .white
|
||||||
|
|
||||||
(self.view as! UISwitch).setOn(self._isOn, animated: false)
|
(self.view as! UISwitch).setOn(self._isOn, animated: false)
|
||||||
|
|
||||||
(self.view as! UISwitch).addTarget(self, action: #selector(switchValueChanged(_:)), for: .valueChanged)
|
(self.view as! UISwitch).addTarget(self, action: #selector(switchValueChanged(_:)), for: .valueChanged)
|
||||||
|
|||||||
@ -8,6 +8,6 @@
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
CABasicAnimation * _Nonnull makeSpringAnimation(NSString * _Nonnull keyPath);
|
CABasicAnimation * _Nonnull makeSpringAnimation(NSString * _Nonnull keyPath);
|
||||||
CABasicAnimation * _Nonnull makeSpringBounceAnimation(NSString * _Nonnull keyPath, CGFloat initialVelocity);
|
CABasicAnimation * _Nonnull makeSpringBounceAnimation(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping);
|
||||||
CGFloat springAnimationValueAt(CABasicAnimation * _Nonnull animation, CGFloat t);
|
CGFloat springAnimationValueAt(CABasicAnimation * _Nonnull animation, CGFloat t);
|
||||||
|
|
||||||
|
|||||||
@ -41,11 +41,11 @@ CABasicAnimation * _Nonnull makeSpringAnimation(NSString * _Nonnull keyPath) {
|
|||||||
return springAnimation;
|
return springAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
CABasicAnimation * _Nonnull makeSpringBounceAnimation(NSString * _Nonnull keyPath, CGFloat initialVelocity) {
|
CABasicAnimation * _Nonnull makeSpringBounceAnimation(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping) {
|
||||||
CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:keyPath];
|
CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:keyPath];
|
||||||
springAnimation.mass = 5.0f;
|
springAnimation.mass = 5.0f;
|
||||||
springAnimation.stiffness = 900.0f;
|
springAnimation.stiffness = 900.0f;
|
||||||
springAnimation.damping = 88.0f;
|
springAnimation.damping = damping;
|
||||||
static bool canSetInitialVelocity = true;
|
static bool canSetInitialVelocity = true;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
|
|||||||
@ -118,11 +118,15 @@ public extension UIImage {
|
|||||||
|
|
||||||
private func makeSubtreeSnapshot(layer: CALayer) -> UIView? {
|
private func makeSubtreeSnapshot(layer: CALayer) -> UIView? {
|
||||||
let view = UIView()
|
let view = UIView()
|
||||||
|
//view.layer.isHidden = layer.isHidden
|
||||||
|
view.layer.opacity = layer.opacity
|
||||||
view.layer.contents = layer.contents
|
view.layer.contents = layer.contents
|
||||||
view.layer.contentsRect = layer.contentsRect
|
view.layer.contentsRect = layer.contentsRect
|
||||||
view.layer.contentsScale = layer.contentsScale
|
view.layer.contentsScale = layer.contentsScale
|
||||||
view.layer.contentsCenter = layer.contentsCenter
|
view.layer.contentsCenter = layer.contentsCenter
|
||||||
view.layer.contentsGravity = layer.contentsGravity
|
view.layer.contentsGravity = layer.contentsGravity
|
||||||
|
view.layer.masksToBounds = layer.masksToBounds
|
||||||
|
view.layer.cornerRadius = layer.cornerRadius
|
||||||
if let sublayers = layer.sublayers {
|
if let sublayers = layer.sublayers {
|
||||||
for sublayer in sublayers {
|
for sublayer in sublayers {
|
||||||
let subtree = makeSubtreeSnapshot(layer: sublayer)
|
let subtree = makeSubtreeSnapshot(layer: sublayer)
|
||||||
|
|||||||
@ -33,6 +33,11 @@ open class ViewControllerPresentationArguments {
|
|||||||
private var containerLayout = ContainerViewLayout()
|
private var containerLayout = ContainerViewLayout()
|
||||||
private let presentationContext: PresentationContext
|
private let presentationContext: PresentationContext
|
||||||
|
|
||||||
|
public final var supportedOrientations: UIInterfaceOrientationMask = .all
|
||||||
|
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||||
|
return self.supportedOrientations
|
||||||
|
}
|
||||||
|
|
||||||
public private(set) var presentationArguments: Any?
|
public private(set) var presentationArguments: Any?
|
||||||
|
|
||||||
private var _displayNode: ASDisplayNode?
|
private var _displayNode: ASDisplayNode?
|
||||||
@ -137,9 +142,9 @@ open class ViewControllerPresentationArguments {
|
|||||||
|
|
||||||
let statusBarHeight: CGFloat = layout.statusBarHeight ?? 0.0
|
let statusBarHeight: CGFloat = layout.statusBarHeight ?? 0.0
|
||||||
var navigationBarFrame = CGRect(origin: CGPoint(x: 0.0, y: max(0.0, statusBarHeight - 20.0)), size: CGSize(width: layout.size.width, height: 64.0))
|
var navigationBarFrame = CGRect(origin: CGPoint(x: 0.0, y: max(0.0, statusBarHeight - 20.0)), size: CGSize(width: layout.size.width, height: 64.0))
|
||||||
if statusBarHeight.isLessThanOrEqualTo(0.0) {
|
if layout.statusBarHeight == nil {
|
||||||
navigationBarFrame.origin.y -= 20.0
|
//navigationBarFrame.origin.y -= 20.0
|
||||||
navigationBarFrame.size.height = 20.0 + 32.0
|
navigationBarFrame.size.height = 44.0
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.displayNavigationBar {
|
if !self.displayNavigationBar {
|
||||||
@ -169,7 +174,7 @@ open class ViewControllerPresentationArguments {
|
|||||||
|
|
||||||
open func displayNodeDidLoad() {
|
open func displayNodeDidLoad() {
|
||||||
if let layer = self.displayNode.layer as? CATracingLayer {
|
if let layer = self.displayNode.layer as? CATracingLayer {
|
||||||
layer.setTraceableInfo(CATracingLayerInfo(shouldBeAdjustedToInverseTransform: false, userData: self.displayNode.layer, tracingTag: Window.keyboardTracingTag))
|
layer.setTraceableInfo(CATracingLayerInfo(shouldBeAdjustedToInverseTransform: false, userData: self.displayNode.layer, tracingTag: WindowTracingTags.keyboard))
|
||||||
}
|
}
|
||||||
self.updateScrollToTopView()
|
self.updateScrollToTopView()
|
||||||
}
|
}
|
||||||
@ -195,7 +200,14 @@ open class ViewControllerPresentationArguments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
|
override open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||||
preconditionFailure("use present(_:in)")
|
super.present(viewControllerToPresent, animated: flag, completion: completion)
|
||||||
|
return
|
||||||
|
|
||||||
|
if let controller = viewControllerToPresent as? ViewController {
|
||||||
|
self.present(controller, in: .window)
|
||||||
|
} else {
|
||||||
|
preconditionFailure("use present(_:in) for \(viewControllerToPresent)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
override open func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
|
||||||
@ -206,12 +218,12 @@ open class ViewControllerPresentationArguments {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var window: Window? {
|
public final var window: WindowHost? {
|
||||||
if let window = self.view.window as? Window {
|
if let window = self.view.window as? WindowHost {
|
||||||
return window
|
return window
|
||||||
} else if let superwindow = self.view.window {
|
} else if let superwindow = self.view.window {
|
||||||
for subview in superwindow.subviews {
|
for subview in superwindow.subviews {
|
||||||
if let subview = subview as? Window {
|
if let subview = subview as? WindowHost {
|
||||||
return subview
|
return subview
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,6 +259,6 @@ open class ViewControllerPresentationArguments {
|
|||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func dismiss() {
|
open func dismiss(completion: (() -> Void)? = nil) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,12 +11,6 @@ private class WindowRootViewController: UIViewController {
|
|||||||
override var prefersStatusBarHidden: Bool {
|
override var prefersStatusBarHidden: Bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/*override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
|
|
||||||
if let presentController = self.presentController {
|
|
||||||
presentController(viewControllerToPresent, flag, completion)
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct WindowLayout: Equatable {
|
private struct WindowLayout: Equatable {
|
||||||
@ -115,9 +109,37 @@ private func containedLayoutForWindowLayout(_ layout: WindowLayout) -> Container
|
|||||||
return ContainerViewLayout(size: layout.size, intrinsicInsets: UIEdgeInsets(), statusBarHeight: layout.statusBarHeight, inputHeight: inputHeight)
|
return ContainerViewLayout(size: layout.size, intrinsicInsets: UIEdgeInsets(), statusBarHeight: layout.statusBarHeight, inputHeight: inputHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Window: UIWindow {
|
public final class WindowHostView {
|
||||||
public static let statusBarTracingTag: Int32 = 0
|
public let view: UIView
|
||||||
public static let keyboardTracingTag: Int32 = 1
|
public let isRotating: () -> Bool
|
||||||
|
|
||||||
|
let updateSupportedInterfaceOrientations: (UIInterfaceOrientationMask) -> Void
|
||||||
|
|
||||||
|
var present: ((ViewController) -> Void)?
|
||||||
|
var updateSize: ((CGSize) -> Void)?
|
||||||
|
var layoutSubviews: (() -> Void)?
|
||||||
|
var updateToInterfaceOrientation: (() -> Void)?
|
||||||
|
var isUpdatingOrientationLayout = false
|
||||||
|
var hitTest: ((CGPoint, UIEvent?) -> UIView?)?
|
||||||
|
|
||||||
|
init(view: UIView, isRotating: @escaping () -> Bool, updateSupportedInterfaceOrientations: @escaping (UIInterfaceOrientationMask) -> Void) {
|
||||||
|
self.view = view
|
||||||
|
self.isRotating = isRotating
|
||||||
|
self.updateSupportedInterfaceOrientations = updateSupportedInterfaceOrientations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct WindowTracingTags {
|
||||||
|
public static let statusBar: Int32 = 0
|
||||||
|
public static let keyboard: Int32 = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
public protocol WindowHost {
|
||||||
|
func present(_ controller: ViewController)
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Window1 {
|
||||||
|
public let hostView: WindowHostView
|
||||||
|
|
||||||
private let statusBarHost: StatusBarHost?
|
private let statusBarHost: StatusBarHost?
|
||||||
private let statusBarManager: StatusBarManager?
|
private let statusBarManager: StatusBarManager?
|
||||||
@ -128,15 +150,15 @@ public class Window: UIWindow {
|
|||||||
private var windowLayout: WindowLayout
|
private var windowLayout: WindowLayout
|
||||||
private var updatingLayout: UpdatingLayout?
|
private var updatingLayout: UpdatingLayout?
|
||||||
|
|
||||||
public var isUpdatingOrientationLayout = false
|
|
||||||
|
|
||||||
private let presentationContext: PresentationContext
|
private let presentationContext: PresentationContext
|
||||||
|
|
||||||
private var tracingStatusBarsInvalidated = false
|
private var tracingStatusBarsInvalidated = false
|
||||||
|
|
||||||
private var statusBarHidden = false
|
private var statusBarHidden = false
|
||||||
|
|
||||||
public init(frame: CGRect, statusBarHost: StatusBarHost?) {
|
public init(hostView: WindowHostView, statusBarHost: StatusBarHost?) {
|
||||||
|
self.hostView = hostView
|
||||||
|
|
||||||
self.statusBarHost = statusBarHost
|
self.statusBarHost = statusBarHost
|
||||||
let statusBarHeight: CGFloat
|
let statusBarHeight: CGFloat
|
||||||
if let statusBarHost = statusBarHost {
|
if let statusBarHost = statusBarHost {
|
||||||
@ -156,15 +178,33 @@ public class Window: UIWindow {
|
|||||||
minimized = false
|
minimized = false
|
||||||
}
|
}
|
||||||
|
|
||||||
self.windowLayout = WindowLayout(size: frame.size, statusBarHeight: statusBarHeight, inputHeight: 0.0, inputMinimized: minimized)
|
self.windowLayout = WindowLayout(size: self.hostView.view.bounds.size, statusBarHeight: statusBarHeight, inputHeight: 0.0, inputMinimized: minimized)
|
||||||
self.presentationContext = PresentationContext()
|
self.presentationContext = PresentationContext()
|
||||||
|
|
||||||
super.init(frame: frame)
|
self.hostView.present = { [weak self] controller in
|
||||||
|
self?.present(controller)
|
||||||
|
}
|
||||||
|
|
||||||
self.layer.setInvalidateTracingSublayers { [weak self] in
|
self.hostView.updateSize = { [weak self] size in
|
||||||
|
self?.updateSize(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.hostView.view.layer.setInvalidateTracingSublayers { [weak self] in
|
||||||
self?.invalidateTracingStatusBars()
|
self?.invalidateTracingStatusBars()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.hostView.layoutSubviews = { [weak self] in
|
||||||
|
self?.layoutSubviews()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.hostView.updateToInterfaceOrientation = { [weak self] in
|
||||||
|
self?.updateToInterfaceOrientation()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.hostView.hitTest = { [weak self] point, event in
|
||||||
|
return self?.hitTest(point, with: event)
|
||||||
|
}
|
||||||
|
|
||||||
self.keyboardManager?.minimizedUpdated = { [weak self] in
|
self.keyboardManager?.minimizedUpdated = { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.updateLayout { current in
|
strongSelf.updateLayout { current in
|
||||||
@ -173,24 +213,9 @@ public class Window: UIWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.presentationContext.view = self
|
self.presentationContext.view = self.hostView.view
|
||||||
self.presentationContext.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout), transition: .immediate)
|
self.presentationContext.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout), transition: .immediate)
|
||||||
|
|
||||||
let rootViewController = WindowRootViewController()
|
|
||||||
super.rootViewController = rootViewController
|
|
||||||
rootViewController.viewWillAppear(false)
|
|
||||||
rootViewController.viewDidAppear(false)
|
|
||||||
rootViewController.view.isHidden = true
|
|
||||||
|
|
||||||
rootViewController.presentController = { [weak self] controller, animated, completion in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.present(LegacyPresentedController(legacyController: controller, presentation: .custom))
|
|
||||||
if let completion = completion {
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.statusBarChangeObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationWillChangeStatusBarFrame, object: nil, queue: OperationQueue.main, using: { [weak self] notification in
|
self.statusBarChangeObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationWillChangeStatusBarFrame, object: nil, queue: OperationQueue.main, using: { [weak self] notification in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let statusBarHeight: CGFloat = max(20.0, (notification.userInfo?[UIApplicationStatusBarFrameUserInfoKey] as? NSValue)?.cgRectValue.height ?? 20.0)
|
let statusBarHeight: CGFloat = max(20.0, (notification.userInfo?[UIApplicationStatusBarFrameUserInfoKey] as? NSValue)?.cgRectValue.height ?? 20.0)
|
||||||
@ -205,7 +230,7 @@ public class Window: UIWindow {
|
|||||||
let keyboardFrame: CGRect = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect()
|
let keyboardFrame: CGRect = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect()
|
||||||
let keyboardHeight = max(0.0, UIScreen.main.bounds.size.height - keyboardFrame.minY)
|
let keyboardHeight = max(0.0, UIScreen.main.bounds.size.height - keyboardFrame.minY)
|
||||||
var duration: Double = (notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0
|
var duration: Double = (notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0
|
||||||
if duration > DBL_EPSILON {
|
if duration > Double.ulpOfOne {
|
||||||
duration = 0.5
|
duration = 0.5
|
||||||
}
|
}
|
||||||
let curve: UInt = (notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue ?? 7
|
let curve: UInt = (notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue ?? 7
|
||||||
@ -237,54 +262,36 @@ public class Window: UIWindow {
|
|||||||
|
|
||||||
private func invalidateTracingStatusBars() {
|
private func invalidateTracingStatusBars() {
|
||||||
self.tracingStatusBarsInvalidated = true
|
self.tracingStatusBarsInvalidated = true
|
||||||
self.setNeedsLayout()
|
self.hostView.view.setNeedsLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
for view in self.hostView.view.subviews.reversed() {
|
||||||
|
if NSStringFromClass(type(of: view)) == "UITransitionView" {
|
||||||
|
if let result = view.hitTest(point, with: event) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let result = self._topLevelOverlayController?.view.hitTest(point, with: event) {
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
||||||
if let result = self.presentationContext.hitTest(point, with: event) {
|
if let result = self.presentationContext.hitTest(point, with: event) {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
return self.viewController?.view.hitTest(point, with: event)
|
return self.viewController?.view.hitTest(point, with: event)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override var frame: CGRect {
|
func updateSize(_ value: CGSize) {
|
||||||
get {
|
|
||||||
return super.frame
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
let sizeUpdated = super.frame.size != value.size
|
|
||||||
super.frame = value
|
|
||||||
|
|
||||||
if sizeUpdated {
|
|
||||||
let transition: ContainedViewLayoutTransition
|
let transition: ContainedViewLayoutTransition
|
||||||
if self.isRotating() {
|
if self.hostView.isRotating() {
|
||||||
transition = .animated(duration: orientationChangeDuration, curve: .easeInOut)
|
transition = .animated(duration: orientationChangeDuration, curve: .easeInOut)
|
||||||
} else {
|
} else {
|
||||||
transition = .immediate
|
transition = .immediate
|
||||||
}
|
}
|
||||||
self.updateLayout { $0.update(size: value.size, transition: transition, overrideTransition: true) }
|
self.updateLayout { $0.update(size: value, transition: transition, overrideTransition: true) }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override var bounds: CGRect {
|
|
||||||
get {
|
|
||||||
return super.frame
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
let sizeUpdated = super.bounds.size != value.size
|
|
||||||
super.bounds = value
|
|
||||||
|
|
||||||
if sizeUpdated {
|
|
||||||
let transition: ContainedViewLayoutTransition
|
|
||||||
if self.isRotating() {
|
|
||||||
transition = .animated(duration: orientationChangeDuration, curve: .easeInOut)
|
|
||||||
} else {
|
|
||||||
transition = .immediate
|
|
||||||
}
|
|
||||||
self.updateLayout { $0.update(size: value.size, transition: transition, overrideTransition: true) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var _rootController: ContainableController?
|
private var _rootController: ContainableController?
|
||||||
@ -301,14 +308,33 @@ public class Window: UIWindow {
|
|||||||
if let rootController = self._rootController {
|
if let rootController = self._rootController {
|
||||||
rootController.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout), transition: .immediate)
|
rootController.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout), transition: .immediate)
|
||||||
|
|
||||||
self.addSubview(rootController.view)
|
self.hostView.view.addSubview(rootController.view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func layoutSubviews() {
|
private var _topLevelOverlayController: ContainableController?
|
||||||
super.layoutSubviews()
|
public var topLevelOverlayController: ContainableController? {
|
||||||
|
get {
|
||||||
|
return _topLevelOverlayController
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
if let topLevelOverlayController = self._topLevelOverlayController {
|
||||||
|
topLevelOverlayController.view.removeFromSuperview()
|
||||||
|
}
|
||||||
|
self._topLevelOverlayController = value
|
||||||
|
|
||||||
|
if let topLevelOverlayController = self._topLevelOverlayController {
|
||||||
|
topLevelOverlayController.containerLayoutUpdated(containedLayoutForWindowLayout(self.windowLayout), transition: .immediate)
|
||||||
|
|
||||||
|
self.hostView.view.addSubview(topLevelOverlayController.view)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.presentationContext.topLevelSubview = self._topLevelOverlayController?.view
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func layoutSubviews() {
|
||||||
if self.tracingStatusBarsInvalidated, let statusBarManager = statusBarManager, let keyboardManager = keyboardManager {
|
if self.tracingStatusBarsInvalidated, let statusBarManager = statusBarManager, let keyboardManager = keyboardManager {
|
||||||
self.tracingStatusBarsInvalidated = false
|
self.tracingStatusBarsInvalidated = false
|
||||||
|
|
||||||
@ -316,7 +342,7 @@ public class Window: UIWindow {
|
|||||||
statusBarManager.surfaces = []
|
statusBarManager.surfaces = []
|
||||||
} else {
|
} else {
|
||||||
var statusBarSurfaces: [StatusBarSurface] = []
|
var statusBarSurfaces: [StatusBarSurface] = []
|
||||||
for layers in self.layer.traceableLayerSurfaces(withTag: Window.statusBarTracingTag) {
|
for layers in self.hostView.view.layer.traceableLayerSurfaces(withTag: WindowTracingTags.statusBar) {
|
||||||
let surface = StatusBarSurface()
|
let surface = StatusBarSurface()
|
||||||
for layer in layers {
|
for layer in layers {
|
||||||
let traceableInfo = layer.traceableInfo()
|
let traceableInfo = layer.traceableInfo()
|
||||||
@ -326,12 +352,12 @@ public class Window: UIWindow {
|
|||||||
}
|
}
|
||||||
statusBarSurfaces.append(surface)
|
statusBarSurfaces.append(surface)
|
||||||
}
|
}
|
||||||
self.layer.adjustTraceableLayerTransforms(CGSize())
|
self.hostView.view.layer.adjustTraceableLayerTransforms(CGSize())
|
||||||
statusBarManager.surfaces = statusBarSurfaces
|
statusBarManager.surfaces = statusBarSurfaces
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyboardSurfaces: [KeyboardSurface] = []
|
var keyboardSurfaces: [KeyboardSurface] = []
|
||||||
for layers in self.layer.traceableLayerSurfaces(withTag: Window.keyboardTracingTag) {
|
for layers in self.hostView.view.layer.traceableLayerSurfaces(withTag: WindowTracingTags.keyboard) {
|
||||||
for layer in layers {
|
for layer in layers {
|
||||||
if let view = layer.delegate as? UITracingLayerView {
|
if let view = layer.delegate as? UITracingLayerView {
|
||||||
keyboardSurfaces.append(KeyboardSurface(host: view))
|
keyboardSurfaces.append(KeyboardSurface(host: view))
|
||||||
@ -339,22 +365,23 @@ public class Window: UIWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyboardManager.surfaces = keyboardSurfaces
|
keyboardManager.surfaces = keyboardSurfaces
|
||||||
|
self.hostView.updateSupportedInterfaceOrientations(self.presentationContext.combinedSupportedOrientations())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Window.isDeviceRotating() {
|
if !UIWindow.isDeviceRotating() {
|
||||||
if !self.isUpdatingOrientationLayout {
|
if !self.hostView.isUpdatingOrientationLayout {
|
||||||
self.commitUpdatingLayout()
|
self.commitUpdatingLayout()
|
||||||
} else {
|
} else {
|
||||||
self.addPostUpdateToInterfaceOrientationBlock(f: { [weak self] in
|
self.addPostUpdateToInterfaceOrientationBlock(f: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.setNeedsLayout()
|
strongSelf.hostView.view.setNeedsLayout()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Window.addPostDeviceOrientationDidChange({ [weak self] in
|
UIWindow.addPostDeviceOrientationDidChange({ [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.setNeedsLayout()
|
strongSelf.hostView.view.setNeedsLayout()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -362,11 +389,7 @@ public class Window: UIWindow {
|
|||||||
|
|
||||||
var postUpdateToInterfaceOrientationBlocks: [(Void) -> Void] = []
|
var postUpdateToInterfaceOrientationBlocks: [(Void) -> Void] = []
|
||||||
|
|
||||||
override public func _update(toInterfaceOrientation arg1: Int32, duration arg2: Double, force arg3: Bool) {
|
private func updateToInterfaceOrientation() {
|
||||||
self.isUpdatingOrientationLayout = true
|
|
||||||
super._update(toInterfaceOrientation: arg1, duration: arg2, force: arg3)
|
|
||||||
self.isUpdatingOrientationLayout = false
|
|
||||||
|
|
||||||
let blocks = self.postUpdateToInterfaceOrientationBlocks
|
let blocks = self.postUpdateToInterfaceOrientationBlocks
|
||||||
self.postUpdateToInterfaceOrientationBlocks = []
|
self.postUpdateToInterfaceOrientationBlocks = []
|
||||||
for f in blocks {
|
for f in blocks {
|
||||||
@ -383,14 +406,14 @@ public class Window: UIWindow {
|
|||||||
self.updatingLayout = UpdatingLayout(layout: self.windowLayout, transition: .immediate)
|
self.updatingLayout = UpdatingLayout(layout: self.windowLayout, transition: .immediate)
|
||||||
}
|
}
|
||||||
update(&self.updatingLayout!)
|
update(&self.updatingLayout!)
|
||||||
self.setNeedsLayout()
|
self.hostView.view.setNeedsLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func commitUpdatingLayout() {
|
private func commitUpdatingLayout() {
|
||||||
if let updatingLayout = self.updatingLayout {
|
if let updatingLayout = self.updatingLayout {
|
||||||
self.updatingLayout = nil
|
self.updatingLayout = nil
|
||||||
if updatingLayout.layout != self.windowLayout {
|
if updatingLayout.layout != self.windowLayout {
|
||||||
var statusBarHeight: CGFloat
|
var statusBarHeight: CGFloat?
|
||||||
if let statusBarHost = self.statusBarHost {
|
if let statusBarHost = self.statusBarHost {
|
||||||
statusBarHeight = statusBarHost.statusBarFrame.size.height
|
statusBarHeight = statusBarHost.statusBarFrame.size.height
|
||||||
} else {
|
} else {
|
||||||
@ -398,14 +421,14 @@ public class Window: UIWindow {
|
|||||||
}
|
}
|
||||||
let statusBarWasHidden = self.statusBarHidden
|
let statusBarWasHidden = self.statusBarHidden
|
||||||
if statusBarHiddenInLandscape && updatingLayout.layout.size.width > updatingLayout.layout.size.height {
|
if statusBarHiddenInLandscape && updatingLayout.layout.size.width > updatingLayout.layout.size.height {
|
||||||
statusBarHeight = 0.0
|
statusBarHeight = nil
|
||||||
self.statusBarHidden = true
|
self.statusBarHidden = true
|
||||||
} else {
|
} else {
|
||||||
self.statusBarHidden = false
|
self.statusBarHidden = false
|
||||||
}
|
}
|
||||||
if self.statusBarHidden != statusBarWasHidden {
|
if self.statusBarHidden != statusBarWasHidden {
|
||||||
self.tracingStatusBarsInvalidated = true
|
self.tracingStatusBarsInvalidated = true
|
||||||
self.setNeedsLayout()
|
self.hostView.view.setNeedsLayout()
|
||||||
}
|
}
|
||||||
self.windowLayout = WindowLayout(size: updatingLayout.layout.size, statusBarHeight: statusBarHeight, inputHeight: updatingLayout.layout.inputHeight, inputMinimized: updatingLayout.layout.inputMinimized)
|
self.windowLayout = WindowLayout(size: updatingLayout.layout.size, statusBarHeight: statusBarHeight, inputHeight: updatingLayout.layout.inputHeight, inputMinimized: updatingLayout.layout.inputMinimized)
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user