wip: Key Commands for Apple devices

This commit is contained in:
Djorkaeff Alexandre 2023-09-29 12:47:35 -03:00
parent 7278b36763
commit 2a0bbdc16d
7 changed files with 163 additions and 3 deletions

View File

@ -0,0 +1,5 @@
export interface IKeyCommand {
input: string;
modifierFlags: number;
discoverableTitle: string;
}

View File

@ -0,0 +1,45 @@
import { NativeModules, NativeEventEmitter } from 'react-native';
import { IKeyCommand } from '../../definitions/IKeyCommand';
const { KeyCommandsManager } = NativeModules;
const eventEmitter = new NativeEventEmitter(NativeModules.KeyCommandsManager);
class KeyCommands {
registeredListeners: { [id: string]: (keyCommand: IKeyCommand) => void } = {};
constructor() {
eventEmitter.addListener('onKeyCommand', this.onKeyCommand);
}
onKeyCommand = (keyCommand: IKeyCommand) => {
const key = this.makeKey(keyCommand);
const listener = this.registeredListeners[key];
listener(keyCommand);
};
addListener = (keyCommand: IKeyCommand, handler: (keyCommand: IKeyCommand) => void) => {
const key = this.makeKey(keyCommand);
this.registeredListeners[key] = handler;
KeyCommandsManager.registerKeyCommand(keyCommand.input, keyCommand.modifierFlags, keyCommand.discoverableTitle);
};
removeListener = (keyCommand: IKeyCommand) => {
const key = this.makeKey(keyCommand);
delete this.registeredListeners[key];
};
makeKey = (keyCommand: IKeyCommand): string => keyCommand.input + keyCommand.modifierFlags;
}
export default new KeyCommands();
// class SearchKeyCommand implements IKeyCommand {
// input = "f";
// modifierFlags: number = 0;
// discoverableTitle: string = "any";
// }
// new KeyCommands().addListener(new Command(), (command) => { console.log(command) })

View File

@ -0,0 +1,7 @@
#import "React/RCTBridgeModule.h"
@interface RCT_EXTERN_MODULE(KeyCommandsManager, NSObject)
RCT_EXTERN_METHOD(registerKeyCommand:(NSString)input modifierFlags:(nonnull NSNumber)modifierFlags discoverableTitle:(NSString)discoverableTitle)
@end

View File

@ -0,0 +1,63 @@
@objc protocol KeyCommandHandler {
func onKeyCommand(_ command: UIKeyCommand)
}
@objc(KeyCommandsManager)
final class KeyCommandsManager: RCTEventEmitter {
@objc
private(set) static var shared: KeyCommandsManager?
@objc
private(set) var commands: [UIKeyCommand] = []
@objc
static var handler: KeyCommandHandler?
private struct Event {
static let onKeyCommand = "onKeyCommand"
}
override init() {
super.init()
KeyCommandsManager.shared = self
}
override func supportedEvents() -> [String] {
[Event.onKeyCommand]
}
@objc
func registerKeyCommand(_ input: NSString, modifierFlags: NSNumber, discoverableTitle: NSString) {
guard let handler = KeyCommandsManager.handler else {
return
}
let command = UIKeyCommand(
input: String(input),
modifierFlags: UIKeyModifierFlags(rawValue: modifierFlags.intValue),
action: #selector(handler.onKeyCommand(_:)),
discoverabilityTitle: String(discoverableTitle)
)
if #available(iOS 15.0, *) {
command.wantsPriorityOverSystemBehavior = true
}
commands.append(command)
}
@objc
func onKeyCommand(_ command: UIKeyCommand) {
guard let input = command.input, let discoverabilityTitle = command.discoverabilityTitle else {
return
}
let body: [String: Any] = [
"input": input,
"modifierFlags": NSNumber(integerLiteral: command.modifierFlags.rawValue),
"discoverableTitle": discoverabilityTitle
]
sendEvent(withName: Event.onKeyCommand, body: body)
}
}

View File

@ -33,12 +33,16 @@
1E1EA8162326CD4500E22452 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E1EA8152326CD4500E22452 /* VideoToolbox.framework */; };
1E1EA8182326CD4B00E22452 /* libc.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E1EA8172326CD4B00E22452 /* libc.tbd */; };
1E1EA81A2326CD5100E22452 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E1EA8192326CD5100E22452 /* libsqlite3.tbd */; };
1E2511352AC64A2100EFED30 /* KeyCommandsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2511342AC64A2100EFED30 /* KeyCommandsManager.swift */; };
1E2511382AC64A5C00EFED30 /* KeyCommandsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E2511372AC64A5C00EFED30 /* KeyCommandsManager.m */; };
1E25743422CBA2CF005A877F /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7ACD4853222860DE00442C55 /* JavaScriptCore.framework */; };
1E2F615B25128F9A00871711 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2F615A25128F9A00871711 /* API.swift */; };
1E2F615D25128FA300871711 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2F615C25128FA300871711 /* Response.swift */; };
1E2F61642512955D00871711 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2F61632512955D00871711 /* HTTPMethod.swift */; };
1E2F61662512958900871711 /* Push.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2F61652512958900871711 /* Push.swift */; };
1E470E832513A71E00E3DD1D /* RocketChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E470E822513A71E00E3DD1D /* RocketChat.swift */; };
1E51A3D32AC7126D00028137 /* KeyCommandsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2511342AC64A2100EFED30 /* KeyCommandsManager.swift */; };
1E51A3D42AC7127000028137 /* KeyCommandsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E2511372AC64A5C00EFED30 /* KeyCommandsManager.m */; };
1E51D962251263CD00DC95DE /* MessageType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E51D961251263CD00DC95DE /* MessageType.swift */; };
1E51D965251263D600DC95DE /* NotificationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E51D964251263D600DC95DE /* NotificationType.swift */; };
1E598AE42515057D002BDFBD /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E598AE32515057D002BDFBD /* Date+Extensions.swift */; };
@ -239,6 +243,8 @@
1E1EA8152326CD4500E22452 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
1E1EA8172326CD4B00E22452 /* libc.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libc.tbd; path = usr/lib/libc.tbd; sourceTree = SDKROOT; };
1E1EA8192326CD5100E22452 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
1E2511342AC64A2100EFED30 /* KeyCommandsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyCommandsManager.swift; sourceTree = "<group>"; };
1E2511372AC64A5C00EFED30 /* KeyCommandsManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeyCommandsManager.m; sourceTree = "<group>"; };
1E2F615A25128F9A00871711 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = "<group>"; };
1E2F615C25128FA300871711 /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = "<group>"; };
1E2F61632512955D00871711 /* HTTPMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPMethod.swift; sourceTree = "<group>"; };
@ -396,6 +402,15 @@
path = API;
sourceTree = "<group>";
};
1E2511302AC649B800EFED30 /* KeyCommands */ = {
isa = PBXGroup;
children = (
1E2511342AC64A2100EFED30 /* KeyCommandsManager.swift */,
1E2511372AC64A5C00EFED30 /* KeyCommandsManager.m */,
);
path = KeyCommands;
sourceTree = "<group>";
};
1E2F61622512954500871711 /* Requests */ = {
isa = PBXGroup;
children = (
@ -521,6 +536,7 @@
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
1E2511302AC649B800EFED30 /* KeyCommands */,
1E76CBC425152A7F0067298C /* Shared */,
1E068CFB24FD2DAF00A0FFC1 /* AppGroup */,
13B07FAE1A68108700A75B9A /* RocketChatRN */,
@ -1347,10 +1363,12 @@
1ED00BB12513E04400A1331F /* ReplyNotification.swift in Sources */,
1E76CBC2251529560067298C /* Storage.swift in Sources */,
1E76CBD925152C8C0067298C /* Push.swift in Sources */,
1E2511382AC64A5C00EFED30 /* KeyCommandsManager.m in Sources */,
1E0426E6251A5467008F022C /* RoomType.swift in Sources */,
1E76CBCD25152C2C0067298C /* MessageType.swift in Sources */,
1E76CBC925152C1F0067298C /* PushResponse.swift in Sources */,
7A92554628777E0100EC3DA3 /* AppDelegate.mm in Sources */,
1E2511352AC64A2100EFED30 /* KeyCommandsManager.swift in Sources */,
1E76CBD325152C770067298C /* Encryption.swift in Sources */,
1E76CBC825152C070067298C /* RocketChat.swift in Sources */,
1E76CBD725152C840067298C /* HTTPMethod.swift in Sources */,
@ -1428,6 +1446,7 @@
7AAB3E19257E6A6E00707CF6 /* Push.swift in Sources */,
7AAB3E1A257E6A6E00707CF6 /* RoomType.swift in Sources */,
7AAB3E1B257E6A6E00707CF6 /* MessageType.swift in Sources */,
1E51A3D32AC7126D00028137 /* KeyCommandsManager.swift in Sources */,
7AAB3E1C257E6A6E00707CF6 /* PushResponse.swift in Sources */,
7A92554728777E0100EC3DA3 /* AppDelegate.mm in Sources */,
7AAB3E1E257E6A6E00707CF6 /* Encryption.swift in Sources */,
@ -1437,6 +1456,7 @@
7AAB3E23257E6A6E00707CF6 /* Data+Extensions.swift in Sources */,
7AAB3E24257E6A6E00707CF6 /* Date+Extensions.swift in Sources */,
7AAB3E25257E6A6E00707CF6 /* Database.swift in Sources */,
1E51A3D42AC7127000028137 /* KeyCommandsManager.m in Sources */,
7AAB3E26257E6A6E00707CF6 /* String+Extensions.swift in Sources */,
7AAB3E27257E6A6E00707CF6 /* Notification.swift in Sources */,
7AAB3E28257E6A6E00707CF6 /* API.swift in Sources */,
@ -1499,6 +1519,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "";
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_STRICT_PROTOTYPES = NO;
CODE_SIGN_ENTITLEMENTS = RocketChatRN/RocketChatRN.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@ -1555,6 +1576,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "";
CLANG_ENABLE_MODULES = YES;
CLANG_WARN_STRICT_PROTOTYPES = NO;
CODE_SIGN_ENTITLEMENTS = RocketChatRN/RocketChatRN.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
@ -1646,7 +1668,7 @@
"$(inherited)",
"$(SRCROOT)/../node_modules/rn-extensions-share/ios/**",
"$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**",
"$PODS_CONFIGURATION_BUILD_DIR/Firebase",
$PODS_CONFIGURATION_BUILD_DIR/Firebase,
);
INFOPLIST_FILE = ShareRocketChatRN/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
@ -1714,7 +1736,7 @@
"$(inherited)",
"$(SRCROOT)/../node_modules/rn-extensions-share/ios/**",
"$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**",
"$PODS_CONFIGURATION_BUILD_DIR/Firebase",
$PODS_CONFIGURATION_BUILD_DIR/Firebase,
);
INFOPLIST_FILE = ShareRocketChatRN/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;

View File

@ -14,7 +14,7 @@
#import "ExpoModulesCore-Swift.h"
#import "RocketChatRN-Swift.h"
@interface AppDelegate : EXAppDelegateWrapper <UIApplicationDelegate, RCTBridgeDelegate>
@interface AppDelegate : EXAppDelegateWrapper <UIApplicationDelegate, RCTBridgeDelegate, KeyCommandHandler>
@property (nonatomic, strong) UIWindow *window;

View File

@ -62,6 +62,7 @@
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
[RNNotifications startMonitorNotifications];
[KeyCommandsManager setHandler:self];
[ReplyNotification configure];
// AppGroup MMKV
@ -73,6 +74,23 @@
return YES;
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (NSArray<UIKeyCommand *> *)keyCommands {
if ([KeyCommandsManager shared]) {
return [[KeyCommandsManager shared] commands];
}
return NULL;
}
- (void)onKeyCommand:(UIKeyCommand *)keyCommand {
if ([KeyCommandsManager shared]) {
[[KeyCommandsManager shared] onKeyCommand:keyCommand];
}
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG