@apexnative/navigation 1.0.0-alpha.3 → 1.0.0-alpha.4
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 +9 -0
- package/android/CLAUDE.md +17 -7
- package/android/CORE.md +8 -3
- package/android/RECIPES.md +9 -3
- 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/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/OptionsCache.kt +8 -4
- package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
- package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +2 -24
- package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
- package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +27 -19
- 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/events/AppearanceDispatcher.kt +17 -7
- package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
- 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/bottomtabs/AppliedTabCalls.kt +49 -0
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +16 -6
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +1 -1
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +5 -5
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +4 -3
- package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +6 -3
- 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 +58 -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 +16 -7
- 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/StackSearchPresenter.kt +3 -3
- 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 +10 -2
- 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/stack/fab/Fab.kt +14 -10
- package/cli/doctor/checks/app.js +61 -13
- package/cli/migrate/native.js +18 -0
- package/cli/setup/source.js +2 -1
- package/cli/setup/steps/mainApplication.js +134 -19
- package/docs-md/architecture/transitions.md +6 -7
- package/docs-md/help/glossary.md +1 -1
- package/docs-md/help/troubleshooting.md +20 -3
- 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 +2 -2
- package/docs-md/start/installation.md +3 -1
- package/ios/CLAUDE.md +17 -5
- package/ios/CORE.md +13 -8
- package/ios/Contract/ANNCommandAnswer.mm +5 -20
- package/ios/Contract/ANNCommandContract.h +15 -0
- package/ios/Contract/ANNCommandContract.mm +78 -0
- package/ios/Core/ANNAppearanceDispatcher.mm +1 -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 -3
- package/ios/Core/ANNNavigationState.mm +10 -5
- 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/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/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/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 +44 -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/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 +5 -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/animations.d.ts +5 -2
- 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/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/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 +56 -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/contract/commands.json +101 -0
- package/src/interfaces/options/animations.ts +5 -2
- package/src/interfaces/options/buttons.ts +13 -5
- package/src/interfaces/options/topBar.ts +22 -9
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#import "ANNScreenPlace.h"
|
|
2
|
+
#import "ANNAssert.h"
|
|
3
|
+
#import "ANNBottomTabsController.h"
|
|
4
|
+
#import <objc/runtime.h>
|
|
5
|
+
|
|
6
|
+
static const void *ANNScreenPlaceKey = &ANNScreenPlaceKey;
|
|
7
|
+
|
|
8
|
+
// The measuring navigation controller of each stack: its first item stands for the stack's top, the second for the
|
|
9
|
+
// entry. Weak keys: it goes with its stack.
|
|
10
|
+
static NSMapTable<UINavigationController *, UINavigationController *> *ANNPlaceProbes(void) {
|
|
11
|
+
static NSMapTable<UINavigationController *, UINavigationController *> *probes;
|
|
12
|
+
if (!probes) {
|
|
13
|
+
probes = [NSMapTable weakToStrongObjectsMapTable];
|
|
14
|
+
}
|
|
15
|
+
return probes;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static UINavigationController *ANNPlaceProbeOf(UINavigationController *stack) {
|
|
19
|
+
UINavigationController *probe = [ANNPlaceProbes() objectForKey:stack];
|
|
20
|
+
if (!probe) {
|
|
21
|
+
probe = [[UINavigationController alloc] initWithRootViewController:[UIViewController new]];
|
|
22
|
+
[probe pushViewController:[UIViewController new] animated:NO];
|
|
23
|
+
[ANNPlaceProbes() setObject:probe forKey:stack];
|
|
24
|
+
}
|
|
25
|
+
return probe;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// What UIKit sizes the bar by, from the entry's item. The search field is a field of its own with the same placement:
|
|
29
|
+
// a search controller shows in one item only.
|
|
30
|
+
static void ANNCopyBarItem(UINavigationItem *from, UINavigationItem *to) {
|
|
31
|
+
to.title = from.title;
|
|
32
|
+
to.prompt = from.prompt;
|
|
33
|
+
to.largeTitleDisplayMode = from.largeTitleDisplayMode;
|
|
34
|
+
to.standardAppearance = from.standardAppearance;
|
|
35
|
+
to.scrollEdgeAppearance = from.scrollEdgeAppearance;
|
|
36
|
+
to.compactAppearance = from.compactAppearance;
|
|
37
|
+
to.compactScrollEdgeAppearance = from.compactScrollEdgeAppearance;
|
|
38
|
+
to.hidesSearchBarWhenScrolling = from.hidesSearchBarWhenScrolling;
|
|
39
|
+
to.searchController =
|
|
40
|
+
from.searchController ? [[UISearchController alloc] initWithSearchResultsController:nil] : nil;
|
|
41
|
+
if (@available(iOS 16.0, *)) {
|
|
42
|
+
to.style = from.style;
|
|
43
|
+
to.preferredSearchBarPlacement = from.preferredSearchBarPlacement;
|
|
44
|
+
}
|
|
45
|
+
if (@available(iOS 26.0, *)) {
|
|
46
|
+
to.attributedSubtitle = from.attributedSubtitle;
|
|
47
|
+
to.largeAttributedSubtitle = from.largeAttributedSubtitle;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Everything the measure reads: the same answer while none of it changed.
|
|
52
|
+
static NSString *ANNPlaceSignature(UINavigationItem *item, UINavigationController *stack, BOOL showsTopBar,
|
|
53
|
+
BOOL showsToolbar) {
|
|
54
|
+
UIView *stackView = stack.view;
|
|
55
|
+
NSMutableString *signature = [NSMutableString
|
|
56
|
+
stringWithFormat:@"%@|%@|%ld|%p|%p|%p|%p|%p|%d|%d|%d|%d|%@|%@", item.title, item.prompt,
|
|
57
|
+
(long)item.largeTitleDisplayMode, item.standardAppearance,
|
|
58
|
+
item.scrollEdgeAppearance, item.compactAppearance,
|
|
59
|
+
item.compactScrollEdgeAppearance, item.searchController,
|
|
60
|
+
item.hidesSearchBarWhenScrolling, stack.navigationBar.prefersLargeTitles,
|
|
61
|
+
showsTopBar, showsToolbar, NSStringFromCGSize(stackView.bounds.size),
|
|
62
|
+
NSStringFromUIEdgeInsets(stackView.safeAreaInsets)];
|
|
63
|
+
[signature appendFormat:@"|%p|%ld", stack,
|
|
64
|
+
(long)stack.topViewController.navigationItem.largeTitleDisplayMode];
|
|
65
|
+
if (@available(iOS 16.0, *)) {
|
|
66
|
+
[signature appendFormat:@"|%ld|%ld", (long)item.style, (long)item.preferredSearchBarPlacement];
|
|
67
|
+
}
|
|
68
|
+
if (@available(iOS 26.0, *)) {
|
|
69
|
+
[signature appendFormat:@"|%@|%@", item.attributedSubtitle, item.largeAttributedSubtitle];
|
|
70
|
+
}
|
|
71
|
+
return signature;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@implementation ANNScreenPlace {
|
|
75
|
+
NSString *_signature;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
- (instancetype)initWithSafeArea:(UIEdgeInsets)safeArea
|
|
79
|
+
showsTopBar:(BOOL)showsTopBar
|
|
80
|
+
showsTabBar:(BOOL)showsTabBar
|
|
81
|
+
signature:(NSString *)signature {
|
|
82
|
+
if (self = [super init]) {
|
|
83
|
+
_safeArea = safeArea;
|
|
84
|
+
_showsTopBar = showsTopBar;
|
|
85
|
+
_showsTabBar = showsTabBar;
|
|
86
|
+
_signature = [signature copy];
|
|
87
|
+
}
|
|
88
|
+
return self;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
+ (ANNScreenPlace *)placeOfEntry:(UIViewController *)entry
|
|
92
|
+
inStack:(UINavigationController *)stack
|
|
93
|
+
options:(ANNNavigationOptions *)options {
|
|
94
|
+
ANNAssertMainQueue();
|
|
95
|
+
UIView *stackView = stack.viewIfLoaded;
|
|
96
|
+
UIWindow *window = stackView.window;
|
|
97
|
+
if (!window) {
|
|
98
|
+
return nil;
|
|
99
|
+
}
|
|
100
|
+
BOOL showsTopBar = [options.topBar.visible withDefault:YES];
|
|
101
|
+
BOOL showsToolbar = options.toolbar.shouldShow;
|
|
102
|
+
BOOL showsTabBar = !entry.hidesBottomBarWhenPushed &&
|
|
103
|
+
[[ANNBottomTabsController tabsOf:entry] showsTabBarForScreen:entry];
|
|
104
|
+
NSString *signature =
|
|
105
|
+
ANNPlaceSignature(entry.navigationItem, stack, showsTopBar, showsToolbar);
|
|
106
|
+
ANNScreenPlace *kept = objc_getAssociatedObject(entry, ANNScreenPlaceKey);
|
|
107
|
+
if (kept && kept.showsTabBar == showsTabBar && [kept->_signature isEqualToString:signature]) {
|
|
108
|
+
return kept;
|
|
109
|
+
}
|
|
110
|
+
UIEdgeInsets safeArea = [self measureEntry:entry
|
|
111
|
+
inStack:stack
|
|
112
|
+
showsTopBar:showsTopBar
|
|
113
|
+
showsToolbar:showsToolbar];
|
|
114
|
+
// The measure stands in the stack's view, whose safe area has the tab bar shown now: an entry that hides it gets
|
|
115
|
+
// the window's bottom there.
|
|
116
|
+
if (!showsTabBar) {
|
|
117
|
+
CGFloat tabBar = stackView.safeAreaInsets.bottom - window.safeAreaInsets.bottom;
|
|
118
|
+
if (tabBar > 0) {
|
|
119
|
+
safeArea.bottom = MAX(safeArea.bottom - tabBar, 0);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
ANNScreenPlace *place = [[ANNScreenPlace alloc] initWithSafeArea:safeArea
|
|
123
|
+
showsTopBar:showsTopBar
|
|
124
|
+
showsTabBar:showsTabBar
|
|
125
|
+
signature:signature];
|
|
126
|
+
objc_setAssociatedObject(entry, ANNScreenPlaceKey, place, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
127
|
+
return place;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// The probe lays out at the stack's size in the stack's view, unseen and for this moment only, and leaves no search
|
|
131
|
+
// field behind.
|
|
132
|
+
+ (UIEdgeInsets)measureEntry:(UIViewController *)entry
|
|
133
|
+
inStack:(UINavigationController *)stack
|
|
134
|
+
showsTopBar:(BOOL)showsTopBar
|
|
135
|
+
showsToolbar:(BOOL)showsToolbar {
|
|
136
|
+
UINavigationController *probe = ANNPlaceProbeOf(stack);
|
|
137
|
+
UIViewController *below = probe.viewControllers.firstObject;
|
|
138
|
+
UIViewController *top = probe.topViewController;
|
|
139
|
+
UINavigationBar *bar = probe.navigationBar;
|
|
140
|
+
UINavigationBar *stackBar = stack.navigationBar;
|
|
141
|
+
bar.prefersLargeTitles = stackBar.prefersLargeTitles;
|
|
142
|
+
bar.standardAppearance = stackBar.standardAppearance;
|
|
143
|
+
bar.scrollEdgeAppearance = stackBar.scrollEdgeAppearance;
|
|
144
|
+
bar.compactAppearance = stackBar.compactAppearance;
|
|
145
|
+
below.navigationItem.largeTitleDisplayMode =
|
|
146
|
+
stack.topViewController.navigationItem.largeTitleDisplayMode;
|
|
147
|
+
ANNCopyBarItem(entry.navigationItem, top.navigationItem);
|
|
148
|
+
top.toolbarItems =
|
|
149
|
+
showsToolbar ? @[ [[UIBarButtonItem alloc] initWithTitle:@" "
|
|
150
|
+
style:UIBarButtonItemStylePlain
|
|
151
|
+
target:nil
|
|
152
|
+
action:nil] ]
|
|
153
|
+
: nil;
|
|
154
|
+
__block UIEdgeInsets safeArea = UIEdgeInsetsZero;
|
|
155
|
+
UIView *stackView = stack.view;
|
|
156
|
+
UIView *probeView = probe.view;
|
|
157
|
+
[UIView performWithoutAnimation:^{
|
|
158
|
+
[probe setNavigationBarHidden:!showsTopBar animated:NO];
|
|
159
|
+
[probe setToolbarHidden:!showsToolbar animated:NO];
|
|
160
|
+
probeView.alpha = 0;
|
|
161
|
+
probeView.userInteractionEnabled = NO;
|
|
162
|
+
probeView.accessibilityElementsHidden = YES;
|
|
163
|
+
probeView.frame = stackView.bounds;
|
|
164
|
+
[stackView insertSubview:probeView atIndex:0];
|
|
165
|
+
[probeView layoutIfNeeded];
|
|
166
|
+
[top.view layoutIfNeeded];
|
|
167
|
+
safeArea = top.view.safeAreaInsets;
|
|
168
|
+
[probeView removeFromSuperview];
|
|
169
|
+
}];
|
|
170
|
+
top.navigationItem.searchController = nil;
|
|
171
|
+
top.toolbarItems = nil;
|
|
172
|
+
return safeArea;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@end
|
|
@@ -15,8 +15,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
15
15
|
/// `showInColumn`: the push's checks of the layout (the options of the tree, what the core makes), then the screen is
|
|
16
16
|
/// made and waits by the push's rules. Once it is ready, by the state then: the source in a split view not collapsed
|
|
17
17
|
/// into its compact layout — the split view shows the screen in `column`, unless a later request of that column began
|
|
18
|
-
/// meanwhile (the last one wins
|
|
19
|
-
///
|
|
18
|
+
/// meanwhile (the last one wins; the superseded one answers when the last one does, with its own screen's id whatever
|
|
19
|
+
/// the last one's outcome, as on Android); else the source in a stack — a push over it; else a rejection. The answer
|
|
20
|
+
/// is the shown screen's id; every rejection destroys the screen.
|
|
20
21
|
+ (void)showInColumn:(NSString *)column
|
|
21
22
|
layout:(ANNLayoutNode *)layout
|
|
22
23
|
componentId:(NSString *)componentId
|
|
@@ -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:^{
|
|
@@ -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
|
|