@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
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#import "ANNEventEmitter.h"
|
|
3
3
|
#import "ANNScreenInsets.h"
|
|
4
4
|
#import "ANNSearchResultsViewController.h"
|
|
5
|
+
#import "ANNUserChoice.h"
|
|
5
6
|
|
|
6
7
|
static void *ANNSearchFieldColorContext = &ANNSearchFieldColorContext;
|
|
7
8
|
|
|
@@ -49,6 +50,47 @@ static NSString *ANNResultsKey(ANNComponentOptions *component) {
|
|
|
49
50
|
return [NSString stringWithFormat:@"%@\n%@", component.name.get, component.componentId.get];
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
static NSString *const ANNScopeChoiceKey = @"topBar.searchBar.selectedScope";
|
|
54
|
+
static NSString *const ANNTokensChoiceKey = @"topBar.searchBar.tokens";
|
|
55
|
+
static NSString *const ANNSuggestionsChoiceKey = @"topBar.searchBar.suggestions";
|
|
56
|
+
|
|
57
|
+
static BOOL ANNHasScope(ANNNavigationOptions *options, NSString *scopeId) {
|
|
58
|
+
for (ANNSearchScopeOptions *scope in options.topBar.searchBar.scopes) {
|
|
59
|
+
if ([[scope.identifier withDefault:nil] isEqualToString:scopeId]) {
|
|
60
|
+
return YES;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return NO;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// The scope the user picked, by its id: it stays over the app's `selectedScope` where the scopes have it, as on
|
|
67
|
+
// Android (`UserChoices.yieldTo`). It goes at a merge into the screen that gives another `selectedScope` than the app
|
|
68
|
+
// had there (the own options', else the screen's resolution before the merge), or after which the screen's scopes
|
|
69
|
+
// don't have it.
|
|
70
|
+
static ANNUserChoice *ANNScopeChoice(NSString *scope) {
|
|
71
|
+
return [ANNUserChoice choiceWithValue:scope
|
|
72
|
+
apply:^(ANNNavigationOptions *options, id value) {
|
|
73
|
+
if (ANNHasScope(options, value)) {
|
|
74
|
+
options.topBar.searchBar.selectedScope = [Text withValue:value];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
merged:^id(id value, ANNNavigationOptions *merge, ANNNavigationOptions *own,
|
|
78
|
+
ANNNavigationOptions *before, ANNNavigationOptions *after) {
|
|
79
|
+
if (!ANNHasScope(after, value)) {
|
|
80
|
+
return nil;
|
|
81
|
+
}
|
|
82
|
+
Text *given = merge.topBar.searchBar.selectedScope;
|
|
83
|
+
if (!given.hasValue) {
|
|
84
|
+
return value;
|
|
85
|
+
}
|
|
86
|
+
Text *ownScope = own.topBar.searchBar.selectedScope;
|
|
87
|
+
Text *was = ownScope.hasValue ? ownScope : before.topBar.searchBar.selectedScope;
|
|
88
|
+
NSString *merged = [given withDefault:nil];
|
|
89
|
+
NSString *had = [was withDefault:nil];
|
|
90
|
+
return merged == had || [merged isEqualToString:had] ? value : nil;
|
|
91
|
+
}];
|
|
92
|
+
}
|
|
93
|
+
|
|
52
94
|
@interface ANNSearchPresenter () <UISearchResultsUpdating, UISearchBarDelegate, UISearchControllerDelegate>
|
|
53
95
|
@end
|
|
54
96
|
|
|
@@ -380,9 +422,11 @@ static NSString *ANNResultsKey(ANNComponentOptions *component) {
|
|
|
380
422
|
|
|
381
423
|
#pragma mark - Tokens
|
|
382
424
|
|
|
425
|
+
// A token's key names its icon by the source the options give, never by the decoded image: a key read before and after
|
|
426
|
+
// the cache lets the image go, or a file at the same path changes, stays the same, and computing it loads nothing.
|
|
383
427
|
static NSString *ANNTokenKey(ANNSearchTokenOptions *token) {
|
|
384
428
|
return [NSString stringWithFormat:@"%@\n%@\n%@\n%@", [token.identifier withDefault:@""], [token.text withDefault:@""],
|
|
385
|
-
[token.sfSymbol withDefault:@""],
|
|
429
|
+
[token.sfSymbol withDefault:@""], token.icon.source.sourceKey ?: @""];
|
|
386
430
|
}
|
|
387
431
|
|
|
388
432
|
static NSArray<NSString *> *ANNTokenIds(NSArray<UISearchToken *> *tokens) {
|
|
@@ -395,6 +439,59 @@ static NSArray<NSString *> *ANNTokenIds(NSArray<UISearchToken *> *tokens) {
|
|
|
395
439
|
return ids;
|
|
396
440
|
}
|
|
397
441
|
|
|
442
|
+
static NSArray<NSString *> *ANNTokenKeys(NSArray<ANNSearchTokenOptions *> *tokens) {
|
|
443
|
+
NSMutableArray<NSString *> *keys = [NSMutableArray new];
|
|
444
|
+
for (ANNSearchTokenOptions *token in tokens) {
|
|
445
|
+
[keys addObject:ANNTokenKey(token)];
|
|
446
|
+
}
|
|
447
|
+
return keys;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// The tokens the field has after the user deleted some (or brought them back with Undo), as copies of their options:
|
|
451
|
+
// they stay over the app's `tokens` until a merge gives a list other than the app had there (the own options', else
|
|
452
|
+
// the screen's resolution before the merge), as the other choices. After a merge the tokens the screen's resolution no
|
|
453
|
+
// longer has (by id) leave the choice, and all of them when it has no `tokens`.
|
|
454
|
+
static ANNUserChoice *ANNTokensChoice(NSArray<ANNSearchTokenOptions *> *tokens) {
|
|
455
|
+
return [ANNUserChoice choiceWithValue:tokens
|
|
456
|
+
apply:^(ANNNavigationOptions *options, id value) {
|
|
457
|
+
// Copies: two trees never share a group.
|
|
458
|
+
NSArray<ANNSearchTokenOptions *> *kept = value;
|
|
459
|
+
NSMutableArray<ANNSearchTokenOptions *> *copies =
|
|
460
|
+
[NSMutableArray arrayWithCapacity:kept.count];
|
|
461
|
+
for (ANNSearchTokenOptions *token in kept) {
|
|
462
|
+
[copies addObject:[token copy]];
|
|
463
|
+
}
|
|
464
|
+
options.topBar.searchBar.tokens = copies;
|
|
465
|
+
}
|
|
466
|
+
merged:^id(id value, ANNNavigationOptions *merge, ANNNavigationOptions *own,
|
|
467
|
+
ANNNavigationOptions *before, ANNNavigationOptions *after) {
|
|
468
|
+
NSArray<ANNSearchTokenOptions *> *now = after.topBar.searchBar.tokens;
|
|
469
|
+
if (!now) {
|
|
470
|
+
return nil;
|
|
471
|
+
}
|
|
472
|
+
NSArray<ANNSearchTokenOptions *> *given = merge.topBar.searchBar.tokens;
|
|
473
|
+
if (given) {
|
|
474
|
+
NSArray<ANNSearchTokenOptions *> *was =
|
|
475
|
+
own.topBar.searchBar.tokens ?: before.topBar.searchBar.tokens;
|
|
476
|
+
if (!was || ![ANNTokenKeys(given) isEqualToArray:ANNTokenKeys(was)]) {
|
|
477
|
+
return nil;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
NSMutableSet<NSString *> *ids = [NSMutableSet new];
|
|
481
|
+
for (ANNSearchTokenOptions *token in now) {
|
|
482
|
+
[ids addObject:[token.identifier withDefault:@""]];
|
|
483
|
+
}
|
|
484
|
+
NSArray<ANNSearchTokenOptions *> *chosen = value;
|
|
485
|
+
NSMutableArray<ANNSearchTokenOptions *> *kept = [NSMutableArray new];
|
|
486
|
+
for (ANNSearchTokenOptions *token in chosen) {
|
|
487
|
+
if ([ids containsObject:[token.identifier withDefault:@""]]) {
|
|
488
|
+
[kept addObject:token];
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return kept.count == chosen.count ? value : kept;
|
|
492
|
+
}];
|
|
493
|
+
}
|
|
494
|
+
|
|
398
495
|
// The field gets the tokens again only when the options changed: setting them resets the user's selection.
|
|
399
496
|
- (void)applyTokens:(NSArray<ANNSearchTokenOptions *> *)tokens field:(UISearchTextField *)field {
|
|
400
497
|
if (!tokens) {
|
|
@@ -426,7 +523,7 @@ static NSArray<NSString *> *ANNTokenIds(NSArray<UISearchToken *> *tokens) {
|
|
|
426
523
|
field.tokens = searchTokens;
|
|
427
524
|
}
|
|
428
525
|
|
|
429
|
-
// The tokens the field has now,
|
|
526
|
+
// The tokens the field has now, kept in the screen's user layer when the user deleted some (or brought them back with
|
|
430
527
|
// Undo), so the options apply them as they are. Their ids, or nil when the search bar has no tokens option.
|
|
431
528
|
- (NSArray<NSString *> *)syncTokens:(UISearchTextField *)field {
|
|
432
529
|
if (!_tokenOptions) {
|
|
@@ -444,24 +541,73 @@ static NSArray<NSString *> *ANNTokenIds(NSArray<UISearchToken *> *tokens) {
|
|
|
444
541
|
}
|
|
445
542
|
if (![_appliedTokens isEqualToArray:keys]) {
|
|
446
543
|
_appliedTokens = keys;
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}];
|
|
544
|
+
// Copies: the objects above belong to the applied tree, and two trees never share a group.
|
|
545
|
+
NSMutableArray<ANNSearchTokenOptions *> *kept =
|
|
546
|
+
[NSMutableArray arrayWithCapacity:tokens.count];
|
|
547
|
+
for (ANNSearchTokenOptions *token in tokens) {
|
|
548
|
+
[kept addObject:[token copy]];
|
|
549
|
+
}
|
|
550
|
+
[_viewController setUserChoice:ANNTokensChoice(kept) forKey:ANNTokensChoiceKey];
|
|
455
551
|
}
|
|
456
552
|
return ids;
|
|
457
553
|
}
|
|
458
554
|
|
|
459
555
|
#pragma mark - Suggestions
|
|
460
556
|
|
|
557
|
+
// A suggestion's key names its icon by its source, as a token's does (`ANNTokenKey`).
|
|
461
558
|
static NSString *ANNSuggestionKey(ANNSearchSuggestionOptions *suggestion) {
|
|
462
559
|
return [NSString stringWithFormat:@"%@\n%@\n%@\n%@\n%@", [suggestion.identifier withDefault:@""],
|
|
463
560
|
[suggestion.title withDefault:@""], [suggestion.accessibilityLabel withDefault:@""],
|
|
464
|
-
[suggestion.sfSymbol withDefault:@""],
|
|
561
|
+
[suggestion.sfSymbol withDefault:@""], suggestion.icon.source.sourceKey ?: @""];
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
static NSArray<NSString *> *ANNSuggestionKeys(NSArray<ANNSearchSuggestionOptions *> *suggestions) {
|
|
565
|
+
NSMutableArray<NSString *> *keys = [NSMutableArray new];
|
|
566
|
+
for (ANNSearchSuggestionOptions *suggestion in suggestions) {
|
|
567
|
+
[keys addObject:ANNSuggestionKey(suggestion)];
|
|
568
|
+
}
|
|
569
|
+
return keys;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// The suggestions UIKit removed, by their keys: they stay out of the app's `suggestions` until the next merge that
|
|
573
|
+
// gives `suggestions`, any list, the same one again too (a fixed list sent on every search-updated event shows each
|
|
574
|
+
// time), as on Android, which shows whatever list a merge gives. After a merge without them the removed ones the
|
|
575
|
+
// screen's resolution no longer has leave the choice.
|
|
576
|
+
static ANNUserChoice *ANNRemovedSuggestionsChoice(NSArray<NSString *> *removed) {
|
|
577
|
+
return [ANNUserChoice choiceWithValue:removed
|
|
578
|
+
apply:^(ANNNavigationOptions *options, id value) {
|
|
579
|
+
NSArray<ANNSearchSuggestionOptions *> *suggestions = options.topBar.searchBar.suggestions;
|
|
580
|
+
if (!suggestions) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
NSSet<NSString *> *gone = [NSSet setWithArray:value];
|
|
584
|
+
NSMutableArray<ANNSearchSuggestionOptions *> *kept = [NSMutableArray new];
|
|
585
|
+
for (ANNSearchSuggestionOptions *suggestion in suggestions) {
|
|
586
|
+
if (![gone containsObject:ANNSuggestionKey(suggestion)]) {
|
|
587
|
+
[kept addObject:suggestion];
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
options.topBar.searchBar.suggestions = kept;
|
|
591
|
+
}
|
|
592
|
+
merged:^id(id value, ANNNavigationOptions *merge, ANNNavigationOptions *own,
|
|
593
|
+
ANNNavigationOptions *before, ANNNavigationOptions *after) {
|
|
594
|
+
if (merge.topBar.searchBar.suggestions) {
|
|
595
|
+
return nil;
|
|
596
|
+
}
|
|
597
|
+
NSSet<NSString *> *now =
|
|
598
|
+
[NSSet setWithArray:ANNSuggestionKeys(after.topBar.searchBar.suggestions)];
|
|
599
|
+
NSArray<NSString *> *removed = value;
|
|
600
|
+
NSMutableArray<NSString *> *kept = [NSMutableArray new];
|
|
601
|
+
for (NSString *key in removed) {
|
|
602
|
+
if ([now containsObject:key]) {
|
|
603
|
+
[kept addObject:key];
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
if (kept.count == 0) {
|
|
607
|
+
return nil;
|
|
608
|
+
}
|
|
609
|
+
return kept.count == removed.count ? value : kept;
|
|
610
|
+
}];
|
|
465
611
|
}
|
|
466
612
|
|
|
467
613
|
- (void)applySuggestions:(NSArray<ANNSearchSuggestionOptions *> *)suggestions
|
|
@@ -491,13 +637,20 @@ static NSString *ANNSuggestionKey(ANNSearchSuggestionOptions *suggestion) {
|
|
|
491
637
|
search.searchSuggestions = items.count ? items : nil;
|
|
492
638
|
}
|
|
493
639
|
|
|
494
|
-
// UIKit has removed the suggestions:
|
|
640
|
+
// UIKit has removed the suggestions: the screen's user layer keeps them out, with those it removed before, until the
|
|
641
|
+
// next mergeOptions that gives suggestions, which show.
|
|
495
642
|
- (void)syncSuggestions:(UISearchController *)search API_AVAILABLE(ios(16.0)) {
|
|
496
643
|
if (_appliedSuggestions.count && !search.searchSuggestions.count) {
|
|
644
|
+
NSArray<NSString *> *removed = _appliedSuggestions;
|
|
497
645
|
_appliedSuggestions = @[];
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
646
|
+
UIViewController<ANNLayoutProtocol> *viewController = _viewController;
|
|
647
|
+
ANNUserChoice *before = [viewController userChoiceForKey:ANNSuggestionsChoiceKey];
|
|
648
|
+
NSArray<NSString *> *removedBefore = before.value;
|
|
649
|
+
if (removedBefore.count) {
|
|
650
|
+
removed = [removedBefore arrayByAddingObjectsFromArray:removed];
|
|
651
|
+
}
|
|
652
|
+
[viewController setUserChoice:ANNRemovedSuggestionsChoice(removed)
|
|
653
|
+
forKey:ANNSuggestionsChoiceKey];
|
|
501
654
|
}
|
|
502
655
|
}
|
|
503
656
|
|
|
@@ -606,14 +759,12 @@ static NSString *ANNSuggestionKey(ANNSearchSuggestionOptions *suggestion) {
|
|
|
606
759
|
}
|
|
607
760
|
}
|
|
608
761
|
|
|
609
|
-
// The pick is
|
|
762
|
+
// The pick is kept in the screen's user layer, so it stays when the options apply again. UIKit then updates the
|
|
610
763
|
// search results: searchBarUpdated carries the new scope.
|
|
611
764
|
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope {
|
|
612
765
|
NSString *scope = [self selectedScope:searchBar];
|
|
613
766
|
if (scope) {
|
|
614
|
-
[_viewController
|
|
615
|
-
options.topBar.searchBar.selectedScope = [Text withValue:scope];
|
|
616
|
-
}];
|
|
767
|
+
[_viewController setUserChoice:ANNScopeChoice(scope) forKey:ANNScopeChoiceKey];
|
|
617
768
|
}
|
|
618
769
|
}
|
|
619
770
|
|
|
@@ -88,6 +88,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
88
88
|
/// had no large title: a large title that doesn't fold into the list fills its place there until the screen appeared.
|
|
89
89
|
- (void)shownFromLowerBarWithBottom:(CGFloat)oldBarBottom;
|
|
90
90
|
|
|
91
|
+
/// iOS 26, a push starts that brings the screen in with its content drawn, before UIKit's push: its large title keeps
|
|
92
|
+
/// a place in the screen for the whole transition (`screenInPush:` of `ANNLargeTitlePresenter`). Nothing for a screen
|
|
93
|
+
/// that didn't wait parked for its content: its content comes in the push.
|
|
94
|
+
- (void)arrivesByPushOn:(UINavigationController *)navigation;
|
|
95
|
+
|
|
91
96
|
/// iOS 26, a pop or a swipe back starts that reveals the screen, after its will-appear and before UIKit lays it out
|
|
92
97
|
/// for the transition: its large title keeps a place in the window for the whole transition. Returns whether the title
|
|
93
98
|
/// is in that place.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#import "ANNBackButtonPresenter.h"
|
|
3
3
|
#import "ANNBarAppearance.h"
|
|
4
4
|
#import "ANNComponentPresenter.h"
|
|
5
|
+
#import "ANNComponentViewController.h"
|
|
5
6
|
#import "ANNExternalViewController.h"
|
|
6
7
|
#import "ANNLargeTitlePresenter.h"
|
|
7
8
|
#import "ANNMainList.h"
|
|
@@ -13,6 +14,7 @@
|
|
|
13
14
|
#import "ANNTitleGlassView.h"
|
|
14
15
|
#import "ANNTitleView.h"
|
|
15
16
|
#import "ANNToolbarPresenter.h"
|
|
17
|
+
#import "ANNUserChoice.h"
|
|
16
18
|
#import "UIViewController+LayoutProtocol.h"
|
|
17
19
|
|
|
18
20
|
// The key of the bar's handler on the screen's content mounts.
|
|
@@ -59,6 +61,30 @@ static NSArray<UIMenuElement *> *ANNRenameElementsOf(NSArray<UIMenuElement *> *e
|
|
|
59
61
|
return kept;
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
static NSString *const ANNRenameChoiceKey = @"topBar.title.text";
|
|
65
|
+
|
|
66
|
+
// The title the user gave: it stays over the app's `title.text` until a merge gives another text than the app had
|
|
67
|
+
// there (the own options', else the title the screen resolved to before the merge, as the other choices); a re-render
|
|
68
|
+
// that sends the old title again keeps it.
|
|
69
|
+
static ANNUserChoice *ANNRenameChoice(NSString *title) {
|
|
70
|
+
return [ANNUserChoice choiceWithValue:title
|
|
71
|
+
apply:^(ANNNavigationOptions *options, id value) {
|
|
72
|
+
options.topBar.title.text = [Text withValue:value];
|
|
73
|
+
}
|
|
74
|
+
merged:^id(id value, ANNNavigationOptions *merge, ANNNavigationOptions *own,
|
|
75
|
+
ANNNavigationOptions *before, ANNNavigationOptions *after) {
|
|
76
|
+
Text *text = merge.topBar.title.text;
|
|
77
|
+
if (!text.hasValue) {
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
Text *ownText = own.topBar.title.text;
|
|
81
|
+
Text *was = ownText.hasValue ? ownText : before.topBar.title.text;
|
|
82
|
+
NSString *merged = [text withDefault:nil];
|
|
83
|
+
NSString *had = [was withDefault:nil];
|
|
84
|
+
return merged == had || [merged isEqualToString:had] ? value : nil;
|
|
85
|
+
}];
|
|
86
|
+
}
|
|
87
|
+
|
|
62
88
|
@interface ANNTopBarPresenter () <UINavigationItemRenameDelegate>
|
|
63
89
|
@end
|
|
64
90
|
|
|
@@ -495,8 +521,11 @@ static NSArray<UIMenuElement *> *ANNRenameElementsOf(NSArray<UIMenuElement *> *e
|
|
|
495
521
|
// The layers of the title: the screen's own text hides a component of its stack or of the defaults; a component in the
|
|
496
522
|
// screen's own options shows over its own text.
|
|
497
523
|
- (BOOL)ownTextHidesComponent {
|
|
498
|
-
|
|
499
|
-
|
|
524
|
+
UIViewController *screen = _screen;
|
|
525
|
+
ANNTopBarTitleOptions *own = screen.options.topBar.title;
|
|
526
|
+
BOOL ownText = (own.text.hasValue && !own.text.isNull) ||
|
|
527
|
+
[screen userChoiceForKey:ANNRenameChoiceKey] != nil;
|
|
528
|
+
return ownText && !ANNHasComponentName(own.component);
|
|
500
529
|
}
|
|
501
530
|
|
|
502
531
|
// iOS 26: the system subtitle under the title and under the large title, with only the attributes given (a color, or
|
|
@@ -644,11 +673,12 @@ static NSArray<UIMenuElement *> *ANNRenameElementsOf(NSArray<UIMenuElement *> *e
|
|
|
644
673
|
__weak ANNBarButtons *buttons = _buttons;
|
|
645
674
|
UIMenu *menu = [title.menu menuWithPickHandler:^(NSString *itemId) {
|
|
646
675
|
[buttons menuItemPicked:itemId
|
|
647
|
-
|
|
648
|
-
|
|
676
|
+
choiceKey:@"topBar.title.menu"
|
|
677
|
+
menuOf:^ANNMenuOptions *(ANNNavigationOptions *options) {
|
|
678
|
+
return options.topBar.title.menu;
|
|
649
679
|
}
|
|
650
|
-
setMenu:^(ANNNavigationOptions *
|
|
651
|
-
|
|
680
|
+
setMenu:^(ANNNavigationOptions *options, ANNMenuOptions *copy) {
|
|
681
|
+
options.topBar.title.menu = copy;
|
|
652
682
|
}];
|
|
653
683
|
}];
|
|
654
684
|
menuTitle = menu.title;
|
|
@@ -659,8 +689,8 @@ static NSArray<UIMenuElement *> *ANNRenameElementsOf(NSArray<UIMenuElement *> *e
|
|
|
659
689
|
|
|
660
690
|
#pragma mark - UINavigationItemRenameDelegate
|
|
661
691
|
|
|
662
|
-
// Empty or blank: the old title back, no event; the same: nothing; new: the screen's
|
|
663
|
-
// again, then `ANN.TitleRenamed`.
|
|
692
|
+
// Empty or blank: the old title back, no event; the same: nothing; new: `title.text` in the screen's user layer, the
|
|
693
|
+
// title drawn again, then `ANN.TitleRenamed`.
|
|
664
694
|
- (void)navigationItem:(UINavigationItem *)navigationItem
|
|
665
695
|
didEndRenamingWithTitle:(NSString *)title {
|
|
666
696
|
UIViewController *screen = _screen;
|
|
@@ -677,9 +707,7 @@ static NSArray<UIMenuElement *> *ANNRenameElementsOf(NSArray<UIMenuElement *> *e
|
|
|
677
707
|
if ([title isEqualToString:old]) {
|
|
678
708
|
return;
|
|
679
709
|
}
|
|
680
|
-
[screen
|
|
681
|
-
own.topBar.title.text = [Text withValue:title];
|
|
682
|
-
}];
|
|
710
|
+
[screen setUserChoice:ANNRenameChoice(title) forKey:ANNRenameChoiceKey];
|
|
683
711
|
ANNNavigationOptions *options = [screen resolveOptionsWithDefault];
|
|
684
712
|
[self applyTitle:options textWins:NO];
|
|
685
713
|
NSString *componentId = screen.layoutInfo.componentId;
|
|
@@ -1101,6 +1129,27 @@ static NSArray<UIMenuElement *> *ANNRenameElementsOf(NSArray<UIMenuElement *> *e
|
|
|
1101
1129
|
options:[screen resolveOptionsWithDefault]];
|
|
1102
1130
|
}
|
|
1103
1131
|
|
|
1132
|
+
// The top of the safe area the screen takes on the stack is that of its place while it waited parked: UIKit lays it out
|
|
1133
|
+
// only inside the push.
|
|
1134
|
+
- (void)arrivesByPushOn:(UINavigationController *)navigation {
|
|
1135
|
+
UIViewController *screen = _screen;
|
|
1136
|
+
if (_native || ![screen isKindOfClass:ANNComponentViewController.class]) {
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
ANNComponentViewController *component = (ANNComponentViewController *)screen;
|
|
1140
|
+
ANNScreenPlace * (^placeWhileParked)(void) = component.placeWhileParked;
|
|
1141
|
+
ANNScreenPlace *place = placeWhileParked ? placeWhileParked() : nil;
|
|
1142
|
+
if (!place || !component.reactView.isReady) {
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
ANNNavigationOptions *options = [screen resolveOptionsWithDefault];
|
|
1146
|
+
[_largeTitle screenInPush:options
|
|
1147
|
+
list:[self followedList]
|
|
1148
|
+
inlineInRow:[self inlineInRow:options]
|
|
1149
|
+
top:place.safeArea.top
|
|
1150
|
+
stackTop:navigation.view.safeAreaInsets.top];
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1104
1153
|
// A native screen's views are the app's: the core lays nothing into them. The band behind the title is filled where
|
|
1105
1154
|
// the title is, and the look follows it, before UIKit lays the screen out for the transition.
|
|
1106
1155
|
- (BOOL)revealedByPop {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#import "ANNEventContract.h"
|
|
11
11
|
#import "ANNExternalViewController.h"
|
|
12
12
|
#import "ANNHinge.h"
|
|
13
|
+
#import "ANNJavaScriptCalls.h"
|
|
13
14
|
#import "ANNLayoutReader.h"
|
|
14
15
|
#import "ANNModalCoordinator.h"
|
|
15
16
|
#import "ANNNativeScreenCalls.h"
|
|
@@ -29,6 +30,9 @@
|
|
|
29
30
|
#import "ANNStackCommands.h"
|
|
30
31
|
#import "ApexNavigation+Internal.h"
|
|
31
32
|
#import "UIViewController+LayoutProtocol.h"
|
|
33
|
+
#import <React/RCTCallInvokerModule.h>
|
|
34
|
+
#import <React/RCTInitializing.h>
|
|
35
|
+
#import <React/RCTInvalidating.h>
|
|
32
36
|
|
|
33
37
|
// How many modules this process made: the first one is a cold start, the next ones come with reloads of JavaScript.
|
|
34
38
|
static NSUInteger ANNTurboModuleCount;
|
|
@@ -84,6 +88,11 @@ static BOOL ANNFindsScreen(NSString *componentId, ANNCommandAnswer *answer) {
|
|
|
84
88
|
return NO;
|
|
85
89
|
}
|
|
86
90
|
|
|
91
|
+
// The module's call invoker and queue go to `ANNJavaScriptCalls`, so that a step of the core can come after the calls
|
|
92
|
+
// JavaScript made (a push after the options of its screen's first commit).
|
|
93
|
+
@interface ANNTurboModule () <RCTCallInvokerModule, RCTInitializing, RCTInvalidating>
|
|
94
|
+
@end
|
|
95
|
+
|
|
87
96
|
// Every asynchronous method takes the one path of `ANNCommandRunner`: on the module's queue the layout is read and
|
|
88
97
|
// checked whole, then one task on the main queue runs the command with its area's class. A question answers at once on
|
|
89
98
|
// the JavaScript thread what it answers before the first data.
|
|
@@ -94,6 +103,11 @@ static BOOL ANNFindsScreen(NSString *componentId, ANNCommandAnswer *answer) {
|
|
|
94
103
|
|
|
95
104
|
RCT_EXPORT_MODULE(ANNTurboModule)
|
|
96
105
|
|
|
106
|
+
// React Native gives the module its shared queue through this (it has none of its own) and its call invoker, both
|
|
107
|
+
// before `initialize`.
|
|
108
|
+
@synthesize methodQueue = _methodQueue;
|
|
109
|
+
@synthesize callInvoker = _callInvoker;
|
|
110
|
+
|
|
97
111
|
+ (BOOL)requiresMainQueueSetup {
|
|
98
112
|
return NO;
|
|
99
113
|
}
|
|
@@ -109,6 +123,14 @@ RCT_EXPORT_MODULE(ANNTurboModule)
|
|
|
109
123
|
return self;
|
|
110
124
|
}
|
|
111
125
|
|
|
126
|
+
- (void)initialize {
|
|
127
|
+
[ANNJavaScriptCalls setCallInvoker:_callInvoker methodQueue:_methodQueue ofModule:self];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
- (void)invalidate {
|
|
131
|
+
[ANNJavaScriptCalls moduleWent:self];
|
|
132
|
+
}
|
|
133
|
+
|
|
112
134
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
113
135
|
(const facebook::react::ObjCTurboModule::InitParams &)params {
|
|
114
136
|
return std::make_shared<facebook::react::NativeANNTurboModuleSpecJSI>(params);
|
|
@@ -139,7 +161,7 @@ RCT_EXPORT_MODULE(ANNTurboModule)
|
|
|
139
161
|
// navigation has a host. React Native starts its surface once the bundle ran.
|
|
140
162
|
- (void)startHost {
|
|
141
163
|
[ANNCommandRunner runVoid:@"startHost"
|
|
142
|
-
what:@"
|
|
164
|
+
what:@"start the host of the slots"
|
|
143
165
|
body:^{
|
|
144
166
|
RCTHost *host = [ApexNavigation getHost];
|
|
145
167
|
if (host) {
|
|
@@ -170,22 +192,23 @@ RCT_EXPORT_MODULE(ANNTurboModule)
|
|
|
170
192
|
}];
|
|
171
193
|
}
|
|
172
194
|
|
|
173
|
-
// `mergeOptions`:
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
195
|
+
// `mergeOptions`: without the navigation's window it logs `nowhereToShow` (JavaScript keeps the options for the next
|
|
196
|
+
// root); a node nobody has (not made yet, gone, a reload) or a node of a modal that goes with the old root takes
|
|
197
|
+
// nothing, without a log, as on Android. The values that could be read merge even when one couldn't. The whole apply
|
|
198
|
+
// is one Core Animation transaction, closed on any error. Then the modal or the overlay of the node takes the merge
|
|
199
|
+
// once (`mergeOptions` step 5).
|
|
177
200
|
- (void)mergeOptions:(NSString *)componentId options:(NSDictionary *)options {
|
|
178
201
|
NSString *what = ANNWhat(@"merge the options of the screen '%@'", componentId);
|
|
179
202
|
[ANNCommandRunner runVoid:@"mergeOptions"
|
|
180
203
|
what:what
|
|
181
204
|
body:^{
|
|
182
|
-
|
|
183
|
-
|
|
205
|
+
if (!ApexNavigation.mainWindow) {
|
|
206
|
+
[ANNCommandRunner logFailure:@"mergeOptions"
|
|
207
|
+
text:ANNErrorTexts.nowhereToShow];
|
|
184
208
|
return;
|
|
185
209
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
[ANNCommandRunner logFailure:@"mergeOptions" text:text];
|
|
210
|
+
UIViewController *node = ANNCommandNode(componentId);
|
|
211
|
+
if (!node) {
|
|
189
212
|
return;
|
|
190
213
|
}
|
|
191
214
|
NSString *unreadablePath = nil;
|
|
@@ -244,13 +267,13 @@ RCT_EXPORT_MODULE(ANNTurboModule)
|
|
|
244
267
|
}];
|
|
245
268
|
}
|
|
246
269
|
|
|
247
|
-
// iOS lays out no screen before its push: always null.
|
|
270
|
+
// iOS lays out no screen before its push: always null (`NSNull`; nil would reach JavaScript as `undefined`).
|
|
248
271
|
- (void)preparePush:(NSString *)commandId
|
|
249
272
|
componentId:(NSString *)componentId
|
|
250
273
|
layout:(NSDictionary *)layout
|
|
251
274
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
252
275
|
reject:(RCTPromiseRejectBlock)reject {
|
|
253
|
-
[ANNErrorHandler resolve:resolve of:@"preparePush" value:
|
|
276
|
+
[ANNErrorHandler resolve:resolve of:@"preparePush" value:NSNull.null];
|
|
254
277
|
}
|
|
255
278
|
|
|
256
279
|
- (void)cancelPreparedPush:(NSString *)componentId {
|
|
@@ -551,26 +574,21 @@ RCT_EXPORT_MODULE(ANNTurboModule)
|
|
|
551
574
|
check:nil
|
|
552
575
|
body:^(id layout, ANNCommandAnswer *answer) {
|
|
553
576
|
// The links module answers once the launch links are known, at once in the background
|
|
554
|
-
// (`getLaunchLink`): the URL, or null.
|
|
577
|
+
// (`getLaunchLink`): the URL, or null (`NSNull`; nil would reach JavaScript as `undefined`).
|
|
555
578
|
[ANNDeepLinkQueue takeLaunchLink:^(NSURL *url) {
|
|
556
|
-
[answer resolve:url.absoluteString];
|
|
579
|
+
[answer resolve:url.absoluteString ?: (id)NSNull.null];
|
|
557
580
|
}];
|
|
558
581
|
}];
|
|
559
582
|
}
|
|
560
583
|
|
|
561
584
|
- (void)updateNativeScreenProps:(NSString *)componentId update:(NSDictionary *)update {
|
|
562
585
|
NSString *what = ANNWhat(@"updateNativeScreenProps for the screen '%@'", componentId);
|
|
563
|
-
// At once, also during a transition; a node that isn't a native screen,
|
|
586
|
+
// At once, also during a transition; a node that isn't a native screen, no node, or a node of a modal that goes
|
|
587
|
+
// with the old root takes nothing, without a log, as on Android.
|
|
564
588
|
[ANNCommandRunner runVoid:@"updateNativeScreenProps"
|
|
565
589
|
what:what
|
|
566
590
|
body:^{
|
|
567
591
|
UIViewController *node = ANNCommandNode(componentId);
|
|
568
|
-
// A node of a modal that goes with the old root is not shown.
|
|
569
|
-
if (!node && [ANNNodeRegistry nodeForComponentId:componentId]) {
|
|
570
|
-
NSString *text = [ANNErrorTexts screenNotShown:componentId];
|
|
571
|
-
[ANNCommandRunner logFailure:@"updateNativeScreenProps" text:text];
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
592
|
if ([node isKindOfClass:ANNExternalViewController.class]) {
|
|
575
593
|
[((ANNExternalViewController *)node).nativeScreenContext
|
|
576
594
|
applyUpdate:update];
|