@apexnative/navigation 1.0.0-alpha.1 → 1.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +147 -51
- package/android/CLAUDE.md +31 -6
- package/android/CORE.md +7 -2
- package/android/RECIPES.md +4 -3
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +29 -1
- package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +5 -4
- package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +3 -2
- package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +5 -4
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +7 -6
- package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +3 -35
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +101 -87
- package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +76 -13
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +86 -16
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +41 -23
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +24 -20
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +25 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +4 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +42 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +29 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +2 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +5 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +4 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +8 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +16 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +287 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +148 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +24 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +51 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +105 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +123 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +19 -0
- package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +5 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +85 -27
- package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +5 -4
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
- package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +45 -1
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +2 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +4 -6
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +4 -6
- package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +15 -0
- package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +137 -1
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +8 -1
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +26 -4
- package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +4 -3
- package/cli/app.js +1 -1
- package/cli/project.js +6 -2
- package/cli/setup/index.js +13 -0
- package/cli/setup/steps/appDelegate.js +66 -11
- package/cli/setup/steps/sceneDelegate.js +108 -0
- package/docs-md/architecture/transitions.md +7 -1
- package/docs-md/containers/modals.md +4 -2
- package/docs-md/containers/overlays.md +3 -1
- package/docs-md/containers/side-menu.md +4 -2
- package/docs-md/containers/tabs.md +2 -0
- package/docs-md/flows/forms-in-a-modal.md +1 -1
- package/docs-md/guides/deep-links.md +15 -33
- package/docs-md/help/glossary.md +1 -1
- package/docs-md/index.json +8 -0
- package/docs-md/screen-ui/back-and-gestures.md +6 -0
- package/docs-md/screen-ui/system-ui.md +1 -1
- package/docs-md/start/installation.md +1 -0
- package/ios/Animations/ANNTransitionAnimator.mm +13 -11
- package/ios/Animations/ANNTransitionWait.mm +6 -7
- package/ios/Animations/Elements/ANNElementFinder.h +57 -0
- package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
- package/ios/Animations/Elements/ANNElementTransition.h +7 -5
- package/ios/Animations/Elements/ANNElementTransition.mm +17 -19
- package/ios/Animations/Elements/ANNSharedElementFlight.h +13 -8
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +59 -24
- package/ios/CLAUDE.md +10 -2
- package/ios/CORE.md +3 -2
- package/ios/Contract/ANNCommandAnswer.h +4 -3
- package/ios/Contract/ANNCommandAnswer.mm +12 -2
- package/ios/Contract/ANNCommandRunner.h +2 -2
- package/ios/Contract/ANNCommandRunner.mm +1 -1
- package/ios/Contract/ANNErrorTexts.h +6 -2
- package/ios/Contract/ANNErrorTexts.mm +18 -10
- package/ios/Core/ANNDeepLinkQueue.h +20 -1
- package/ios/Core/ANNDeepLinkQueue.mm +107 -12
- package/ios/Core/ANNErrorHandler.h +8 -3
- package/ios/Core/ANNErrorHandler.mm +17 -1
- package/ios/Core/ANNEventContract.h +246 -0
- package/ios/Core/ANNEventContract.mm +225 -0
- package/ios/Core/ANNEventEmitter.h +5 -1
- package/ios/Core/ANNEventEmitter.mm +117 -80
- package/ios/Core/ANNHinge.mm +6 -4
- package/ios/Core/ANNSceneDelegate.mm +25 -15
- package/ios/Core/ANNSystemUI.h +3 -2
- package/ios/Core/ANNSystemUI.mm +7 -0
- package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +6 -4
- package/ios/Layouts/Modal/ANNModalCoordinator.mm +1 -1
- package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
- package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
- package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
- package/ios/Layouts/Root/ANNRootCoordinator.mm +12 -3
- package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
- package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
- package/ios/Layouts/Screen/ANNComponentViewController.mm +28 -7
- package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
- package/ios/Layouts/Screen/ANNScreenInsets.mm +6 -4
- package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -6
- package/ios/Layouts/SplitView/ANNSplitViewController.mm +4 -7
- package/ios/Options/ANNSheetOptions.h +4 -1
- package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
- package/ios/RECIPES.md +2 -1
- package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
- package/ios/TurboModules/ANNTurboModule.mm +5 -2
- package/lib/module/ARCHITECTURE.md +7 -4
- package/lib/module/api/app/createNavigation.js +2 -0
- package/lib/module/api/app/createNavigation.js.map +1 -1
- package/lib/module/api/hooks/useNavigation.js +8 -3
- package/lib/module/api/hooks/useNavigation.js.map +1 -1
- package/lib/module/api/linking/dispatchedLinks.js +23 -0
- package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
- package/lib/module/interfaces/contract/errors.json +275 -0
- package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
- package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
- package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
- package/lib/typescript/interfaces/Events.d.ts +9 -0
- package/lib/typescript/interfaces/Events.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/animations.d.ts +27 -18
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/modals.d.ts +33 -24
- package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/sideMenu.d.ts +7 -6
- package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/system.d.ts +10 -6
- package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ARCHITECTURE.md +7 -4
- package/src/api/app/createNavigation.ts +2 -0
- package/src/api/hooks/useNavigation.ts +8 -3
- package/src/api/linking/dispatchedLinks.ts +18 -0
- package/src/interfaces/Events.ts +10 -0
- package/src/interfaces/contract/errors.json +275 -0
- package/src/interfaces/options/animations.ts +27 -18
- package/src/interfaces/options/modals.ts +33 -24
- package/src/interfaces/options/sideMenu.ts +7 -6
- package/src/interfaces/options/system.ts +10 -6
package/ios/Core/ANNHinge.mm
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#import "ANNHinge.h"
|
|
2
2
|
#import "ANNAssert.h"
|
|
3
|
+
#import "ANNEventContract.h"
|
|
3
4
|
#import "ANNUtils.h"
|
|
4
5
|
|
|
5
6
|
NSNotificationName const ANNHingeDidChangeNotification = @"ANNHingeDidChange";
|
|
@@ -34,11 +35,12 @@ static NSDictionary<NSString *, id> *ANNHingeValue(UIHinge *hinge) API_AVAILABLE
|
|
|
34
35
|
if (!hinge) {
|
|
35
36
|
return @{};
|
|
36
37
|
}
|
|
38
|
+
const auto &keys = ANNEventContract.HingeChanged;
|
|
37
39
|
NSString *state = ANNHingeStateName(hinge.status);
|
|
38
40
|
if (hinge.status == UIHingeStatusUnknown) {
|
|
39
|
-
return @{
|
|
41
|
+
return @{keys.state : state};
|
|
40
42
|
}
|
|
41
|
-
return @{
|
|
43
|
+
return @{keys.state : state, keys.angle : @(round(hinge.angle * 1800 / M_PI) / 10)};
|
|
42
44
|
}
|
|
43
45
|
#endif
|
|
44
46
|
|
|
@@ -94,13 +96,13 @@ static NSDictionary<NSString *, id> *ANNHingeValue(UIHinge *hinge) API_AVAILABLE
|
|
|
94
96
|
if ([ANNLastHinge isEqualToDictionary:value]) {
|
|
95
97
|
return;
|
|
96
98
|
}
|
|
97
|
-
previousState = ANNLastHinge[
|
|
99
|
+
previousState = ANNLastHinge[ANNEventContract.HingeChanged.state];
|
|
98
100
|
ANNLastHinge = value;
|
|
99
101
|
}
|
|
100
102
|
if (ANNHingeUpdatesEnabled) {
|
|
101
103
|
[ANNHingeEventEmitter sendHingeChanged:value];
|
|
102
104
|
}
|
|
103
|
-
id state = value[
|
|
105
|
+
id state = value[ANNEventContract.HingeChanged.state];
|
|
104
106
|
if (previousState != state && ![previousState isEqual:state]) {
|
|
105
107
|
[NSNotificationCenter.defaultCenter postNotificationName:ANNHingeDidChangeNotification
|
|
106
108
|
object:nil];
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#import "ANNSceneDelegate.h"
|
|
2
|
+
#import "ANNDeepLinkQueue.h"
|
|
2
3
|
#import "ApexNavigation.h"
|
|
3
|
-
#import <React/RCTLinkingManager.h>
|
|
4
4
|
|
|
5
5
|
// On the scene life cycle UIKit stops calling the app delegate's URL, user activity and foreground/background
|
|
6
|
-
// methods. The scene forwards them, so AppDelegate overrides (and the deep links of ANNDeepLinkQueue) keep working
|
|
6
|
+
// methods. The scene forwards them, so AppDelegate overrides (and the deep links of ANNDeepLinkQueue) keep working; the
|
|
7
|
+
// links keep their scene, through which React Native 0.88 and newer take them.
|
|
7
8
|
@implementation ANNSceneDelegate
|
|
8
9
|
|
|
9
10
|
- (void)scene:(UIScene *)scene
|
|
@@ -15,21 +16,21 @@
|
|
|
15
16
|
self.window = [ApexNavigation attachToWindowScene:(UIWindowScene *)scene];
|
|
16
17
|
|
|
17
18
|
for (UIOpenURLContext *context in connectionOptions.URLContexts) {
|
|
18
|
-
[self ann_openURLContext:context];
|
|
19
|
+
[self ann_openURLContext:context ofScene:scene];
|
|
19
20
|
}
|
|
20
21
|
for (NSUserActivity *activity in connectionOptions.userActivities) {
|
|
21
|
-
[self ann_continueUserActivity:activity];
|
|
22
|
+
[self ann_continueUserActivity:activity ofScene:scene];
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
|
|
26
27
|
for (UIOpenURLContext *context in URLContexts) {
|
|
27
|
-
[self ann_openURLContext:context];
|
|
28
|
+
[self ann_openURLContext:context ofScene:scene];
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity {
|
|
32
|
-
[self ann_continueUserActivity:userActivity];
|
|
33
|
+
[self ann_continueUserActivity:userActivity ofScene:scene];
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
- (void)sceneDidBecomeActive:(UIScene *)scene {
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
|
|
63
64
|
#pragma mark - private
|
|
64
65
|
|
|
65
|
-
- (void)ann_openURLContext:(UIOpenURLContext *)context {
|
|
66
|
+
- (void)ann_openURLContext:(UIOpenURLContext *)context ofScene:(UIScene *)scene {
|
|
66
67
|
UIApplication *application = UIApplication.sharedApplication;
|
|
67
68
|
id<UIApplicationDelegate> appDelegate = application.delegate;
|
|
68
69
|
if ([appDelegate respondsToSelector:@selector(application:openURL:options:)]) {
|
|
@@ -70,22 +71,31 @@
|
|
|
70
71
|
options[UIApplicationOpenURLOptionsSourceApplicationKey] = context.options.sourceApplication;
|
|
71
72
|
options[UIApplicationOpenURLOptionsAnnotationKey] = context.options.annotation;
|
|
72
73
|
options[UIApplicationOpenURLOptionsOpenInPlaceKey] = @(context.options.openInPlace);
|
|
73
|
-
[
|
|
74
|
+
[ANNDeepLinkQueue forwardURLContext:context
|
|
75
|
+
ofScene:scene
|
|
76
|
+
through:^{
|
|
77
|
+
[appDelegate application:application openURL:context.URL options:options];
|
|
78
|
+
}];
|
|
74
79
|
} else {
|
|
75
|
-
[
|
|
80
|
+
[ANNDeepLinkQueue openURLContext:context ofScene:scene];
|
|
76
81
|
}
|
|
77
82
|
}
|
|
78
83
|
|
|
79
|
-
- (void)ann_continueUserActivity:(NSUserActivity *)activity {
|
|
84
|
+
- (void)ann_continueUserActivity:(NSUserActivity *)activity ofScene:(UIScene *)scene {
|
|
80
85
|
UIApplication *application = UIApplication.sharedApplication;
|
|
81
86
|
id<UIApplicationDelegate> appDelegate = application.delegate;
|
|
82
87
|
if ([appDelegate respondsToSelector:@selector(application:continueUserActivity:restorationHandler:)]) {
|
|
83
|
-
[
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
[ANNDeepLinkQueue forwardUserActivity:activity
|
|
89
|
+
ofScene:scene
|
|
90
|
+
through:^{
|
|
91
|
+
[appDelegate application:application
|
|
92
|
+
continueUserActivity:activity
|
|
93
|
+
restorationHandler:^(
|
|
94
|
+
NSArray<id<UIUserActivityRestoring>> *restorableObjects){
|
|
95
|
+
}];
|
|
96
|
+
}];
|
|
87
97
|
} else if ([activity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
|
|
88
|
-
[
|
|
98
|
+
[ANNDeepLinkQueue openUserActivity:activity ofScene:scene];
|
|
89
99
|
}
|
|
90
100
|
}
|
|
91
101
|
|
package/ios/Core/ANNSystemUI.h
CHANGED
|
@@ -36,8 +36,9 @@ typedef NS_ENUM(NSInteger, ANNSystemUIQuestion) {
|
|
|
36
36
|
/// The owner adds the asks UIKit doesn't make — a merge, a side menu at rest, an overlay, a root replaced, the bar of a
|
|
37
37
|
/// stack shown or hidden, the orientation after an appearance — and makes them once per turn of the main queue: a
|
|
38
38
|
/// trigger marks groups, the marks of a turn are coalesced, and at its end UIKit is asked again for each marked group
|
|
39
|
-
/// in the main window and every overlay window.
|
|
40
|
-
///
|
|
39
|
+
/// in the main window and every overlay window. Each ask of the status bar also lays out the screens' blurs under it
|
|
40
|
+
/// (`statusBar.blur`), then and on the next turn. It keeps no values but the last status bar of each window, which
|
|
41
|
+
/// only chooses whether a change of the style animates. Never a wait. Main queue.
|
|
41
42
|
@interface ANNSystemUI : NSObject
|
|
42
43
|
|
|
43
44
|
- (instancetype)init NS_UNAVAILABLE;
|
package/ios/Core/ANNSystemUI.mm
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#import "ANNSystemUI.h"
|
|
2
2
|
#import "ANNAssert.h"
|
|
3
|
+
#import "ANNComponentPresenter.h"
|
|
3
4
|
#import "ANNComponentViewController.h"
|
|
4
5
|
#import "ANNDefaultOptions.h"
|
|
5
6
|
#import "ANNOverlayCoordinator.h"
|
|
@@ -280,6 +281,12 @@ static NSArray<UIViewController *> *ANNChainOf(UIWindow *window) {
|
|
|
280
281
|
ask();
|
|
281
282
|
}
|
|
282
283
|
}
|
|
284
|
+
// The status bar hidden or shown moves no view where the safe area stays (a device with a notch): the blurs under
|
|
285
|
+
// it take its frame now, and once more on the next turn of the main queue, in case UIKit settles it after the ask.
|
|
286
|
+
[ANNComponentPresenter statusBarDidChange];
|
|
287
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
288
|
+
[ANNComponentPresenter statusBarDidChange];
|
|
289
|
+
});
|
|
283
290
|
}
|
|
284
291
|
|
|
285
292
|
// A controller that is no node of the layout (React Native's `<Modal>`, an alert, the splash) animates as UIKit's
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
#import "ANNArrangementState.h"
|
|
6
6
|
#import "ANNComponentViewController.h"
|
|
7
|
+
#import "ANNEventContract.h"
|
|
7
8
|
#import "ANNExternalViewController.h"
|
|
8
9
|
#import "ANNShownScreens.h"
|
|
9
10
|
#import "ANNUtils.h"
|
|
@@ -130,11 +131,12 @@ static BOOL ANNKeepsState(UIViewController *screen) {
|
|
|
130
131
|
|
|
131
132
|
static NSDictionary<NSString *, id> *ANNStateOf(NSString *placement, NSString *layout, BOOL front,
|
|
132
133
|
BOOL hidden) {
|
|
134
|
+
const auto &keys = ANNEventContract.ArrangementChanged;
|
|
133
135
|
return @{
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
keys.placement : placement,
|
|
137
|
+
keys.layout : layout,
|
|
138
|
+
keys.front : @(front),
|
|
139
|
+
keys.hidden : @(hidden),
|
|
138
140
|
};
|
|
139
141
|
}
|
|
140
142
|
|
|
@@ -407,7 +407,7 @@ static void ANNCollectIds(UIViewController *node, NSMutableSet<NSString *> *ids)
|
|
|
407
407
|
ANNNavigationOptions *resolved = [root resolveOptionsWithDefault];
|
|
408
408
|
ANNModalPresentation *presentation =
|
|
409
409
|
[[ANNModalPresentation alloc] initWithOptions:resolved animated:modal.animatedOverride];
|
|
410
|
-
NSString *problem = [presentation
|
|
410
|
+
NSString *problem = [presentation fitToPresenting:presenting windowRoot:windowRoot];
|
|
411
411
|
if (problem) {
|
|
412
412
|
[self failShowOf:modal reason:problem];
|
|
413
413
|
done();
|
|
@@ -20,7 +20,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
20
20
|
|
|
21
21
|
/// `modalPresentationStyle`: one to one; unset is UIKit's automatic style; an unknown string full screen.
|
|
22
22
|
@property(nonatomic, readonly) UIModalPresentationStyle style;
|
|
23
|
-
/// `modalTransitionStyle`: `coverVertical` unless one of the others is given
|
|
23
|
+
/// `modalTransitionStyle`: `coverVertical` unless one of the others is given; `partialCurl` only where UIKit curls
|
|
24
|
+
/// (`fitToPresenting:windowRoot:`).
|
|
24
25
|
@property(nonatomic, readonly) UIModalTransitionStyle transitionStyle;
|
|
25
26
|
/// The present is animated: `enter.enabled` is not `false`.
|
|
26
27
|
@property(nonatomic, readonly) BOOL animated;
|
|
@@ -47,10 +48,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
47
48
|
animation:(nullable ANNModalAnimationOptions *)animation
|
|
48
49
|
under:(nullable UIViewController *)under;
|
|
49
50
|
|
|
50
|
-
///
|
|
51
|
-
///
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
/// Fits the show to `presenting`, before `prepare:…`: `partialCurl` stays only for a full-screen modal over a
|
|
52
|
+
/// controller that fills the screen (`presenting` is `windowRoot`, the main window's root, or a full-screen modal);
|
|
53
|
+
/// otherwise `transitionStyle` becomes `coverVertical`. Returns why UIKit can't make the show (`presenting` was shown
|
|
54
|
+
/// with `partialCurl`), as the reason of the rejection; nil when it can.
|
|
55
|
+
- (nullable NSString *)fitToPresenting:(UIViewController *)presenting
|
|
56
|
+
windowRoot:(nullable UIViewController *)windowRoot;
|
|
54
57
|
|
|
55
58
|
/// Before `presentViewController:`: the style and the transition, the presentation's delegate, the popover kept a
|
|
56
59
|
/// popover (`adaptive: false`), the sheet, the size, the popover's source on `presentingLayout`, the hold, the
|
|
@@ -118,21 +118,21 @@ static NSDictionary<NSString *, NSNumber *> *ANNTransitionStyles(void) {
|
|
|
118
118
|
return nil;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
// UIKit
|
|
122
|
-
// shown with `partialCurl` presents nothing more: the command
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
// UIKit curls only a full-screen modal over a controller that fills the screen: elsewhere `partialCurl` is
|
|
122
|
+
// `coverVertical`, so the modal still shows. A controller shown with `partialCurl` presents nothing more: the command
|
|
123
|
+
// rejects before it asks UIKit.
|
|
124
|
+
- (NSString *)fitToPresenting:(UIViewController *)presenting
|
|
125
|
+
windowRoot:(UIViewController *)windowRoot {
|
|
125
126
|
if (presenting.presentingViewController &&
|
|
126
127
|
presenting.modalTransitionStyle == UIModalTransitionStylePartialCurl) {
|
|
127
|
-
return @"partialCurl
|
|
128
|
+
return @"a modal shown with partialCurl can't show another modal";
|
|
128
129
|
}
|
|
129
|
-
if (_transitionStyle
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return @"partialCurl needs a full screen modal";
|
|
130
|
+
if (_transitionStyle == UIModalTransitionStylePartialCurl) {
|
|
131
|
+
BOOL presentingFills = presenting == windowRoot ||
|
|
132
|
+
presenting.modalPresentationStyle == UIModalPresentationFullScreen;
|
|
133
|
+
if (_style != UIModalPresentationFullScreen || !presentingFills) {
|
|
134
|
+
_transitionStyle = UIModalTransitionStyleCoverVertical;
|
|
135
|
+
}
|
|
136
136
|
}
|
|
137
137
|
return nil;
|
|
138
138
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#import "ANNSheetPresenter.h"
|
|
2
2
|
#import "ANNModalSizePresenter.h"
|
|
3
3
|
#import "ANNReactView.h"
|
|
4
|
+
#import "ANNUtils.h"
|
|
4
5
|
#import "UIViewController+LayoutProtocol.h"
|
|
5
6
|
#import <React/RCTLog.h>
|
|
6
7
|
#import <objc/runtime.h>
|
|
@@ -53,7 +54,7 @@ static NSString *const ANNContentDetent = @"content";
|
|
|
53
54
|
+ (void)applyOptions:(ANNSheetOptions *)options toSheet:(UISheetPresentationController *)sheet {
|
|
54
55
|
if (options.detents) {
|
|
55
56
|
NSMutableArray<UISheetPresentationControllerDetent *> *detents = [NSMutableArray new];
|
|
56
|
-
for (id value in options.detents) {
|
|
57
|
+
for (id value in [self sortedDetents:options.detents ofSheet:sheet]) {
|
|
57
58
|
UISheetPresentationControllerDetent *detent = [self detentFor:value ofSheet:sheet];
|
|
58
59
|
if (detent) {
|
|
59
60
|
[detents addObject:detent];
|
|
@@ -81,6 +82,85 @@ static NSString *const ANNContentDetent = @"content";
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
// UIKit wants the detents once each, from the lowest to the highest: it takes the last for the largest and closes the
|
|
86
|
+
// sheet on a drag down from the first. The options may give them in any order and more than once; the first of a
|
|
87
|
+
// repeat stays, and detents of the same height keep their order.
|
|
88
|
+
+ (NSArray *)sortedDetents:(NSArray *)values ofSheet:(UISheetPresentationController *)sheet {
|
|
89
|
+
NSMutableArray *detents = [NSMutableArray new];
|
|
90
|
+
NSMutableSet<NSString *> *identifiers = [NSMutableSet new];
|
|
91
|
+
for (id value in values) {
|
|
92
|
+
NSString *identifier = [self identifierFor:value];
|
|
93
|
+
if (identifier && ![identifiers containsObject:identifier]) {
|
|
94
|
+
[identifiers addObject:identifier];
|
|
95
|
+
[detents addObject:value];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
CGFloat maximum = [self maximumDetentHeightOf:sheet];
|
|
99
|
+
return [detents sortedArrayWithOptions:NSSortStable
|
|
100
|
+
usingComparator:^NSComparisonResult(id a, id b) {
|
|
101
|
+
return [self compareHeightOf:a
|
|
102
|
+
with:b
|
|
103
|
+
maximum:maximum
|
|
104
|
+
ofSheet:sheet];
|
|
105
|
+
}];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// The content of a sheet sized to it changed its height, and with it maybe its place among the other detents.
|
|
109
|
+
+ (void)sortDetentsOfSheet:(UISheetPresentationController *)sheet API_AVAILABLE(ios(16.0)) {
|
|
110
|
+
CGFloat maximum = [self maximumDetentHeightOf:sheet];
|
|
111
|
+
NSArray<UISheetPresentationControllerDetent *> *detents = sheet.detents;
|
|
112
|
+
NSArray<UISheetPresentationControllerDetent *> *sorted = [detents
|
|
113
|
+
sortedArrayWithOptions:NSSortStable
|
|
114
|
+
usingComparator:^NSComparisonResult(UISheetPresentationControllerDetent *a,
|
|
115
|
+
UISheetPresentationControllerDetent *b) {
|
|
116
|
+
return [self compareHeightOf:[self detentForIdentifier:a.identifier]
|
|
117
|
+
with:[self detentForIdentifier:b.identifier]
|
|
118
|
+
maximum:maximum
|
|
119
|
+
ofSheet:sheet];
|
|
120
|
+
}];
|
|
121
|
+
if (![sorted isEqualToArray:detents]) {
|
|
122
|
+
sheet.detents = sorted;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
+ (NSComparisonResult)compareHeightOf:(id)a
|
|
127
|
+
with:(id)b
|
|
128
|
+
maximum:(CGFloat)maximum
|
|
129
|
+
ofSheet:(UISheetPresentationController *)sheet {
|
|
130
|
+
CGFloat heightA = [self heightOf:a maximum:maximum ofSheet:sheet];
|
|
131
|
+
CGFloat heightB = [self heightOf:b maximum:maximum ofSheet:sheet];
|
|
132
|
+
return heightA < heightB ? NSOrderedAscending
|
|
133
|
+
: heightA > heightB ? NSOrderedDescending : NSOrderedSame;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// The height a detent of the options stands at, to sort them, as its resolver gives it: 'medium' half of the largest
|
|
137
|
+
// height (UIKit's is about half), 'large' all of it, a height capped at it, 'content' the content's height now, all of
|
|
138
|
+
// it while the content isn't measured.
|
|
139
|
+
+ (CGFloat)heightOf:(id)value
|
|
140
|
+
maximum:(CGFloat)maximum
|
|
141
|
+
ofSheet:(UISheetPresentationController *)sheet {
|
|
142
|
+
if ([value isEqual:@"medium"]) {
|
|
143
|
+
return maximum / 2;
|
|
144
|
+
}
|
|
145
|
+
if ([value isKindOfClass:NSNumber.class]) {
|
|
146
|
+
return MIN([value doubleValue], maximum);
|
|
147
|
+
}
|
|
148
|
+
if ([value isEqual:ANNContentDetent]) {
|
|
149
|
+
CGFloat height = [self contentHeightOf:sheet.presentedViewController];
|
|
150
|
+
return height > 0 ? MIN(height, maximum) : maximum;
|
|
151
|
+
}
|
|
152
|
+
return maximum;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// About the largest height of a sheet: its container, or the window before it is shown, below the top safe area.
|
|
156
|
+
+ (CGFloat)maximumDetentHeightOf:(UISheetPresentationController *)sheet {
|
|
157
|
+
UIView *view = sheet.containerView ?: ANNUtils.mainWindow;
|
|
158
|
+
if (!view) {
|
|
159
|
+
return ANNUtils.mainScreen.bounds.size.height;
|
|
160
|
+
}
|
|
161
|
+
return view.bounds.size.height - view.safeAreaInsets.top;
|
|
162
|
+
}
|
|
163
|
+
|
|
84
164
|
+ (UISheetPresentationControllerDetent *)detentFor:(id)value
|
|
85
165
|
ofSheet:(UISheetPresentationController *)sheet {
|
|
86
166
|
if ([value isEqual:@"medium"]) {
|
|
@@ -180,6 +260,7 @@ static NSString *const ANNContentDetent = @"content";
|
|
|
180
260
|
}
|
|
181
261
|
height = newHeight;
|
|
182
262
|
[strongSheet animateChanges:^{
|
|
263
|
+
[self sortDetentsOfSheet:strongSheet];
|
|
183
264
|
[strongSheet invalidateDetents];
|
|
184
265
|
}];
|
|
185
266
|
}
|
|
@@ -201,6 +282,7 @@ static NSString *const ANNContentDetent = @"content";
|
|
|
201
282
|
// The new screen's content mounts may come later: its mounts resolve the detents again too.
|
|
202
283
|
[self followContentOfSheet:sheet when:YES];
|
|
203
284
|
[sheet animateChanges:^{
|
|
285
|
+
[self sortDetentsOfSheet:sheet];
|
|
204
286
|
[sheet invalidateDetents];
|
|
205
287
|
}];
|
|
206
288
|
}
|
|
@@ -69,7 +69,10 @@ typedef NS_ENUM(NSInteger, ANNRootShowState) {
|
|
|
69
69
|
// The nodes whose appearance the transition reports itself (`driveAppearanceOf:`), while `driving`.
|
|
70
70
|
@property(nonatomic, copy) NSArray<UIViewController *> *driven;
|
|
71
71
|
@property(nonatomic) BOOL driving;
|
|
72
|
+
// The snapshot of the window as it was: it dissolves over the new root (`dissolves`), plays its `exit` (`custom`), or
|
|
73
|
+
// only covers the old root's modals while they go, and leaves as the new root is the window's.
|
|
72
74
|
@property(nonatomic, strong, nullable) UIView *snapshot;
|
|
75
|
+
@property(nonatomic) BOOL dissolves;
|
|
73
76
|
// The root is the window's root: the old root's modals went before it (`startTransitionOf:done:`).
|
|
74
77
|
@property(nonatomic) BOOL installed;
|
|
75
78
|
// The root's view waits in the window under the current root (`park:`).
|
|
@@ -415,9 +418,14 @@ static __weak ANNRootShow *ANNAnimatingShow;
|
|
|
415
418
|
BOOL seen = !window.hidden && scene != nil &&
|
|
416
419
|
scene.activationState != UISceneActivationStateBackground;
|
|
417
420
|
BOOL dissolves = !overSplash && !enterDisabled && !custom && seen;
|
|
421
|
+
show.dissolves = dissolves;
|
|
418
422
|
show.custom = custom && seen;
|
|
419
|
-
|
|
420
|
-
|
|
423
|
+
// UIKit draws the dismissal of the old root's modals, without animation too (a sheet's dim goes a frame before
|
|
424
|
+
// its card): with nothing to dissolve, the snapshot covers them until the new root is in place.
|
|
425
|
+
BOOL covers = seen && old.presentedViewController != nil;
|
|
426
|
+
UIView *snapshot = dissolves || show.custom || covers
|
|
427
|
+
? [window snapshotViewAfterScreenUpdates:NO]
|
|
428
|
+
: nil;
|
|
421
429
|
|
|
422
430
|
show.state = ANNRootShowStateTransition;
|
|
423
431
|
// It shows from here: a stack in it counts as on screen.
|
|
@@ -480,7 +488,8 @@ static __weak ANNRootShow *ANNAnimatingShow;
|
|
|
480
488
|
[self endTransitionOf:show];
|
|
481
489
|
return;
|
|
482
490
|
}
|
|
483
|
-
|
|
491
|
+
// A snapshot that only covered the old root's modals leaves in this turn, with the new root in place under it.
|
|
492
|
+
if (!snapshot || !show.dissolves) {
|
|
484
493
|
[self endTransitionOf:show];
|
|
485
494
|
return;
|
|
486
495
|
}
|
|
@@ -19,11 +19,19 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
19
19
|
/// it. Nothing before the screen's view is loaded.
|
|
20
20
|
- (void)applyBackground:(ANNNavigationOptions *)resolvedOptions;
|
|
21
21
|
|
|
22
|
-
/// `statusBar.blur` (iOS): UIKit's regular blur over the screen's own view in the frame of the scene's status bar
|
|
23
|
-
///
|
|
24
|
-
///
|
|
22
|
+
/// `statusBar.blur` (iOS): UIKit's regular blur over the screen's own view in the frame of the scene's status bar (x 0,
|
|
23
|
+
/// the view's width), laid out at once; `false` or none removes it. At each appearance and at a merge that names it;
|
|
24
|
+
/// nothing before the screen's view is loaded.
|
|
25
25
|
- (void)applyStatusBarBlur:(ANNNavigationOptions *)resolvedOptions;
|
|
26
26
|
|
|
27
|
+
/// The blur takes the status bar's frame as it is now; nothing without a blur. The single place of its frame: the blur
|
|
28
|
+
/// as it is applied, the screen's view laid out (a rotation, a new window size, a new safe area), a size transition
|
|
29
|
+
/// along its animation and at its end, the turn after new traits, and `statusBarDidChange`.
|
|
30
|
+
- (void)layOutStatusBarBlur;
|
|
31
|
+
|
|
32
|
+
/// The status bar was asked again (hidden or shown, a new style): every blur takes its frame.
|
|
33
|
+
+ (void)statusBarDidChange;
|
|
34
|
+
|
|
27
35
|
/// The blur stays the last subview of the screen's view: the content added after it goes under it.
|
|
28
36
|
- (void)keepStatusBarBlurOnTop;
|
|
29
37
|
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
#import "ANNTopBarPresenter.h"
|
|
6
6
|
#import "ANNUtils.h"
|
|
7
7
|
|
|
8
|
+
// The presenters whose screen shows `statusBar.blur`: the status bar hidden or shown lays out no view, so they hear of
|
|
9
|
+
// it from the system UI (`statusBarDidChange`).
|
|
10
|
+
static NSHashTable<ANNComponentPresenter *> *ANNBlurringPresenters;
|
|
11
|
+
|
|
8
12
|
@implementation ANNComponentPresenter {
|
|
9
13
|
// `statusBar.blur` while it is on.
|
|
10
14
|
UIVisualEffectView *_statusBarBlur;
|
|
@@ -95,9 +99,7 @@
|
|
|
95
99
|
|
|
96
100
|
#pragma mark - The status bar's blur (`statusBar.blur`)
|
|
97
101
|
|
|
98
|
-
// Over the screen's own view, never over a React view; no touches, nothing for VoiceOver.
|
|
99
|
-
// status bar's as it is now, in the view's own coordinates without a conversion: a pushed screen's view may still be
|
|
100
|
-
// out of place while it appears.
|
|
102
|
+
// Over the screen's own view, never over a React view; no touches, nothing for VoiceOver.
|
|
101
103
|
- (void)applyStatusBarBlur:(ANNNavigationOptions *)resolvedOptions {
|
|
102
104
|
ANNComponentViewController *screen = self.screen;
|
|
103
105
|
if (!screen.isViewLoaded) {
|
|
@@ -106,6 +108,7 @@
|
|
|
106
108
|
if (![resolvedOptions.statusBar.blur withDefault:NO]) {
|
|
107
109
|
[_statusBarBlur removeFromSuperview];
|
|
108
110
|
_statusBarBlur = nil;
|
|
111
|
+
[ANNBlurringPresenters removeObject:self];
|
|
109
112
|
return;
|
|
110
113
|
}
|
|
111
114
|
UIView *view = screen.view;
|
|
@@ -115,15 +118,40 @@
|
|
|
115
118
|
_statusBarBlur.userInteractionEnabled = NO;
|
|
116
119
|
_statusBarBlur.isAccessibilityElement = NO;
|
|
117
120
|
_statusBarBlur.accessibilityElementsHidden = YES;
|
|
121
|
+
if (!ANNBlurringPresenters) {
|
|
122
|
+
ANNBlurringPresenters = [NSHashTable weakObjectsHashTable];
|
|
123
|
+
}
|
|
124
|
+
[ANNBlurringPresenters addObject:self];
|
|
118
125
|
}
|
|
119
|
-
CGRect statusBar = ANNUtils.statusBarFrame;
|
|
120
|
-
_statusBarBlur.frame = CGRectMake(0, CGRectGetMinY(statusBar), CGRectGetWidth(view.bounds),
|
|
121
|
-
CGRectGetHeight(statusBar));
|
|
122
126
|
if (_statusBarBlur.superview != view) {
|
|
123
127
|
[view addSubview:_statusBarBlur];
|
|
124
128
|
} else {
|
|
125
129
|
[view bringSubviewToFront:_statusBarBlur];
|
|
126
130
|
}
|
|
131
|
+
[self layOutStatusBarBlur];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// The status bar's frame in the scene of the screen's window (the main window's before the screen is in one), in the
|
|
135
|
+
// view's own coordinates without a conversion: a pushed screen's view may still be out of place while it appears. A
|
|
136
|
+
// hidden status bar has no frame, and the blur no height.
|
|
137
|
+
- (void)layOutStatusBarBlur {
|
|
138
|
+
UIView *view = _statusBarBlur.superview;
|
|
139
|
+
if (!view) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
UIWindowScene *scene = view.window.windowScene;
|
|
143
|
+
CGRect statusBar = scene ? scene.statusBarManager.statusBarFrame : ANNUtils.statusBarFrame;
|
|
144
|
+
CGRect frame = CGRectMake(0, CGRectGetMinY(statusBar), CGRectGetWidth(view.bounds),
|
|
145
|
+
CGRectGetHeight(statusBar));
|
|
146
|
+
if (!CGRectEqualToRect(_statusBarBlur.frame, frame)) {
|
|
147
|
+
_statusBarBlur.frame = frame;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
+ (void)statusBarDidChange {
|
|
152
|
+
for (ANNComponentPresenter *presenter in ANNBlurringPresenters.allObjects) {
|
|
153
|
+
[presenter layOutStatusBarBlur];
|
|
154
|
+
}
|
|
127
155
|
}
|
|
128
156
|
|
|
129
157
|
- (void)keepStatusBarBlurOnTop {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#import "ANNArrangementState.h"
|
|
4
4
|
#import "ANNBottomTabsController.h"
|
|
5
5
|
#import "ANNComponentPresenter.h"
|
|
6
|
+
#import "ANNEventContract.h"
|
|
6
7
|
#import "ANNHinge.h"
|
|
7
8
|
#import "ANNKeyCommands.h"
|
|
8
9
|
#import "ANNNodeRegistry.h"
|
|
@@ -66,6 +67,12 @@
|
|
|
66
67
|
|
|
67
68
|
#pragma mark - The view
|
|
68
69
|
|
|
70
|
+
- (nullable ANNComponentPresenter *)componentPresenter {
|
|
71
|
+
ANNNodePresenter *presenter = self.presenter;
|
|
72
|
+
return [presenter isKindOfClass:ANNComponentPresenter.class] ? (ANNComponentPresenter *)presenter
|
|
73
|
+
: nil;
|
|
74
|
+
}
|
|
75
|
+
|
|
69
76
|
// The size of the screen of the navigation window's scene, not the deprecated main screen: a surface made before the
|
|
70
77
|
// screen is in a window starts with the width it will have.
|
|
71
78
|
- (void)loadView {
|
|
@@ -94,6 +101,22 @@
|
|
|
94
101
|
}
|
|
95
102
|
// The pair the screen is in may lie otherwise now.
|
|
96
103
|
[self.arrangement screenDidChangeLayout:self];
|
|
104
|
+
[self.componentPresenter layOutStatusBarBlur];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// UIKit names the size transition as the moment the status bar's frame changes (a rotation, a new window size): the
|
|
108
|
+
// blur follows it along the animation and takes the final frame at its end.
|
|
109
|
+
- (void)viewWillTransitionToSize:(CGSize)size
|
|
110
|
+
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
|
111
|
+
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
|
112
|
+
__weak ANNComponentViewController *weakSelf = self;
|
|
113
|
+
[coordinator
|
|
114
|
+
animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
|
115
|
+
[weakSelf.componentPresenter layOutStatusBarBlur];
|
|
116
|
+
}
|
|
117
|
+
completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
|
118
|
+
[weakSelf.componentPresenter layOutStatusBarBlur];
|
|
119
|
+
}];
|
|
97
120
|
}
|
|
98
121
|
|
|
99
122
|
- (void)viewSafeAreaInsetsDidChange {
|
|
@@ -110,6 +133,7 @@
|
|
|
110
133
|
__weak ANNComponentViewController *weakSelf = self;
|
|
111
134
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
112
135
|
[weakSelf updateRootLayout];
|
|
136
|
+
[weakSelf.componentPresenter layOutStatusBarBlur];
|
|
113
137
|
});
|
|
114
138
|
}
|
|
115
139
|
|
|
@@ -200,9 +224,7 @@
|
|
|
200
224
|
#pragma mark - The root frame and the safe area
|
|
201
225
|
|
|
202
226
|
- (void)applyBackground {
|
|
203
|
-
|
|
204
|
-
[(ANNComponentPresenter *)self.presenter applyBackground:[self resolveOptionsWithDefault]];
|
|
205
|
-
}
|
|
227
|
+
[self.componentPresenter applyBackground:[self resolveOptionsWithDefault]];
|
|
206
228
|
}
|
|
207
229
|
|
|
208
230
|
// The navigation controller that shows the screen's stack: the stack, or UIKit's More navigation while a tab of More
|
|
@@ -434,7 +456,8 @@
|
|
|
434
456
|
if (!regions) {
|
|
435
457
|
return;
|
|
436
458
|
}
|
|
437
|
-
|
|
459
|
+
const auto &keys = ANNEventContract.ScreenRegionsChanged;
|
|
460
|
+
BOOL empty = [regions[keys.division] count] == 0 && [regions[keys.occlusion] count] == 0;
|
|
438
461
|
if (empty && ![ANNScreenRegions regionsForScreenId:componentId]) {
|
|
439
462
|
return;
|
|
440
463
|
}
|
|
@@ -606,9 +629,7 @@
|
|
|
606
629
|
content.autoresizingMask = UIViewAutoresizingNone;
|
|
607
630
|
content.frame = [self rootFrameForOptions:[self resolveOptionsWithDefault]];
|
|
608
631
|
[view addSubview:content];
|
|
609
|
-
|
|
610
|
-
[(ANNComponentPresenter *)self.presenter keepStatusBarBlurOnTop];
|
|
611
|
-
}
|
|
632
|
+
[self.componentPresenter keepStatusBarBlurOnTop];
|
|
612
633
|
[self applyBackground];
|
|
613
634
|
[self updateRootLayout];
|
|
614
635
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#import "ANNNativeScreenContext+Internal.h"
|
|
2
2
|
#import "ANNErrorTexts.h"
|
|
3
|
+
#import "ANNEventContract.h"
|
|
3
4
|
#import "ANNEventEmitter.h"
|
|
4
5
|
#import "ANNNativeScreenCalls.h"
|
|
5
6
|
#import <React/RCTUtils.h>
|
|
@@ -71,12 +72,13 @@
|
|
|
71
72
|
componentId:self->_componentId]];
|
|
72
73
|
return;
|
|
73
74
|
}
|
|
75
|
+
const auto &keys = ANNEventContract.NativeScreenCall;
|
|
74
76
|
[eventEmitter sendNativeScreenCall:@{
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
keys.componentId : self->_componentId,
|
|
78
|
+
keys.callId : callId,
|
|
79
|
+
keys.kind : kind,
|
|
80
|
+
keys.name : name,
|
|
81
|
+
keys.args : arguments ?: @[],
|
|
80
82
|
}];
|
|
81
83
|
});
|
|
82
84
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#import "ANNScreenInsets.h"
|
|
2
|
+
#import "ANNEventContract.h"
|
|
2
3
|
|
|
3
4
|
NSNotificationName const ANNScreenSafeAreaPaddingDidChangeNotification = @"ANNScreenSafeAreaPaddingDidChange";
|
|
4
5
|
|
|
@@ -26,11 +27,12 @@ static NSMutableDictionary<NSString *, NSValue *> *ANNScreenPaddingById;
|
|
|
26
27
|
object:screenId];
|
|
27
28
|
}
|
|
28
29
|
// JavaScript gets what still covers the content: the edges the safe area view keeps it off are 0.
|
|
30
|
+
const auto &keys = ANNEventContract.ScreenInsetsChanged;
|
|
29
31
|
NSDictionary<NSString *, NSNumber *> *value = @{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
keys.top : @(MAX(insets.top - padding.top, 0)),
|
|
33
|
+
keys.right : @(MAX(insets.right - padding.right, 0)),
|
|
34
|
+
keys.bottom : @(MAX(insets.bottom - padding.bottom, 0)),
|
|
35
|
+
keys.left : @(MAX(insets.left - padding.left, 0)),
|
|
34
36
|
};
|
|
35
37
|
@synchronized(ANNScreenInsetsById) {
|
|
36
38
|
if ([ANNScreenInsetsById[screenId] isEqualToDictionary:value]) {
|