@apexnative/navigation 1.0.0-alpha.3 → 1.0.0-alpha.5
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 +22 -0
- package/android/CLAUDE.md +26 -9
- package/android/CORE.md +32 -17
- package/android/RECIPES.md +9 -3
- package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +25 -9
- package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
- package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
- package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
- package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
- package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
- package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
- package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +33 -22
- package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +5 -4
- package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
- package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +39 -20
- package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -4
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +6 -6
- package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +10 -5
- package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +47 -46
- package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +34 -7
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
- package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +6 -4
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +12 -12
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +4 -3
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
- package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
- package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +3 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +25 -17
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +6 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +5 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +45 -14
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +25 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +8 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +8 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +61 -15
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +28 -18
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +25 -12
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +2 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +85 -29
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +2 -2
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +7 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +5 -8
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +14 -11
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +56 -21
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +4 -2
- package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
- package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
- package/cli/doctor/checks/app.js +61 -13
- package/cli/doctor/checks/splash.js +4 -22
- package/cli/migrate/native.js +18 -0
- package/cli/setup/source.js +2 -1
- package/cli/setup/steps/mainApplication.js +134 -19
- package/cli/splash/index.js +3 -1
- package/docs-md/architecture/transitions.md +6 -7
- package/docs-md/containers/modals.md +2 -2
- package/docs-md/guides/cli.md +1 -2
- package/docs-md/help/glossary.md +1 -1
- package/docs-md/help/troubleshooting.md +22 -5
- package/docs-md/index.json +4 -0
- package/docs-md/migration/from-react-native-navigation.md +8 -2
- package/docs-md/screen-ui/back-and-gestures.md +24 -2
- package/docs-md/start/installation.md +4 -2
- package/ios/CLAUDE.md +17 -5
- package/ios/CORE.md +18 -13
- package/ios/Contract/ANNCommandAnswer.h +9 -2
- package/ios/Contract/ANNCommandAnswer.mm +28 -30
- package/ios/Contract/ANNCommandContract.h +15 -0
- package/ios/Contract/ANNCommandContract.mm +78 -0
- package/ios/Core/ANNAppearanceDispatcher.h +5 -4
- package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
- package/ios/Core/ANNErrorHandler.h +1 -1
- package/ios/Core/ANNErrorHandler.mm +3 -1
- package/ios/Core/ANNEventEmitter.h +1 -1
- package/ios/Core/ANNEventEmitter.mm +2 -2
- package/ios/Core/ANNJavaScriptCalls.h +34 -0
- package/ios/Core/ANNJavaScriptCalls.mm +61 -0
- package/ios/Core/ANNNavigationState.h +7 -5
- package/ios/Core/ANNNavigationState.mm +8 -7
- package/ios/Core/ANNNodeHelper.h +32 -12
- package/ios/Core/ANNNodeHelper.mm +100 -3
- package/ios/Core/ANNRenderWait.h +15 -1
- package/ios/Core/ANNRenderWait.mm +119 -17
- package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
- package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
- package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
- package/ios/Layouts/Modal/ANNModalCoordinator.mm +55 -14
- package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
- package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
- package/ios/Layouts/Screen/ANNComponentViewController.h +8 -0
- package/ios/Layouts/Screen/ANNComponentViewController.mm +32 -5
- package/ios/Layouts/Screen/ANNScreenPlace.h +41 -0
- package/ios/Layouts/Screen/ANNScreenPlace.mm +175 -0
- package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
- package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
- package/ios/Layouts/SplitView/ANNSplitViewController.mm +4 -2
- package/ios/Layouts/Stack/ANNPreviewPush.h +5 -5
- package/ios/Layouts/Stack/ANNPreviewPush.mm +85 -22
- package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
- package/ios/Layouts/Stack/ANNStackController.mm +26 -3
- package/ios/Layouts/Stack/ANNStackQueue.h +3 -1
- package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
- package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
- package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
- package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
- package/ios/Layouts/Tabs/ANNBottomTabsController.mm +13 -5
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +2 -2
- package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +109 -7
- package/ios/Options/ANNOptionsCache.h +7 -6
- package/ios/Options/ANNSearchBarOptions.h +4 -3
- package/ios/Options/ANNUserChoice.h +57 -0
- package/ios/Options/ANNUserChoice.mm +44 -0
- package/ios/Options/Params/ANNImageSource.h +61 -0
- package/ios/Options/Params/ANNImageSource.mm +101 -0
- package/ios/Options/Params/ANNOptionImages.h +37 -0
- package/ios/Options/Params/ANNOptionImages.mm +284 -0
- package/ios/Options/Params/Image.h +11 -2
- package/ios/Options/Params/Image.mm +15 -2
- package/ios/Options/Params/ImageParser.h +5 -5
- package/ios/Options/Params/ImageParser.mm +28 -46
- package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
- package/ios/RECIPES.md +11 -5
- package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
- package/ios/React/Slots/ANNSlotContainers.h +14 -6
- package/ios/React/Slots/ANNSlotContainers.mm +75 -2
- package/ios/TopBar/ANNBarButtons.h +9 -5
- package/ios/TopBar/ANNBarButtons.mm +211 -63
- package/ios/TopBar/ANNIconButtonImage.h +1 -0
- package/ios/TopBar/ANNIconButtonImage.mm +34 -1
- package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
- package/ios/TopBar/ANNLargeTitlePresenter.mm +26 -3
- package/ios/TopBar/ANNSearchPresenter.mm +170 -19
- package/ios/TopBar/ANNTopBarPresenter.h +5 -0
- package/ios/TopBar/ANNTopBarPresenter.mm +60 -11
- package/ios/TurboModules/ANNTurboModule.mm +39 -21
- package/lib/module/ARCHITECTURE.md +18 -18
- package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
- package/lib/module/api/commands/commands.js +54 -6
- package/lib/module/api/commands/commands.js.map +1 -1
- package/lib/module/api/navigation.js.map +1 -1
- package/lib/module/engine/commands.js +9 -7
- package/lib/module/engine/commands.js.map +1 -1
- package/lib/module/engine/layout.js +13 -9
- package/lib/module/engine/layout.js.map +1 -1
- package/lib/module/engine/options.js +44 -11
- package/lib/module/engine/options.js.map +1 -1
- package/lib/module/engine/places.js +52 -7
- package/lib/module/engine/places.js.map +1 -1
- package/lib/module/engine/props.js +30 -1
- package/lib/module/engine/props.js.map +1 -1
- package/lib/module/engine/rememberedOptions.js +1 -1
- package/lib/module/engine/rememberedOptions.js.map +1 -1
- package/lib/module/engine/screens.js +22 -12
- package/lib/module/engine/screens.js.map +1 -1
- package/lib/module/interfaces/contract/commands.json +101 -0
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts +5 -2
- package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
- package/lib/typescript/api/commands/commands.d.ts.map +1 -1
- package/lib/typescript/api/commands/presentation.d.ts +4 -3
- package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts +1 -1
- package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
- package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
- package/lib/typescript/api/navigation.d.ts +4 -1
- package/lib/typescript/api/navigation.d.ts.map +1 -1
- package/lib/typescript/engine/commands.d.ts.map +1 -1
- package/lib/typescript/engine/options.d.ts +5 -2
- package/lib/typescript/engine/options.d.ts.map +1 -1
- package/lib/typescript/engine/places.d.ts +7 -2
- package/lib/typescript/engine/places.d.ts.map +1 -1
- package/lib/typescript/engine/props.d.ts +8 -1
- package/lib/typescript/engine/props.d.ts.map +1 -1
- package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
- package/lib/typescript/engine/screens.d.ts.map +1 -1
- package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
- package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
- package/lib/typescript/interfaces/Events.d.ts +19 -10
- package/lib/typescript/interfaces/Events.d.ts.map +1 -1
- package/lib/typescript/interfaces/Options.d.ts +1 -1
- package/lib/typescript/interfaces/Options.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/animations.d.ts +23 -4
- package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/buttons.d.ts +13 -5
- package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/stack.d.ts +9 -0
- package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
- package/lib/typescript/interfaces/options/topBar.d.ts +22 -9
- package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ARCHITECTURE.md +18 -18
- package/src/adapters/NativeANNTurboModule.ts +5 -2
- package/src/api/commands/commands.ts +48 -7
- package/src/api/commands/presentation.ts +4 -3
- package/src/api/events/navigationEvents.ts +1 -1
- package/src/api/hooks/useNavigation.ts +1 -1
- package/src/api/navigation.ts +4 -1
- package/src/engine/commands.ts +19 -7
- package/src/engine/layout.ts +16 -9
- package/src/engine/options.ts +39 -11
- package/src/engine/places.ts +65 -7
- package/src/engine/props.ts +30 -1
- package/src/engine/rememberedOptions.ts +4 -1
- package/src/engine/screens.tsx +23 -13
- package/src/interfaces/ComponentEvents.ts +2 -2
- package/src/interfaces/Events.ts +19 -10
- package/src/interfaces/Options.ts +1 -0
- package/src/interfaces/contract/commands.json +101 -0
- package/src/interfaces/options/animations.ts +24 -4
- package/src/interfaces/options/buttons.ts +13 -5
- package/src/interfaces/options/stack.ts +9 -0
- package/src/interfaces/options/topBar.ts +22 -9
- package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
- package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
|
@@ -15,14 +15,19 @@
|
|
|
15
15
|
#import "ANNRenderWait.h"
|
|
16
16
|
#import "ANNShownScreens.h"
|
|
17
17
|
#import "ANNStackCommands.h"
|
|
18
|
+
#import "ANNStackController.h"
|
|
18
19
|
#import "ANNStackQueue.h"
|
|
19
20
|
#import "ApexNavigation+Internal.h"
|
|
20
21
|
#import "UIViewController+LayoutProtocol.h"
|
|
21
22
|
#import <React/RCTLog.h>
|
|
22
23
|
|
|
23
|
-
// The limits of the bar components of a push: title and background 1 s, buttons 0.5 s.
|
|
24
|
+
// The limits of the bar components of a push: title and background 1 s, buttons 0.5 s. With `waitForRender` unset they
|
|
25
|
+
// count from the wait's start, as a stack's push; with `true`, from the content's end.
|
|
24
26
|
static const ANNBarWaitLimits ANNColumnBarLimits = {1, 0.5};
|
|
25
27
|
|
|
28
|
+
// How long the push's wait waits for the screen's first content when `waitForRender` is not set, as a stack's push.
|
|
29
|
+
static const NSTimeInterval ANNColumnRenderLimit = 0.5;
|
|
30
|
+
|
|
26
31
|
// The split view of `node`: the node itself or the nearest of its layout parents that has columns.
|
|
27
32
|
static UIViewController *ANNSplitViewOf(UIViewController *node) {
|
|
28
33
|
for (UIViewController *parent = node; parent; parent = parent.layoutParent) {
|
|
@@ -45,17 +50,26 @@ static BOOL ANNIsOnScreen(UIViewController *node) {
|
|
|
45
50
|
|
|
46
51
|
@class ANNColumnRequest;
|
|
47
52
|
|
|
53
|
+
// A request the newest of its column superseded: its answer and the id it resolves with, its own screen's (each
|
|
54
|
+
// `showInColumn` answers its own screen, as on Android).
|
|
55
|
+
@interface ANNSupersededRequest : NSObject
|
|
56
|
+
@property(nonatomic, strong) ANNCommandAnswer *answer;
|
|
57
|
+
@property(nonatomic, copy) NSString *value;
|
|
58
|
+
@end
|
|
59
|
+
|
|
60
|
+
@implementation ANNSupersededRequest
|
|
61
|
+
@end
|
|
62
|
+
|
|
48
63
|
// "The last request of a column" (`showInColumn` step 2): one per split view and column. The newest request decides
|
|
49
|
-
//
|
|
64
|
+
// when the requests it superseded answer; each of them resolves with its own screen's id whatever the newest one's
|
|
65
|
+
// outcome, as on Android.
|
|
50
66
|
@interface ANNColumnRecord : NSObject
|
|
51
67
|
@property(nonatomic, weak, nullable) UIViewController *splitView;
|
|
52
68
|
@property(nonatomic, copy) NSString *column;
|
|
53
69
|
// Weakly: what runs the newest request holds it (the waiting requests, the split view's call, the push).
|
|
54
70
|
@property(nonatomic, weak, nullable) ANNColumnRequest *newest;
|
|
55
|
-
@property(nonatomic, strong) NSMutableArray<
|
|
71
|
+
@property(nonatomic, strong) NSMutableArray<ANNSupersededRequest *> *superseded;
|
|
56
72
|
@property(nonatomic) BOOL ended;
|
|
57
|
-
@property(nonatomic, copy, nullable) NSString *value;
|
|
58
|
-
@property(nonatomic, copy, nullable) NSString *rejection;
|
|
59
73
|
@end
|
|
60
74
|
|
|
61
75
|
@implementation ANNColumnRecord
|
|
@@ -184,10 +198,11 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
|
|
|
184
198
|
return record;
|
|
185
199
|
}
|
|
186
200
|
|
|
187
|
-
// Step 1, the push's wait: `waitForRender` unset waits for the
|
|
188
|
-
// it takes (with the rule for content nobody knows of), then the bar components; `false` for nothing; nothing either
|
|
189
|
-
// while the source's place isn't seen.
|
|
190
|
-
//
|
|
201
|
+
// Step 1, the push's wait, as a stack's push: `waitForRender` unset waits for the content at most 0.5 s, `true` as long
|
|
202
|
+
// as it takes (with the rule for content nobody knows of), then the bar components; `false` for nothing; nothing either
|
|
203
|
+
// while the source's place isn't seen. The content's end waits for the calls JavaScript made by then, so that the
|
|
204
|
+
// options of the screen's first commit are applied before it shows. Read from the screen's own options over the
|
|
205
|
+
// defaults: it has no place yet. The screen waits unseen in the source's window, as a layer that waits to show.
|
|
191
206
|
+ (void)startWaitOf:(ANNColumnRequest *)request {
|
|
192
207
|
UIViewController *screen = request.screen;
|
|
193
208
|
Bool *waitForRender = [screen resolveOptionsWithDefault].animations.push.waitForRender;
|
|
@@ -198,20 +213,22 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
|
|
|
198
213
|
[self readyOnNextTurnOf:request];
|
|
199
214
|
return;
|
|
200
215
|
}
|
|
201
|
-
BOOL
|
|
216
|
+
BOOL bounded = !waitForRender.hasValue;
|
|
202
217
|
__weak UIViewController *weakScreen = screen;
|
|
203
218
|
NSArray<UIViewController *> * (^screens)(void) = ^NSArray<UIViewController *> * {
|
|
204
219
|
UIViewController *waited = weakScreen;
|
|
205
220
|
return waited ? waited.waitedComponentViewControllers : @[];
|
|
206
221
|
};
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
wait.unknownContentRule =
|
|
222
|
+
ANNRenderWait *wait =
|
|
223
|
+
[[ANNRenderWait alloc] initWithContent:ANNRenderWaitContentNode
|
|
224
|
+
node:screen
|
|
225
|
+
screens:screens
|
|
226
|
+
limit:bounded ? ANNColumnRenderLimit : 0
|
|
227
|
+
bar:ANNRenderWaitBarAfterContent
|
|
228
|
+
barLimits:ANNColumnBarLimits];
|
|
229
|
+
wait.unknownContentRule = !bounded;
|
|
230
|
+
wait.settlesThroughJavaScript = YES;
|
|
231
|
+
wait.barLimitsFromStart = bounded;
|
|
215
232
|
__weak ANNColumnRequest *weakRequest = request;
|
|
216
233
|
wait.canEnd = ^BOOL {
|
|
217
234
|
ANNColumnRequest *waiting = weakRequest;
|
|
@@ -225,7 +242,7 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
|
|
|
225
242
|
if (!ready) {
|
|
226
243
|
return;
|
|
227
244
|
}
|
|
228
|
-
//
|
|
245
|
+
// A screen that didn't render while parked makes its content right before it shows (as a push does).
|
|
229
246
|
[ANNSplitViewCommands render:ready];
|
|
230
247
|
if (ready.starting) {
|
|
231
248
|
[ANNSplitViewCommands readyOnNextTurnOf:ready];
|
|
@@ -233,14 +250,12 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
|
|
|
233
250
|
[ANNSplitViewCommands readyOf:ready];
|
|
234
251
|
}
|
|
235
252
|
};
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
};
|
|
243
|
-
}
|
|
253
|
+
wait.setUp = ^{
|
|
254
|
+
ANNColumnRequest *waiting = weakRequest;
|
|
255
|
+
if (waiting) {
|
|
256
|
+
[ANNSplitViewCommands park:waiting];
|
|
257
|
+
}
|
|
258
|
+
};
|
|
244
259
|
request.wait = wait;
|
|
245
260
|
request.starting = YES;
|
|
246
261
|
@try {
|
|
@@ -281,6 +296,13 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
|
|
|
281
296
|
[screen setWaitForRender:YES];
|
|
282
297
|
}
|
|
283
298
|
if (window) {
|
|
299
|
+
__weak ANNColumnRequest *placed = request;
|
|
300
|
+
ANNScreenPlace * (^place)(void) = ^ANNScreenPlace * {
|
|
301
|
+
return [ANNSplitViewCommands placeOf:placed];
|
|
302
|
+
};
|
|
303
|
+
for (ANNComponentViewController *each in ANNStackScreensOfEntry(screen)) {
|
|
304
|
+
each.placeWhileParked = place;
|
|
305
|
+
}
|
|
284
306
|
request.parking = [ANNParking new];
|
|
285
307
|
[request.parking park:screen inView:window];
|
|
286
308
|
}
|
|
@@ -304,6 +326,34 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
|
|
|
304
326
|
}
|
|
305
327
|
}
|
|
306
328
|
|
|
329
|
+
// Where the parked screen will show, as far as it is known now: the column's stack (whose screens it replaces), the
|
|
330
|
+
// navigation controller UIKit keeps a column that is a screen alone in, or the source's stack while the split view
|
|
331
|
+
// shows as one stack. Nil without one: the screen lays out with its view's own safe area.
|
|
332
|
+
+ (nullable ANNScreenPlace *)placeOf:(ANNColumnRequest *)request {
|
|
333
|
+
UIViewController *screen = request.screen;
|
|
334
|
+
UIViewController *source = request.source;
|
|
335
|
+
if (!screen || !source) {
|
|
336
|
+
return nil;
|
|
337
|
+
}
|
|
338
|
+
UIViewController *splitView = ANNSplitViewOf(source);
|
|
339
|
+
UINavigationController *stack = nil;
|
|
340
|
+
if (splitView && !ANNIsCollapsedIntoCompact(splitView)) {
|
|
341
|
+
UIViewController *columnNode =
|
|
342
|
+
[(id<ANNLayoutProtocol>)splitView viewControllerOfColumn:request.column];
|
|
343
|
+
stack = [columnNode isKindOfClass:UINavigationController.class]
|
|
344
|
+
? (UINavigationController *)columnNode
|
|
345
|
+
: columnNode.navigationController;
|
|
346
|
+
} else {
|
|
347
|
+
stack = [ANNStackCommands stackOf:source].shownNavigationController;
|
|
348
|
+
}
|
|
349
|
+
if (!stack) {
|
|
350
|
+
return nil;
|
|
351
|
+
}
|
|
352
|
+
return [ANNScreenPlace placeOfEntry:screen
|
|
353
|
+
inStack:stack
|
|
354
|
+
options:[ANNStackOptionsScreen(screen) resolveOptionsWithDefault]];
|
|
355
|
+
}
|
|
356
|
+
|
|
307
357
|
// The screen leaves its place and the waiting requests; UIKit ends its departure from the window here (it shows in
|
|
308
358
|
// this turn, or goes).
|
|
309
359
|
+ (void)leaveWaitingPlace:(ANNColumnRequest *)request {
|
|
@@ -353,18 +403,23 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
|
|
|
353
403
|
[self request:request endedWithValue:nil rejection:text];
|
|
354
404
|
}
|
|
355
405
|
|
|
356
|
-
// Superseded at its readiness: its screen goes without having shown (no events)
|
|
357
|
-
//
|
|
406
|
+
// Superseded at its readiness: its screen goes without having shown (no events). It answers when the newest request
|
|
407
|
+
// does, at once when that answered, with its own screen's id: the newest one's rejection (a container for a stack
|
|
408
|
+
// column, a split view that went) is about that request only.
|
|
358
409
|
+ (void)supersede:(ANNColumnRequest *)request {
|
|
359
410
|
[self leaveWaitingPlace:request];
|
|
360
411
|
request.done = YES;
|
|
412
|
+
NSString *value = ANNStackAnswerIdOf(request.screen, ANNStackAnswerCommandShowInColumn);
|
|
361
413
|
[request.screen destroy];
|
|
362
414
|
ANNColumnRecord *record = request.record;
|
|
363
415
|
if (record.ended) {
|
|
364
|
-
[
|
|
416
|
+
[request.answer resolve:value];
|
|
365
417
|
return;
|
|
366
418
|
}
|
|
367
|
-
|
|
419
|
+
ANNSupersededRequest *superseded = [ANNSupersededRequest new];
|
|
420
|
+
superseded.answer = request.answer;
|
|
421
|
+
superseded.value = value;
|
|
422
|
+
[record.superseded addObject:superseded];
|
|
368
423
|
}
|
|
369
424
|
|
|
370
425
|
// (a) The split view shows the screen in the column: a stack column's screens are replaced without an animation and
|
|
@@ -373,14 +428,26 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
|
|
|
373
428
|
// `DidDisappear` of the screens that left, `DidAppear` of the new one, the state, then the answer.
|
|
374
429
|
+ (void)show:(ANNColumnRequest *)request inSplitView:(UIViewController *)splitView {
|
|
375
430
|
UIViewController *screen = request.screen;
|
|
431
|
+
UIViewController *columnNode =
|
|
432
|
+
[(id<ANNLayoutProtocol>)splitView viewControllerOfColumn:request.column];
|
|
433
|
+
// A stack column takes what a stack takes, a screen or a pair; any other layout rejects `columnIsStack`, as on
|
|
434
|
+
// Android. A column that is a screen alone takes any layout in its place.
|
|
435
|
+
if ([columnNode isKindOfClass:UINavigationController.class] &&
|
|
436
|
+
[ANNLayoutValidator checkStackChild:request.layout
|
|
437
|
+
stackId:columnNode.layoutInfo.componentId ?: @""]) {
|
|
438
|
+
[self leaveWaitingPlace:request];
|
|
439
|
+
[screen destroy];
|
|
440
|
+
[self request:request
|
|
441
|
+
endedWithValue:nil
|
|
442
|
+
rejection:[ANNErrorTexts columnIsStack:request.componentId column:request.column]];
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
376
445
|
// Before the parking lets go of it, so that UIKit's calls stay silent until the end.
|
|
377
446
|
[ANNAppearanceDispatcher driveAppearanceOf:@[ screen ]];
|
|
378
447
|
request.driven = YES;
|
|
379
448
|
[self leaveWaitingPlace:request];
|
|
380
449
|
// A screen alone in a column has the split view as its parent by the layout (UIKit puts it into a navigation
|
|
381
450
|
// controller of its own); a stack column's stack is its parent.
|
|
382
|
-
UIViewController *columnNode =
|
|
383
|
-
[(id<ANNLayoutProtocol>)splitView viewControllerOfColumn:request.column];
|
|
384
451
|
if (columnNode && ![columnNode isKindOfClass:UINavigationController.class]) {
|
|
385
452
|
[screen setExplicitLayoutParent:splitView];
|
|
386
453
|
}
|
|
@@ -485,7 +552,8 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
|
|
|
485
552
|
|
|
486
553
|
#pragma mark - The answers
|
|
487
554
|
|
|
488
|
-
// The request answers once; when it is the newest of its column, the requests it superseded answer
|
|
555
|
+
// The request answers once; when it is the newest of its column, the requests it superseded answer then, each with its
|
|
556
|
+
// own screen's id.
|
|
489
557
|
+ (void)request:(ANNColumnRequest *)request
|
|
490
558
|
endedWithValue:(NSString *)value
|
|
491
559
|
rejection:(NSString *)rejection {
|
|
@@ -499,13 +567,11 @@ static NSMapTable<UIViewController *, ANNColumnRecordsOfSplitView *> *ANNColumnR
|
|
|
499
567
|
return;
|
|
500
568
|
}
|
|
501
569
|
record.ended = YES;
|
|
502
|
-
record.value = value;
|
|
503
|
-
record.rejection = rejection;
|
|
504
570
|
record.newest = nil;
|
|
505
|
-
NSArray<
|
|
571
|
+
NSArray<ANNSupersededRequest *> *superseded = [record.superseded copy];
|
|
506
572
|
[record.superseded removeAllObjects];
|
|
507
|
-
for (
|
|
508
|
-
[
|
|
573
|
+
for (ANNSupersededRequest *each in superseded) {
|
|
574
|
+
[each.answer resolve:each.value];
|
|
509
575
|
}
|
|
510
576
|
// A request that begins from now on starts a record of its own.
|
|
511
577
|
UIViewController *splitView = record.splitView;
|
|
@@ -214,19 +214,21 @@ static UISplitViewControllerColumn ANNSplitViewColumn(NSString *name) {
|
|
|
214
214
|
completion:(ANNTransitionCompletionBlock)completion
|
|
215
215
|
rejection:(ANNTransitionRejectionBlock)rejection {
|
|
216
216
|
UIViewController *previous = _columns[column];
|
|
217
|
-
NSString *fromId = fromViewController.layoutInfo.componentId;
|
|
217
|
+
NSString *fromId = fromViewController.layoutInfo.componentId ?: @"";
|
|
218
218
|
if (!previous) {
|
|
219
219
|
rejection([ANNErrorTexts noSuchColumn:fromId column:column], nil);
|
|
220
220
|
return;
|
|
221
221
|
}
|
|
222
222
|
if ([previous isKindOfClass:UINavigationController.class]) {
|
|
223
|
-
// UIKit does not take a navigation controller among the screens of another.
|
|
223
|
+
// UIKit does not take a navigation controller among the screens of another. The core rejects every layout a
|
|
224
|
+
// stack doesn't take before it asks; this guards the module's own call.
|
|
224
225
|
if ([screen isKindOfClass:UINavigationController.class]) {
|
|
225
226
|
rejection([ANNErrorTexts columnIsStack:fromId column:column], nil);
|
|
226
227
|
return;
|
|
227
228
|
}
|
|
228
229
|
// In place, as a column of UIKit apps changes; UIKit animates a column it brings on top.
|
|
229
230
|
[(UINavigationController *)previous setStackChildren:@[ screen ]
|
|
231
|
+
inColumn:column
|
|
230
232
|
fromViewController:fromViewController
|
|
231
233
|
animated:NO
|
|
232
234
|
completion:^{
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
NS_ASSUME_NONNULL_BEGIN
|
|
7
7
|
|
|
8
8
|
/// The preview of a push (`usePreview`): a push that waits for a tap on its preview. Its screen is made and renders
|
|
9
|
-
/// unseen, out of the stack, its key kept; the view with `preview.nativeID` is looked for on the source screen at once
|
|
10
|
-
///
|
|
11
|
-
/// it on a long press. A tap that commits pushes the screen without an animation and without a
|
|
12
|
-
/// the entry with its key; a preview that goes without being opened destroys its screen and
|
|
13
|
-
/// queue.
|
|
9
|
+
/// unseen, out of the stack, its key kept; the view with `preview.nativeID` is looked for on the source screen at once,
|
|
10
|
+
/// then at each mount of the source's content (on each frame for a slot screen), for at most 0.5 s; found, the preview module (`ANNPreviewInteraction`)
|
|
11
|
+
/// shows the screen from it on a long press. A tap that commits pushes the screen without an animation and without a
|
|
12
|
+
/// wait, or goes back to the entry with its key; a preview that goes without being opened destroys its screen and
|
|
13
|
+
/// rejects the push. Main queue.
|
|
14
14
|
@interface ANNPreviewPush : NSObject
|
|
15
15
|
|
|
16
16
|
- (instancetype)init NS_UNAVAILABLE;
|
|
@@ -6,14 +6,16 @@
|
|
|
6
6
|
#import "ANNPopoverPresenter.h"
|
|
7
7
|
#import "ANNPreviewInteraction.h"
|
|
8
8
|
#import "ANNReloadCoordinator.h"
|
|
9
|
+
#import "ANNSlotScreenView.h"
|
|
9
10
|
#import "ANNStackCommands.h"
|
|
10
11
|
#import "ANNStackController.h"
|
|
11
12
|
#import "ApexNavigation+Internal.h"
|
|
12
13
|
#import "UIViewController+LayoutProtocol.h"
|
|
13
14
|
|
|
14
|
-
// The view of a component mounts a frame or so after the command that rendered it: it is looked for
|
|
15
|
-
// a
|
|
16
|
-
static const
|
|
15
|
+
// The view of a component mounts a frame or so after the command that rendered it: it is looked for at each mount of
|
|
16
|
+
// the source's content until this limit (30 frames), then the preview goes, as with a `nativeID` no view has.
|
|
17
|
+
static const NSTimeInterval ANNPreviewSearchLimit = 30.0 / 60;
|
|
18
|
+
// Where the source's mounts can't be heard, a frame apart.
|
|
17
19
|
static const NSTimeInterval ANNPreviewSearchInterval = 1.0 / 60;
|
|
18
20
|
|
|
19
21
|
// One preview from its push to its end: the tap took it, or it went.
|
|
@@ -28,7 +30,8 @@ static const NSTimeInterval ANNPreviewSearchInterval = 1.0 / 60;
|
|
|
28
30
|
@property(nonatomic, copy) NSString *componentId;
|
|
29
31
|
@property(nonatomic, copy) NSString *what;
|
|
30
32
|
@property(nonatomic) NSUInteger generation;
|
|
31
|
-
|
|
33
|
+
// The content whose mounts the search hears, while it looks.
|
|
34
|
+
@property(nonatomic, weak, nullable) UIView<ANNComponentProtocol> *watched;
|
|
32
35
|
@property(nonatomic) BOOL attached;
|
|
33
36
|
@property(nonatomic) BOOL done;
|
|
34
37
|
// The screen's unseen place in the main window, at its preview size, until UIKit takes its view for the menu.
|
|
@@ -84,7 +87,7 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
84
87
|
[screen destroy];
|
|
85
88
|
@throw;
|
|
86
89
|
}
|
|
87
|
-
[self
|
|
90
|
+
[self startSearch:record];
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
// The screen renders as now: its view waits unseen in the main window, at the size of the preview, so that its content
|
|
@@ -110,41 +113,99 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
110
113
|
|
|
111
114
|
#pragma mark - The search
|
|
112
115
|
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
+
// The view is looked for at once; else again at each mount of the source's content, where it comes with one of them,
|
|
117
|
+
// and a last time at the limit, when the preview goes. Both later steps keep the generation they were made with: after
|
|
118
|
+
// a reload they do nothing.
|
|
119
|
+
+ (void)startSearch:(ANNPreviewRecord *)record {
|
|
120
|
+
if ([self search:record last:NO]) {
|
|
116
121
|
return;
|
|
117
122
|
}
|
|
123
|
+
UIViewController *source = record.source;
|
|
124
|
+
// A source that is a container (a stack) is heard through the screen it shows.
|
|
125
|
+
UIView<ANNComponentProtocol> *content =
|
|
126
|
+
source.reactView ?: source.presentedComponentViewController.reactView;
|
|
127
|
+
__weak ANNPreviewRecord *weakRecord = record;
|
|
128
|
+
NSUInteger generation = record.generation;
|
|
129
|
+
// A slot screen hears only the first mount of its slot, not those deeper in it, and a container may show no React
|
|
130
|
+
// content yet: there the view is looked for on each frame until the limit.
|
|
131
|
+
if (!content || [content isKindOfClass:ANNSlotScreenView.class]) {
|
|
132
|
+
[self searchNextFrame:record];
|
|
133
|
+
} else {
|
|
134
|
+
record.watched = content;
|
|
135
|
+
[content setContentDidMount:^{
|
|
136
|
+
ANNPreviewRecord *searching = weakRecord;
|
|
137
|
+
if (searching && generation == ANNReloadCoordinator.generation) {
|
|
138
|
+
[ANNPreviewPush search:searching last:NO];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
forKey:[self mountKeyOf:record]];
|
|
142
|
+
}
|
|
143
|
+
int64_t delay = (int64_t)(ANNPreviewSearchLimit * NSEC_PER_SEC);
|
|
144
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay), dispatch_get_main_queue(), ^{
|
|
145
|
+
ANNPreviewRecord *searching = weakRecord;
|
|
146
|
+
if (searching && generation == ANNReloadCoordinator.generation) {
|
|
147
|
+
[ANNPreviewPush search:searching last:YES];
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// One more search on the next frame, and so on until the view is found or the preview goes; after a reload, none.
|
|
153
|
+
+ (void)searchNextFrame:(ANNPreviewRecord *)record {
|
|
154
|
+
__weak ANNPreviewRecord *weakRecord = record;
|
|
155
|
+
NSUInteger generation = record.generation;
|
|
156
|
+
int64_t delay = (int64_t)(ANNPreviewSearchInterval * NSEC_PER_SEC);
|
|
157
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay), dispatch_get_main_queue(), ^{
|
|
158
|
+
ANNPreviewRecord *searching = weakRecord;
|
|
159
|
+
if (searching && generation == ANNReloadCoordinator.generation &&
|
|
160
|
+
![ANNPreviewPush search:searching last:NO]) {
|
|
161
|
+
[ANNPreviewPush searchNextFrame:searching];
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// YES when the search is over: the view was found, or the preview went or stopped. Each search asks first whether the
|
|
167
|
+
// preview still lives: a source that went makes it go, a reload stops it silently. The last one, not finding the view,
|
|
168
|
+
// makes the preview go.
|
|
169
|
+
+ (BOOL)search:(ANNPreviewRecord *)record last:(BOOL)last {
|
|
170
|
+
if (record.done || record.attached) {
|
|
171
|
+
return YES;
|
|
172
|
+
}
|
|
118
173
|
if (record.generation != ANNReloadCoordinator.generation) {
|
|
119
|
-
return;
|
|
174
|
+
return YES;
|
|
120
175
|
}
|
|
121
176
|
UIViewController *source = record.source;
|
|
122
177
|
if (!source || source.nodeHelper.destroyed) {
|
|
123
178
|
[self gone:record];
|
|
124
|
-
return;
|
|
179
|
+
return YES;
|
|
125
180
|
}
|
|
126
181
|
// Read only: the view is found by its `nativeID`, and its tag is its current Fabric tag.
|
|
127
182
|
UIView *view = [ANNPopoverPresenter viewWithNativeID:record.nativeID in:source.viewIfLoaded];
|
|
128
183
|
if (view) {
|
|
129
184
|
[self attach:record toView:view source:source];
|
|
130
|
-
return;
|
|
185
|
+
return YES;
|
|
131
186
|
}
|
|
132
|
-
if (
|
|
187
|
+
if (last) {
|
|
133
188
|
[self gone:record];
|
|
134
|
-
return;
|
|
189
|
+
return YES;
|
|
135
190
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
191
|
+
return NO;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// The key of the search's mount handler: one per preview, so that two previews of one source don't replace each other.
|
|
195
|
+
+ (NSString *)mountKeyOf:(ANNPreviewRecord *)record {
|
|
196
|
+
return [@"preview." stringByAppendingString:record.previewId];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// The search stops hearing the mounts: only its own handler goes.
|
|
200
|
+
+ (void)stopWatching:(ANNPreviewRecord *)record {
|
|
201
|
+
UIView<ANNComponentProtocol> *content = record.watched;
|
|
202
|
+
record.watched = nil;
|
|
203
|
+
[content setContentDidMount:nil forKey:[self mountKeyOf:record]];
|
|
144
204
|
}
|
|
145
205
|
|
|
146
206
|
+ (void)attach:(ANNPreviewRecord *)record toView:(UIView *)view source:(UIViewController *)source {
|
|
147
207
|
record.attached = YES;
|
|
208
|
+
[self stopWatching:record];
|
|
148
209
|
__weak ANNPreviewRecord *weakRecord = record;
|
|
149
210
|
BOOL (^commit)(void) = ^BOOL {
|
|
150
211
|
return [ANNPreviewPush commit:weakRecord];
|
|
@@ -231,9 +292,10 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
231
292
|
[record.answer reject:[ANNErrorTexts previewGone:record.previewId]];
|
|
232
293
|
}
|
|
233
294
|
|
|
234
|
-
// The record is done: the screen leaves its unseen place, the table forgets it.
|
|
295
|
+
// The record is done: the search stops, the screen leaves its unseen place, the table forgets it.
|
|
235
296
|
+ (void)finish:(ANNPreviewRecord *)record {
|
|
236
297
|
record.done = YES;
|
|
298
|
+
[self stopWatching:record];
|
|
237
299
|
[self unpark:record];
|
|
238
300
|
if (ANNPreviewRecords()[record.previewId] == record) {
|
|
239
301
|
[ANNPreviewRecords() removeObjectForKey:record.previewId];
|
|
@@ -286,6 +348,7 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
|
|
|
286
348
|
NSMutableArray<UIViewController *> *screens = [NSMutableArray new];
|
|
287
349
|
for (ANNPreviewRecord *record in ANNPreviewRecords().allValues) {
|
|
288
350
|
record.done = YES;
|
|
351
|
+
[self stopWatching:record];
|
|
289
352
|
[self unpark:record];
|
|
290
353
|
if (!record.attached) {
|
|
291
354
|
[screens addObject:record.screen];
|
|
@@ -1102,6 +1102,11 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
1102
1102
|
if (change == ANNStackChangePush && animated) {
|
|
1103
1103
|
lowerBarBottom = [self lowerBarBottomOf:navigation leaving:coveredTop];
|
|
1104
1104
|
}
|
|
1105
|
+
// The large title of a screen that comes with its content takes its place for the transition before UIKit's push.
|
|
1106
|
+
if (change == ANNStackChangePush && animated) {
|
|
1107
|
+
UIViewController *arriving = ANNStackOptionsScreen(entries.lastObject);
|
|
1108
|
+
[[ANNTopBarPresenter presenterOfScreen:arriving] arrivesByPushOn:navigation];
|
|
1109
|
+
}
|
|
1105
1110
|
// The revealed screen's large title takes its place for the transition before UIKit lays the screen out for it.
|
|
1106
1111
|
if (change == ANNStackChangePop && animated) {
|
|
1107
1112
|
[self popReveals:entries.lastObject leaving:coveredTop on:navigation];
|
|
@@ -1428,10 +1433,28 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
|
|
|
1428
1433
|
|
|
1429
1434
|
// The screen waits in the window at the stack's size, under UIKit's container view ( `ANNParking`): it isn't a child of
|
|
1430
1435
|
// anything there, gets no touches, is hidden from accessibility, and its appearance is driven, so UIKit's callbacks
|
|
1431
|
-
// report nothing for it.
|
|
1432
|
-
//
|
|
1436
|
+
// report nothing for it. UIKit gives such a view no safe area: its screens lay out with that of their place on top of
|
|
1437
|
+
// the stack meanwhile (`ANNScreenPlace`). Each path that ends the wait gives the view back as it was; UIKit's push of
|
|
1438
|
+
// the entry re-parents it in the same turn, so its departure is not ended here.
|
|
1433
1439
|
- (void)stackPark:(UIViewController *)entry {
|
|
1434
|
-
|
|
1440
|
+
UINavigationController *navigation = self.shownNavigationController;
|
|
1441
|
+
// Its screens lay out as on top of the stack, with the bar and the toolbar the entry shows there.
|
|
1442
|
+
__weak UIViewController *weakEntry = entry;
|
|
1443
|
+
__weak UINavigationController *weakNavigation = navigation;
|
|
1444
|
+
ANNScreenPlace * (^place)(void) = ^ANNScreenPlace * {
|
|
1445
|
+
UIViewController *parked = weakEntry;
|
|
1446
|
+
UINavigationController *stack = weakNavigation;
|
|
1447
|
+
if (!parked || !stack) {
|
|
1448
|
+
return nil;
|
|
1449
|
+
}
|
|
1450
|
+
return [ANNScreenPlace placeOfEntry:parked
|
|
1451
|
+
inStack:stack
|
|
1452
|
+
options:[ANNStackOptionsScreen(parked) resolveOptionsWithDefault]];
|
|
1453
|
+
};
|
|
1454
|
+
for (ANNComponentViewController *screen in ANNStackScreensOfEntry(entry)) {
|
|
1455
|
+
screen.placeWhileParked = place;
|
|
1456
|
+
}
|
|
1457
|
+
[_parking park:entry inView:navigation.view];
|
|
1435
1458
|
}
|
|
1436
1459
|
|
|
1437
1460
|
- (void)stackUnpark:(UIViewController *)entry {
|
|
@@ -166,9 +166,11 @@ typedef NS_ENUM(NSInteger, ANNStackChange) {
|
|
|
166
166
|
completion:(nullable dispatch_block_t)completion
|
|
167
167
|
rejection:(nullable ANNTransitionRejectionBlock)rejection;
|
|
168
168
|
|
|
169
|
-
/// A command that moves nothing (`popTo` of the top) answers `value` in its turn
|
|
169
|
+
/// A command that moves nothing (`popTo` of the top) answers `value` in its turn; a failure meanwhile rejects with the
|
|
170
|
+
/// command's own `what`.
|
|
170
171
|
- (void)noneWithValue:(id)value
|
|
171
172
|
answer:(ANNCommandAnswer *)answer
|
|
173
|
+
what:(NSString *)what
|
|
172
174
|
componentId:(NSString *)componentId
|
|
173
175
|
source:(nullable UIViewController *)source;
|
|
174
176
|
|