@apexnative/navigation 1.0.0-alpha.5 → 1.0.0-alpha.6
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 +25 -0
- package/README.md +1 -1
- package/android/CLAUDE.md +14 -12
- package/android/CORE.md +9 -6
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +36 -5
- package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +0 -2
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +12 -49
- package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
- package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +9 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +13 -10
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +7 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +20 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +119 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +7 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +4 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +4 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +3 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
- package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
- package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
- package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +9 -2
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +11 -0
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +318 -25
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +18 -20
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +17 -25
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +15 -22
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +12 -9
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +84 -35
- package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +49 -40
- package/docs-md/architecture/transitions.md +4 -2
- package/docs-md/containers/modals.md +2 -0
- package/docs-md/containers/overlays.md +1 -1
- package/docs-md/containers/side-menu.md +1 -1
- package/docs-md/containers/tabs.md +2 -0
- package/docs-md/flows/bottom-sheets.md +1 -1
- package/docs-md/fundamentals/starting-the-app.md +1 -1
- package/docs-md/help/glossary.md +2 -2
- package/docs-md/help/troubleshooting.md +21 -0
- package/docs-md/index.json +12 -0
- package/docs-md/migration/from-expo-router.md +1 -1
- package/docs-md/migration/from-react-native-navigation.md +1 -1
- package/docs-md/migration/from-react-navigation.md +2 -2
- package/docs-md/screen-ui/back-and-gestures.md +14 -0
- package/docs-md/screen-ui/bar-buttons.md +4 -4
- package/docs-md/screen-ui/search.md +1 -1
- package/docs-md/screen-ui/system-ui.md +16 -11
- package/docs-md/screen-ui/toolbar-and-fab.md +2 -2
- package/docs-md/screen-ui/top-bar.md +8 -4
- package/ios/Animations/ANNFrameDriver.mm +2 -0
- package/ios/Animations/Elements/ANNSharedElementFlight.mm +70 -4
- package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
- package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
- package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
- package/ios/Animations/Interpolators/ANNViewTracks.h +6 -4
- package/ios/Animations/Interpolators/ANNViewTracks.mm +49 -9
- package/ios/CLAUDE.md +17 -15
- package/ios/CORE.md +24 -20
- package/ios/Contract/ANNCommandRunner.h +8 -7
- package/ios/Contract/ANNCommandRunner.mm +21 -27
- package/ios/Contract/ANNLayoutNode.h +3 -3
- package/ios/Contract/ANNLayoutReader.h +3 -3
- package/ios/Core/ANNJavaScriptCalls.h +11 -12
- package/ios/Core/ANNJavaScriptCalls.mm +7 -16
- package/ios/Core/ANNReloadCoordinator.mm +4 -8
- package/ios/Core/ApexNavigation+Internal.h +1 -1
- package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
- package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
- package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +4 -4
- package/ios/Layouts/Screen/ANNComponentViewController.h +2 -2
- package/ios/Layouts/Screen/ANNComponentViewController.mm +9 -22
- package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
- package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
- package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
- package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
- package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
- package/ios/Layouts/Screen/ANNScreenRegions.mm +0 -38
- package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
- package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
- package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
- package/ios/Layouts/Stack/ANNPreviewPush.mm +57 -5
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
- package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.mm +2 -1
- package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +4 -0
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +123 -36
- package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
- package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
- package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
- package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
- package/ios/Options/ANNBottomTabsOptions.h +2 -0
- package/ios/Options/ANNBottomTabsOptions.mm +1 -0
- package/ios/Options/ANNOptions.h +18 -0
- package/ios/Options/ANNOptions.mm +112 -1
- package/ios/Options/ANNOptionsReader.mm +110 -0
- package/ios/Options/Params/ANNParam.h +15 -0
- package/ios/Options/Params/ANNParam.mm +61 -0
- package/ios/Options/Params/Color.h +3 -0
- package/ios/Options/Params/Color.mm +21 -0
- package/ios/Options/Params/Image.h +4 -0
- package/ios/Options/Params/Image.mm +20 -0
- package/ios/React/ANNReactView.mm +6 -25
- package/ios/React/ANNSafeAreaViewComponentView.mm +26 -15
- package/ios/React/ANNSurfaceHostingView.h +6 -0
- package/ios/React/ANNSurfaceHostingView.mm +116 -0
- package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
- package/ios/TopBar/ANNBarAppearance.h +2 -1
- package/ios/TopBar/ANNBarAppearance.mm +111 -30
- package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
- package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
- package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
- package/ios/TopBar/ANNBarButtons.h +5 -3
- package/ios/TopBar/ANNBarButtons.mm +186 -17
- package/ios/TopBar/ANNLargeTitlePresenter.mm +24 -4
- package/ios/TopBar/ANNMainList.h +3 -0
- package/ios/TopBar/ANNMainList.mm +4 -0
- package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
- package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
- package/ios/TopBar/ANNSearchPresenter.mm +2 -2
- package/ios/TopBar/ANNSearchResultsViewController.mm +5 -5
- package/ios/TopBar/ANNTopBarPresenter.h +3 -2
- package/ios/TopBar/ANNTopBarPresenter.mm +95 -22
- package/ios/TurboModules/ANNTurboModule.mm +20 -16
- package/lib/module/ARCHITECTURE.md +8 -4
- package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
- package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
- package/lib/module/api/options/OptionsChain.js +2 -2
- package/lib/module/engine/commands.js +21 -1
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/screens.js +29 -4
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/typescript/api/app/createNavigation.d.ts +3 -3
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
- package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
- package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
- package/lib/typescript/engine/commands.d.ts.map +1 -1
- package/lib/typescript/engine/screens.d.ts +20 -6
- package/lib/typescript/engine/screens.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/animations.d.ts +12 -7
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/bottomTabs.d.ts +18 -5
- package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +8 -8
- package/lib/typescript/interfaces/options/system.d.ts +8 -5
- package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
- package/lib/typescript/interfaces/options/topBar.d.ts +32 -29
- package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ARCHITECTURE.md +8 -4
- package/src/api/app/createNavigation.ts +3 -3
- package/src/api/hooks/useSafeAreaInsets.ts +4 -3
- package/src/api/options/OptionsChain.ts +2 -2
- package/src/engine/commands.ts +30 -6
- package/src/engine/screens.tsx +29 -8
- package/src/interfaces/options/animations.ts +12 -7
- package/src/interfaces/options/bottomTabs.ts +18 -5
- package/src/interfaces/options/buttons.ts +8 -8
- package/src/interfaces/options/system.ts +8 -5
- package/src/interfaces/options/toolbar.ts +2 -2
- package/src/interfaces/options/topBar.ts +32 -29
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -42
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -70
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
- package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
- package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -70
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
#import "ANNComponentViewController.h"
|
|
2
2
|
#import "ANNAppearanceDispatcher.h"
|
|
3
|
-
#import "ANNArrangementState.h"
|
|
4
3
|
#import "ANNBottomTabsController.h"
|
|
5
4
|
#import "ANNComponentPresenter.h"
|
|
6
|
-
#import "ANNEventContract.h"
|
|
7
5
|
#import "ANNHinge.h"
|
|
8
6
|
#import "ANNKeyCommands.h"
|
|
9
7
|
#import "ANNNodeRegistry.h"
|
|
@@ -11,7 +9,7 @@
|
|
|
11
9
|
#import "ANNPendingLayers.h"
|
|
12
10
|
#import "ANNPreviewPush.h"
|
|
13
11
|
#import "ANNScreenBars.h"
|
|
14
|
-
#import "
|
|
12
|
+
#import "ANNScreenEnvironment.h"
|
|
15
13
|
#import "ANNScreenReadiness.h"
|
|
16
14
|
#import "ANNScreenRegions.h"
|
|
17
15
|
#import "ANNScreenSafeArea.h"
|
|
@@ -432,7 +430,7 @@
|
|
|
432
430
|
return UIRectEdgeNone;
|
|
433
431
|
}
|
|
434
432
|
|
|
435
|
-
// The insets and the padding of a React screen or a slot screen go to the
|
|
433
|
+
// The insets and the padding of a React screen or a slot screen go to the store, which keeps them, gives JavaScript
|
|
436
434
|
// what still covers the content and tells only of changes; the regions in the same pass. Only in a window and with an
|
|
437
435
|
// id; never after the destroy, which removed them (a late layout would bring them back), nor for the JavaScript that
|
|
438
436
|
// went (an old screen held after a reload: the new JavaScript may give its id to a new screen).
|
|
@@ -453,22 +451,18 @@
|
|
|
453
451
|
UINavigationController *stack = [self shownNavigation];
|
|
454
452
|
ANNScreenPaddingContext context = {
|
|
455
453
|
.inStack = stack != nil,
|
|
456
|
-
// The stack's toolbar, by the rule the stack shows it with: one that `topBar.hideOnScroll`
|
|
457
|
-
// hid with the bar still counts.
|
|
458
|
-
.stackShowsToolbar = stack != nil && options.toolbar.shouldShow,
|
|
459
|
-
.windowBottomSafeArea = window.safeAreaInsets.bottom,
|
|
460
454
|
.verticalBarSide = [self verticalBarSide],
|
|
461
455
|
};
|
|
462
456
|
UIEdgeInsets padding = ANNScreenPadding(insets, options, context);
|
|
463
|
-
[
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
457
|
+
[ANNScreenEnvironment setInsets:insets
|
|
458
|
+
padding:padding
|
|
459
|
+
forScreenId:componentId
|
|
460
|
+
eventEmitter:eventEmitter];
|
|
467
461
|
[self updateRegions];
|
|
468
462
|
}
|
|
469
463
|
|
|
470
464
|
// The regions in the same pass, and on the next turn after a change of the hinge's state (`hingeDidChange:`). Nil
|
|
471
|
-
// before iOS 27.1: nothing to keep.
|
|
465
|
+
// before iOS 27.1: nothing to keep. The store neither keeps nor sends an empty first result.
|
|
472
466
|
- (void)updateRegions {
|
|
473
467
|
UIView<ANNComponentProtocol> *content = _reactView;
|
|
474
468
|
NSString *componentId = self.layoutInfo.componentId;
|
|
@@ -483,12 +477,7 @@
|
|
|
483
477
|
if (!regions) {
|
|
484
478
|
return;
|
|
485
479
|
}
|
|
486
|
-
|
|
487
|
-
BOOL empty = [regions[keys.division] count] == 0 && [regions[keys.occlusion] count] == 0;
|
|
488
|
-
if (empty && ![ANNScreenRegions regionsForScreenId:componentId]) {
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
[ANNScreenRegions setRegions:regions forScreenId:componentId eventEmitter:eventEmitter];
|
|
480
|
+
[ANNScreenEnvironment setRegions:regions forScreenId:componentId eventEmitter:eventEmitter];
|
|
492
481
|
}
|
|
493
482
|
|
|
494
483
|
- (void)hingeDidChange:(NSNotification *)notification {
|
|
@@ -690,9 +679,7 @@
|
|
|
690
679
|
// its destroy, as at a reload) keeps it.
|
|
691
680
|
NSString *componentId = self.layoutInfo.componentId;
|
|
692
681
|
if (componentId && ![ANNNodeRegistry nodeForComponentId:componentId]) {
|
|
693
|
-
[
|
|
694
|
-
[ANNScreenRegions removeScreenId:componentId];
|
|
695
|
-
[ANNArrangementState removeScreenId:componentId];
|
|
682
|
+
[ANNScreenEnvironment removeScreenId:componentId];
|
|
696
683
|
[ANNScreenReadiness removeScreenId:componentId];
|
|
697
684
|
}
|
|
698
685
|
}
|
|
@@ -9,15 +9,18 @@
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Previews `preview` from `view`, the component view with the tag `reactTag`, and replaces an earlier
|
|
12
|
-
* preview of the view. `
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* preview of the view. `prepare` runs as each press starts, before the menu shows the preview: it
|
|
13
|
+
* renders the screen if it hasn't yet, and returns NO when the preview went instead (no menu shows
|
|
14
|
+
* then). `commit` runs on a tap on the preview and returns whether it showed the screen; the
|
|
15
|
+
* preview goes then, as the push it stands for is done. `dismissed` runs once when the preview
|
|
16
|
+
* goes without being shown as a screen: replaced by another preview of the view, after Fabric gave
|
|
17
|
+
* the view to another component, or when `source`, the screen of the view, goes.
|
|
16
18
|
*/
|
|
17
19
|
+ (void)attachPreview:(UIViewController *)preview
|
|
18
20
|
toView:(UIView *)view
|
|
19
21
|
reactTag:(NSInteger)reactTag
|
|
20
22
|
source:(UIViewController *)source
|
|
23
|
+
prepare:(BOOL (^)(void))prepare
|
|
21
24
|
commit:(BOOL (^)(void))commit
|
|
22
25
|
dismissed:(void (^)(void))dismissed;
|
|
23
26
|
|
|
@@ -24,15 +24,23 @@ static NSMutableSet *ANNPreviews(void) {
|
|
|
24
24
|
@implementation ANNPreviewInteraction {
|
|
25
25
|
UIViewController *_preview;
|
|
26
26
|
NSInteger _reactTag;
|
|
27
|
+
__weak UIViewController *_source;
|
|
28
|
+
BOOL (^_prepare)(void);
|
|
27
29
|
BOOL (^_commit)(void);
|
|
28
30
|
void (^_dismissed)(void);
|
|
29
31
|
UIContextMenuInteraction *_interaction;
|
|
32
|
+
// The snapshots of the view that the menu of this press lifts and puts back, over the view until
|
|
33
|
+
// the menu is gone. Each press has its own list: a new press may start while the last menu goes.
|
|
34
|
+
NSMutableArray<UIView *> *_snapshots;
|
|
35
|
+
// The list of the menu that goes now: its end removes them.
|
|
36
|
+
__weak NSMutableArray<UIView *> *_endingSnapshots;
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
+ (void)attachPreview:(UIViewController *)preview
|
|
33
40
|
toView:(UIView *)view
|
|
34
41
|
reactTag:(NSInteger)reactTag
|
|
35
42
|
source:(UIViewController *)source
|
|
43
|
+
prepare:(BOOL (^)(void))prepare
|
|
36
44
|
commit:(BOOL (^)(void))commit
|
|
37
45
|
dismissed:(void (^)(void))dismissed {
|
|
38
46
|
if (!view || !preview) {
|
|
@@ -45,6 +53,8 @@ static NSMutableSet *ANNPreviews(void) {
|
|
|
45
53
|
ANNPreviewInteraction *previewInteraction = [ANNPreviewInteraction new];
|
|
46
54
|
previewInteraction->_preview = preview;
|
|
47
55
|
previewInteraction->_reactTag = reactTag;
|
|
56
|
+
previewInteraction->_source = source;
|
|
57
|
+
previewInteraction->_prepare = [prepare copy];
|
|
48
58
|
previewInteraction->_commit = [commit copy];
|
|
49
59
|
previewInteraction->_dismissed = [dismissed copy];
|
|
50
60
|
previewInteraction->_interaction =
|
|
@@ -91,7 +101,9 @@ static NSMutableSet *ANNPreviews(void) {
|
|
|
91
101
|
[view removeInteraction:_interaction];
|
|
92
102
|
// A tap's commit animation may still run: a preview that went, its screen destroyed and its push failed, is not
|
|
93
103
|
// pushed when the animation ends.
|
|
104
|
+
_prepare = nil;
|
|
94
105
|
_commit = nil;
|
|
106
|
+
[ANNPreviewInteraction removeSnapshots:_snapshots];
|
|
95
107
|
void (^dismissed)(void) = _dismissed;
|
|
96
108
|
_dismissed = nil;
|
|
97
109
|
if (dismissed) {
|
|
@@ -116,6 +128,18 @@ static NSMutableSet *ANNPreviews(void) {
|
|
|
116
128
|
[self detach];
|
|
117
129
|
return nil;
|
|
118
130
|
}
|
|
131
|
+
// UIKit ends a lift that never became a menu too (the touch ended before the long press); should
|
|
132
|
+
// it not, the snapshot of that press goes now.
|
|
133
|
+
if (_snapshots != _endingSnapshots) {
|
|
134
|
+
[ANNPreviewInteraction removeSnapshots:_snapshots];
|
|
135
|
+
}
|
|
136
|
+
_snapshots = [NSMutableArray new];
|
|
137
|
+
// UIKit asks for the configuration as the press starts, about half a second before it shows the preview: the
|
|
138
|
+
// screen renders now, so that its content is there by then.
|
|
139
|
+
if (_prepare && !_prepare()) {
|
|
140
|
+
[self detach];
|
|
141
|
+
return nil;
|
|
142
|
+
}
|
|
119
143
|
UIViewController *preview = _preview;
|
|
120
144
|
NSArray *actions = preview.resolveOptions.preview.actions;
|
|
121
145
|
return [UIContextMenuConfiguration
|
|
@@ -129,6 +153,23 @@ static NSMutableSet *ANNPreviews(void) {
|
|
|
129
153
|
}];
|
|
130
154
|
}
|
|
131
155
|
|
|
156
|
+
// The menu goes: the snapshots of its press go once it is gone. UIKit asks for the one
|
|
157
|
+
// it goes back to after this call, so the list is read at the end, not now.
|
|
158
|
+
- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
159
|
+
willEndForConfiguration:(UIContextMenuConfiguration *)configuration
|
|
160
|
+
animator:(id<UIContextMenuInteractionAnimating>)animator {
|
|
161
|
+
NSMutableArray<UIView *> *snapshots = _snapshots;
|
|
162
|
+
_endingSnapshots = snapshots;
|
|
163
|
+
void (^remove)(void) = ^{
|
|
164
|
+
[ANNPreviewInteraction removeSnapshots:snapshots];
|
|
165
|
+
};
|
|
166
|
+
if (animator) {
|
|
167
|
+
[animator addCompletion:remove];
|
|
168
|
+
} else {
|
|
169
|
+
dispatch_async(dispatch_get_main_queue(), remove);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
132
173
|
- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
133
174
|
willPerformPreviewActionForMenuWithConfiguration:(UIContextMenuConfiguration *)configuration
|
|
134
175
|
animator:(id<UIContextMenuInteractionCommitAnimating>)
|
|
@@ -148,24 +189,45 @@ static NSMutableSet *ANNPreviews(void) {
|
|
|
148
189
|
|
|
149
190
|
#pragma mark - Targeted previews
|
|
150
191
|
|
|
151
|
-
// The view the menu lifts from and goes back to: a snapshot of the source view
|
|
152
|
-
//
|
|
153
|
-
//
|
|
192
|
+
// The view the menu lifts from and goes back to: a snapshot of the source view, laid over it in the
|
|
193
|
+
// view of its screen, the core's own (in its window when the view is elsewhere), so that it goes with
|
|
194
|
+
// the screen (a pop right after the menu). With the source view itself UIKit adds its views next to
|
|
195
|
+
// it, among the React views of its parent, and Fabric then mounts and unmounts at the wrong places.
|
|
196
|
+
// A snapshot out of the window, with only a target there, iOS 27 doesn't lift: it dims it in place.
|
|
154
197
|
- (UITargetedPreview *)snapshotPreviewOf:(UIView *)view {
|
|
155
|
-
|
|
198
|
+
UIView *container = _source.viewIfLoaded;
|
|
199
|
+
if (!container || ![view isDescendantOfView:container]) {
|
|
200
|
+
container = view.window;
|
|
201
|
+
}
|
|
202
|
+
// A screen out of its window (a command took it away while the menu showed) has no place for it:
|
|
203
|
+
// UIKit needs the view in a window.
|
|
204
|
+
if (!container.window) {
|
|
205
|
+
return nil;
|
|
206
|
+
}
|
|
156
207
|
UIView *snapshot = [view snapshotViewAfterScreenUpdates:NO];
|
|
157
|
-
if (!
|
|
208
|
+
if (!snapshot) {
|
|
158
209
|
return nil;
|
|
159
210
|
}
|
|
211
|
+
snapshot.frame = [view convertRect:view.bounds toView:container];
|
|
212
|
+
snapshot.userInteractionEnabled = NO;
|
|
213
|
+
snapshot.accessibilityElementsHidden = YES;
|
|
214
|
+
[container addSubview:snapshot];
|
|
215
|
+
if (!_snapshots) {
|
|
216
|
+
_snapshots = [NSMutableArray new];
|
|
217
|
+
}
|
|
218
|
+
[_snapshots addObject:snapshot];
|
|
160
219
|
UIPreviewParameters *parameters = [UIPreviewParameters new];
|
|
161
220
|
parameters.backgroundColor = UIColor.clearColor;
|
|
162
221
|
parameters.visiblePath = [UIBezierPath bezierPathWithRoundedRect:view.bounds
|
|
163
222
|
cornerRadius:view.layer.cornerRadius];
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
223
|
+
return [[UITargetedPreview alloc] initWithView:snapshot parameters:parameters];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
+ (void)removeSnapshots:(NSMutableArray<UIView *> *)snapshots {
|
|
227
|
+
for (UIView *snapshot in snapshots) {
|
|
228
|
+
[snapshot removeFromSuperview];
|
|
229
|
+
}
|
|
230
|
+
[snapshots removeAllObjects];
|
|
169
231
|
}
|
|
170
232
|
|
|
171
233
|
- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#import "ANNEventEmitter.h"
|
|
2
|
+
#import <UIKit/UIKit.h>
|
|
3
|
+
|
|
4
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
5
|
+
|
|
6
|
+
/// A view that keeps a screen's content out of its padding (the screen's safe area view).
|
|
7
|
+
@protocol ANNScreenPaddingListener <NSObject>
|
|
8
|
+
/// The padding of its screen changed. Main queue.
|
|
9
|
+
- (void)screenPaddingDidChange;
|
|
10
|
+
@end
|
|
11
|
+
|
|
12
|
+
/// What JavaScript knows of each screen's place, by the screen's id, in one record: its safe area (the insets
|
|
13
|
+
/// JavaScript gets, `useSafeAreaInsets`, and the padding of its safe area view), its reserved regions
|
|
14
|
+
/// (`useReservedRegions`) and, in a pair, its arrangement (`useArrangement`). The core measures them
|
|
15
|
+
/// (`ANNScreenSafeArea`, `ANNScreenRegions`, the pair's layout) on the main queue and keeps them here; JavaScript reads
|
|
16
|
+
/// them from its own thread for a screen's first render, under one lock, and gets every change as an event. When the
|
|
17
|
+
/// screen goes, `removeScreenId:` clears all of it. As on Android (`ScreenEnvironment`).
|
|
18
|
+
@interface ANNScreenEnvironment : NSObject
|
|
19
|
+
|
|
20
|
+
/// Keeps the screen's insets and the padding of its safe area view. The padding is the part of the insets the safe
|
|
21
|
+
/// area view keeps the content out of (the edges the screen's options give); JavaScript gets the rest, what still
|
|
22
|
+
/// covers the content (0 on a padded edge). Tells the padding's listeners of that screen when the padding changed, then
|
|
23
|
+
/// JavaScript (`ANN.ScreenInsetsChanged`) when its insets did. Main queue.
|
|
24
|
+
+ (void)setInsets:(UIEdgeInsets)insets
|
|
25
|
+
padding:(UIEdgeInsets)padding
|
|
26
|
+
forScreenId:(NSString *)screenId
|
|
27
|
+
eventEmitter:(ANNEventEmitter *)eventEmitter;
|
|
28
|
+
/// The padding of the screen's safe area view; none before the screen was laid out. Any thread.
|
|
29
|
+
+ (UIEdgeInsets)paddingForScreenId:(NSString *)screenId;
|
|
30
|
+
/// `{ top, right, bottom, left }`, or nil before the screen was laid out. Any thread.
|
|
31
|
+
+ (nullable NSDictionary<NSString *, NSNumber *> *)insetsForScreenId:(NSString *)screenId;
|
|
32
|
+
|
|
33
|
+
/// Keeps the screen's regions (`{ division, occlusion }`) and tells JavaScript (`ANN.ScreenRegionsChanged`) when they
|
|
34
|
+
/// changed. None at first is what JavaScript reads before the first layout: it is neither kept nor told. Main queue.
|
|
35
|
+
+ (void)setRegions:(NSDictionary<NSString *, NSArray *> *)regions
|
|
36
|
+
forScreenId:(NSString *)screenId
|
|
37
|
+
eventEmitter:(ANNEventEmitter *)eventEmitter;
|
|
38
|
+
/// `{ division, occlusion }`, or nil before the screen's regions were first kept. Any thread.
|
|
39
|
+
+ (nullable NSDictionary<NSString *, NSArray *> *)regionsForScreenId:(NSString *)screenId;
|
|
40
|
+
|
|
41
|
+
/// Keeps the screen's arrangement (`{ placement, layout, front, hidden }`) and tells JavaScript
|
|
42
|
+
/// (`ANN.ArrangementChanged`) when it changed; nothing goes without an emitter. Main queue.
|
|
43
|
+
+ (void)setArrangement:(NSDictionary<NSString *, id> *)arrangement
|
|
44
|
+
forScreenId:(NSString *)screenId
|
|
45
|
+
eventEmitter:(nullable ANNEventEmitter *)eventEmitter;
|
|
46
|
+
/// The screen's arrangement, or nil for a screen outside a pair. Any thread.
|
|
47
|
+
+ (nullable NSDictionary<NSString *, id> *)arrangementForScreenId:(NSString *)screenId;
|
|
48
|
+
|
|
49
|
+
/// Tells `listener` of each change of the screen's padding, until it is removed or goes (held weakly). Several
|
|
50
|
+
/// listeners may listen to one screen. Main queue.
|
|
51
|
+
+ (void)addPaddingListener:(id<ANNScreenPaddingListener>)listener forScreenId:(NSString *)screenId;
|
|
52
|
+
+ (void)removePaddingListener:(id<ANNScreenPaddingListener>)listener
|
|
53
|
+
forScreenId:(NSString *)screenId;
|
|
54
|
+
|
|
55
|
+
/// Forgets everything kept for the screen. Its padding listeners stay: a live safe area view keeps listening while it
|
|
56
|
+
/// keeps the id, and stops itself. Main queue.
|
|
57
|
+
+ (void)removeScreenId:(NSString *)screenId;
|
|
58
|
+
/// Forgets every screen: after a reload the new JavaScript counts its ids anew. Main queue.
|
|
59
|
+
+ (void)removeAll;
|
|
60
|
+
|
|
61
|
+
@end
|
|
62
|
+
|
|
63
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#import "ANNScreenEnvironment.h"
|
|
2
|
+
#import "ANNEventContract.h"
|
|
3
|
+
|
|
4
|
+
// One screen's record; nil for a fact not known yet (not laid out, no regions, outside a pair). Changed and read only
|
|
5
|
+
// under the lock of `ANNEnvironmentById`; the values are immutable, so a reader keeps what it took.
|
|
6
|
+
@interface ANNScreenEnvironmentRecord : NSObject
|
|
7
|
+
@property(nonatomic, copy, nullable) NSDictionary<NSString *, NSNumber *> *insets;
|
|
8
|
+
@property(nonatomic, strong, nullable) NSValue *padding;
|
|
9
|
+
@property(nonatomic, copy, nullable) NSDictionary<NSString *, NSArray *> *regions;
|
|
10
|
+
@property(nonatomic, copy, nullable) NSDictionary<NSString *, id> *arrangement;
|
|
11
|
+
@end
|
|
12
|
+
|
|
13
|
+
@implementation ANNScreenEnvironmentRecord
|
|
14
|
+
@end
|
|
15
|
+
|
|
16
|
+
// Written on the main queue, read from any thread: every access holds its lock.
|
|
17
|
+
static NSMutableDictionary<NSString *, ANNScreenEnvironmentRecord *> *ANNEnvironmentById;
|
|
18
|
+
// The safe area views of each screen, by its id (the id's value: the view's id and the core's are other strings), held
|
|
19
|
+
// weakly. Main queue only.
|
|
20
|
+
static NSMutableDictionary<NSString *, NSHashTable<id<ANNScreenPaddingListener>> *>
|
|
21
|
+
*ANNPaddingListenersById;
|
|
22
|
+
|
|
23
|
+
@implementation ANNScreenEnvironment
|
|
24
|
+
|
|
25
|
+
+ (void)initialize {
|
|
26
|
+
if (self == ANNScreenEnvironment.class) {
|
|
27
|
+
ANNEnvironmentById = [NSMutableDictionary new];
|
|
28
|
+
ANNPaddingListenersById = [NSMutableDictionary new];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// The screen's record, a new one for a screen not kept yet. Under the lock.
|
|
33
|
+
+ (ANNScreenEnvironmentRecord *)recordOf:(NSString *)screenId {
|
|
34
|
+
ANNScreenEnvironmentRecord *record = ANNEnvironmentById[screenId];
|
|
35
|
+
if (!record) {
|
|
36
|
+
record = [ANNScreenEnvironmentRecord new];
|
|
37
|
+
ANNEnvironmentById[screenId] = record;
|
|
38
|
+
}
|
|
39
|
+
return record;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#pragma mark - Insets and padding
|
|
43
|
+
|
|
44
|
+
+ (void)setInsets:(UIEdgeInsets)insets
|
|
45
|
+
padding:(UIEdgeInsets)padding
|
|
46
|
+
forScreenId:(NSString *)screenId
|
|
47
|
+
eventEmitter:(ANNEventEmitter *)eventEmitter {
|
|
48
|
+
NSValue *paddingValue = [NSValue valueWithUIEdgeInsets:padding];
|
|
49
|
+
// JavaScript gets what still covers the content: the edges the safe area view keeps it off are 0.
|
|
50
|
+
const auto &keys = ANNEventContract.ScreenInsetsChanged;
|
|
51
|
+
NSDictionary<NSString *, NSNumber *> *value = @{
|
|
52
|
+
keys.top : @(MAX(insets.top - padding.top, 0)),
|
|
53
|
+
keys.right : @(MAX(insets.right - padding.right, 0)),
|
|
54
|
+
keys.bottom : @(MAX(insets.bottom - padding.bottom, 0)),
|
|
55
|
+
keys.left : @(MAX(insets.left - padding.left, 0)),
|
|
56
|
+
};
|
|
57
|
+
BOOL paddingChanged;
|
|
58
|
+
BOOL insetsChanged;
|
|
59
|
+
@synchronized(ANNEnvironmentById) {
|
|
60
|
+
ANNScreenEnvironmentRecord *record = [self recordOf:screenId];
|
|
61
|
+
paddingChanged = ![record.padding isEqualToValue:paddingValue];
|
|
62
|
+
insetsChanged = ![record.insets isEqualToDictionary:value];
|
|
63
|
+
record.padding = paddingValue;
|
|
64
|
+
record.insets = value;
|
|
65
|
+
}
|
|
66
|
+
// The listeners read the padding back, so it is kept before they are told. A copy: a listener may stop or start
|
|
67
|
+
// listening while it is told.
|
|
68
|
+
if (paddingChanged) {
|
|
69
|
+
NSHashTable<id<ANNScreenPaddingListener>> *listeners = ANNPaddingListenersById[screenId];
|
|
70
|
+
for (id<ANNScreenPaddingListener> listener in listeners.allObjects) {
|
|
71
|
+
[listener screenPaddingDidChange];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (insetsChanged) {
|
|
75
|
+
[eventEmitter sendScreenInsetsChanged:screenId insets:value];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
+ (UIEdgeInsets)paddingForScreenId:(NSString *)screenId {
|
|
80
|
+
@synchronized(ANNEnvironmentById) {
|
|
81
|
+
return ANNEnvironmentById[screenId].padding.UIEdgeInsetsValue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
+ (NSDictionary<NSString *, NSNumber *> *)insetsForScreenId:(NSString *)screenId {
|
|
86
|
+
@synchronized(ANNEnvironmentById) {
|
|
87
|
+
return ANNEnvironmentById[screenId].insets;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#pragma mark - Regions
|
|
92
|
+
|
|
93
|
+
+ (void)setRegions:(NSDictionary<NSString *, NSArray *> *)regions
|
|
94
|
+
forScreenId:(NSString *)screenId
|
|
95
|
+
eventEmitter:(ANNEventEmitter *)eventEmitter {
|
|
96
|
+
const auto &keys = ANNEventContract.ScreenRegionsChanged;
|
|
97
|
+
BOOL empty = [regions[keys.division] count] == 0 && [regions[keys.occlusion] count] == 0;
|
|
98
|
+
@synchronized(ANNEnvironmentById) {
|
|
99
|
+
NSDictionary<NSString *, NSArray *> *before = ANNEnvironmentById[screenId].regions;
|
|
100
|
+
if ((!before && empty) || [before isEqualToDictionary:regions]) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
[self recordOf:screenId].regions = regions;
|
|
104
|
+
}
|
|
105
|
+
[eventEmitter sendScreenRegionsChanged:screenId regions:regions];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
+ (NSDictionary<NSString *, NSArray *> *)regionsForScreenId:(NSString *)screenId {
|
|
109
|
+
@synchronized(ANNEnvironmentById) {
|
|
110
|
+
return ANNEnvironmentById[screenId].regions;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
#pragma mark - Arrangement
|
|
115
|
+
|
|
116
|
+
+ (void)setArrangement:(NSDictionary<NSString *, id> *)arrangement
|
|
117
|
+
forScreenId:(NSString *)screenId
|
|
118
|
+
eventEmitter:(ANNEventEmitter *)eventEmitter {
|
|
119
|
+
@synchronized(ANNEnvironmentById) {
|
|
120
|
+
ANNScreenEnvironmentRecord *record = [self recordOf:screenId];
|
|
121
|
+
if ([record.arrangement isEqualToDictionary:arrangement]) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
record.arrangement = arrangement;
|
|
125
|
+
}
|
|
126
|
+
[eventEmitter sendArrangementChanged:screenId state:arrangement];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
+ (NSDictionary<NSString *, id> *)arrangementForScreenId:(NSString *)screenId {
|
|
130
|
+
@synchronized(ANNEnvironmentById) {
|
|
131
|
+
return ANNEnvironmentById[screenId].arrangement;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#pragma mark - Padding listeners
|
|
136
|
+
|
|
137
|
+
+ (void)addPaddingListener:(id<ANNScreenPaddingListener>)listener
|
|
138
|
+
forScreenId:(NSString *)screenId {
|
|
139
|
+
NSHashTable<id<ANNScreenPaddingListener>> *listeners = ANNPaddingListenersById[screenId];
|
|
140
|
+
if (!listeners) {
|
|
141
|
+
listeners = [NSHashTable weakObjectsHashTable];
|
|
142
|
+
ANNPaddingListenersById[screenId] = listeners;
|
|
143
|
+
}
|
|
144
|
+
[listeners addObject:listener];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
+ (void)removePaddingListener:(id<ANNScreenPaddingListener>)listener
|
|
148
|
+
forScreenId:(NSString *)screenId {
|
|
149
|
+
NSHashTable<id<ANNScreenPaddingListener>> *listeners = ANNPaddingListenersById[screenId];
|
|
150
|
+
[listeners removeObject:listener];
|
|
151
|
+
[self forgetListenersOfScreenIdIfNone:screenId];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// A view that went (it doesn't remove itself in its `dealloc`) leaves no entry in the weak table: `allObjects` counts
|
|
155
|
+
// only the live ones. The table of a screen nobody listens to goes with the last one, or with the screen's record.
|
|
156
|
+
+ (void)forgetListenersOfScreenIdIfNone:(NSString *)screenId {
|
|
157
|
+
NSHashTable<id<ANNScreenPaddingListener>> *listeners = ANNPaddingListenersById[screenId];
|
|
158
|
+
if (listeners && listeners.allObjects.count == 0) {
|
|
159
|
+
[ANNPaddingListenersById removeObjectForKey:screenId];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
#pragma mark - Removal
|
|
164
|
+
|
|
165
|
+
+ (void)removeScreenId:(NSString *)screenId {
|
|
166
|
+
@synchronized(ANNEnvironmentById) {
|
|
167
|
+
[ANNEnvironmentById removeObjectForKey:screenId];
|
|
168
|
+
}
|
|
169
|
+
[self forgetListenersOfScreenIdIfNone:screenId];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
+ (void)removeAll {
|
|
173
|
+
@synchronized(ANNEnvironmentById) {
|
|
174
|
+
[ANNEnvironmentById removeAllObjects];
|
|
175
|
+
}
|
|
176
|
+
for (NSString *screenId in ANNPaddingListenersById.allKeys) {
|
|
177
|
+
[self forgetListenersOfScreenIdIfNone:screenId];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
@end
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
#import "ANNEventEmitter.h"
|
|
2
1
|
#import <UIKit/UIKit.h>
|
|
3
2
|
|
|
4
3
|
NS_ASSUME_NONNULL_BEGIN
|
|
5
4
|
|
|
6
|
-
/// The reserved regions of
|
|
7
|
-
///
|
|
8
|
-
/// `{ x, y, width, height }`.
|
|
9
|
-
/// for a screen's first render, and gets every change as `ANN.ScreenRegionsChanged`.
|
|
5
|
+
/// The reserved regions of a screen (`useReservedRegions`), iOS 27.1: `division`, where the screen divides (the fold of
|
|
6
|
+
/// a partly folded device), and `occlusion`, where hardware covers it (a camera); each a list of
|
|
7
|
+
/// `{ x, y, width, height }`. Measured here; kept for JavaScript by `ANNScreenEnvironment`.
|
|
10
8
|
@interface ANNScreenRegions : NSObject
|
|
11
9
|
|
|
12
10
|
/// The active regions UIKit reserves in `view`, without the margins it adds around them for interactive content, in
|
|
@@ -15,19 +13,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
15
13
|
+ (nullable NSDictionary<NSString *, NSArray *> *)regionsOfView:(UIView *)view
|
|
16
14
|
inCoordinatesOf:(UIView *)coordinateView;
|
|
17
15
|
|
|
18
|
-
/// Keeps the screen's regions and tells when they changed. Main queue.
|
|
19
|
-
+ (void)setRegions:(NSDictionary<NSString *, NSArray *> *)regions
|
|
20
|
-
forScreenId:(NSString *)screenId
|
|
21
|
-
eventEmitter:(ANNEventEmitter *)eventEmitter;
|
|
22
|
-
|
|
23
|
-
/// `{ division, occlusion }`, or nil before the screen was laid out. Any thread.
|
|
24
|
-
+ (nullable NSDictionary<NSString *, NSArray *> *)regionsForScreenId:(NSString *)screenId;
|
|
25
|
-
|
|
26
|
-
+ (void)removeScreenId:(NSString *)screenId;
|
|
27
|
-
|
|
28
|
-
/// Forgets every screen: after a reload the new JavaScript counts its ids anew. Main queue.
|
|
29
|
-
+ (void)removeAll;
|
|
30
|
-
|
|
31
16
|
@end
|
|
32
17
|
|
|
33
18
|
NS_ASSUME_NONNULL_END
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
#import "ANNScreenRegions.h"
|
|
2
2
|
#import "ANNEventContract.h"
|
|
3
3
|
|
|
4
|
-
static NSMutableDictionary<NSString *, NSDictionary<NSString *, NSArray *> *> *ANNScreenRegionsById;
|
|
5
|
-
|
|
6
4
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 270100
|
|
7
5
|
// The part of a region inside the screen, CGRectNull for a region outside it (the fold beside a screen of a pair, the
|
|
8
6
|
// camera above a screen under the bar). A fold is 0 wide or 0 high: it is inside where its line crosses the screen,
|
|
@@ -51,12 +49,6 @@ ANNRegionRects(NSArray<UIViewReservedRegion *> *regions, UIView *view, UIView *c
|
|
|
51
49
|
|
|
52
50
|
@implementation ANNScreenRegions
|
|
53
51
|
|
|
54
|
-
+ (void)initialize {
|
|
55
|
-
if (self == ANNScreenRegions.class) {
|
|
56
|
-
ANNScreenRegionsById = [NSMutableDictionary new];
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
52
|
+ (NSDictionary<NSString *, NSArray *> *)regionsOfView:(UIView *)view
|
|
61
53
|
inCoordinatesOf:(UIView *)coordinateView {
|
|
62
54
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 270100
|
|
@@ -75,34 +67,4 @@ ANNRegionRects(NSArray<UIViewReservedRegion *> *regions, UIView *view, UIView *c
|
|
|
75
67
|
return nil;
|
|
76
68
|
}
|
|
77
69
|
|
|
78
|
-
+ (void)setRegions:(NSDictionary<NSString *, NSArray *> *)regions
|
|
79
|
-
forScreenId:(NSString *)screenId
|
|
80
|
-
eventEmitter:(ANNEventEmitter *)eventEmitter {
|
|
81
|
-
@synchronized(ANNScreenRegionsById) {
|
|
82
|
-
if ([ANNScreenRegionsById[screenId] isEqualToDictionary:regions]) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
ANNScreenRegionsById[screenId] = regions;
|
|
86
|
-
}
|
|
87
|
-
[eventEmitter sendScreenRegionsChanged:screenId regions:regions];
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
+ (NSDictionary<NSString *, NSArray *> *)regionsForScreenId:(NSString *)screenId {
|
|
91
|
-
@synchronized(ANNScreenRegionsById) {
|
|
92
|
-
return ANNScreenRegionsById[screenId];
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
+ (void)removeScreenId:(NSString *)screenId {
|
|
97
|
-
@synchronized(ANNScreenRegionsById) {
|
|
98
|
-
[ANNScreenRegionsById removeObjectForKey:screenId];
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
+ (void)removeAll {
|
|
103
|
-
@synchronized(ANNScreenRegionsById) {
|
|
104
|
-
[ANNScreenRegionsById removeAllObjects];
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
70
|
@end
|
|
@@ -7,10 +7,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
7
7
|
typedef struct {
|
|
8
8
|
/// The screen is in a stack.
|
|
9
9
|
BOOL inStack;
|
|
10
|
-
/// The screen's stack shows its toolbar.
|
|
11
|
-
BOOL stackShowsToolbar;
|
|
12
|
-
/// The bottom of the window's safe area: the home indicator.
|
|
13
|
-
CGFloat windowBottomSafeArea;
|
|
14
10
|
/// The physical side of the iPhone Duo vertical bar (iOS 27.1): `UIRectEdgeLeft`, `UIRectEdgeRight`, or
|
|
15
11
|
/// `UIRectEdgeNone` without one.
|
|
16
12
|
UIRectEdge verticalBarSide;
|
|
@@ -27,11 +23,10 @@ FOUNDATION_EXPORT UIEdgeInsets ANNScreenInsetsOverRoot(CGRect rootFrame, CGSize
|
|
|
27
23
|
UIEdgeInsets safeArea);
|
|
28
24
|
|
|
29
25
|
/// The padding the screen's safe area view keeps (`layout.safeAreaEdges`): the insets on the padded edges, 0 on the
|
|
30
|
-
/// others. With `layout.safeAreaEdges` exactly those edges
|
|
31
|
-
/// without it every edge but: the top under a shown top bar (in a stack, under the top
|
|
32
|
-
/// `false`) or with a large title that can show; the bottom
|
|
33
|
-
///
|
|
34
|
-
/// unless `layout.drawBehindVerticalBar` or `layout.verticalBars` is `false`.
|
|
26
|
+
/// others. With `layout.safeAreaEdges` exactly those edges, but the top under a large title that can show (in a stack,
|
|
27
|
+
/// `topBar.visible` not `false`); without it every edge but: the top under a shown top bar (in a stack, under the top
|
|
28
|
+
/// bar, `topBar.visible` not `false`) or with a large title that can show; the bottom, always; the side of the
|
|
29
|
+
/// vertical bar unless `layout.drawBehindVerticalBar` or `layout.verticalBars` is `false`.
|
|
35
30
|
FOUNDATION_EXPORT UIEdgeInsets ANNScreenPadding(UIEdgeInsets insets, ANNNavigationOptions *options,
|
|
36
31
|
ANNScreenPaddingContext context);
|
|
37
32
|
|