This commit is contained in:
ZaidElkurdi 2015-07-12 23:04:12 -07:00
parent 1f95829caa
commit 61013b77a1
30 changed files with 117 additions and 42 deletions

View File

@ -22,9 +22,17 @@ static BOOL defaultHandling = YES;
static AFConnection *currConnection;
static APPluginSystem *pluginManager;
static BOOL hasLoadedSnippets = NO;
static APSession *previousSession;
BOOL shouldHandleRequest(NSString *text, APSession *currSession) {
pluginManager = [[%c(APSpringboardUtils) sharedAPUtils] getPluginManager];
if (previousSession && [previousSession isListeningAfterSpeaking]) {
NSLog(@"AP: Using previous session");
currSession = previousSession;
} else {
NSLog(@"AP: Creating new session");
previousSession = currSession;
}
NSArray *lowerCaseArr = [[text componentsSeparatedByString: @" "] valueForKey:@"lowercaseString"];
NSSet *tokens = [NSSet setWithArray:lowerCaseArr];
BOOL pluginWillHandle = [pluginManager handleCommand:text withTokens:tokens withSession:currSession];
@ -133,6 +141,14 @@ BOOL shouldHandleRequest(NSString *text, APSession *currSession) {
}
}
- (void)endSession {
if (pluginManager) {
[pluginManager assistantWasDismissed];
}
previousSession = nil;
%orig;
}
%end
%hook AFConnectionClientServiceDelegate
@ -151,7 +167,6 @@ BOOL shouldHandleRequest(NSString *text, APSession *currSession) {
}
NSLog(@"AP Starting Speech Query: %@", phraseBuilder);
AFConnection *connection = MSHookIvar<AFConnection*>(self, "_connection");
APSession *currSession = [APSession sessionWithConnection:connection];
if (shouldHandleRequest(phraseBuilder, currSession)) {

View File

@ -1,9 +1,9 @@
include theos/makefiles/common.mk
export ARCHS = armv7 armv7s arm64
export TARGET = iphone:clang:latest:8.0
export TARGET_IPHONEOS_DEPLOYMENT_VERSION = 8.0
export SDKVERSION=8.1
export TARGET = iphone:clang:latest:8.4
export TARGET_IPHONEOS_DEPLOYMENT_VERSION = 8.4
export SDKVERSION=8.4
TWEAK_NAME = Assistant+

Binary file not shown.

View File

@ -1,8 +1,8 @@
include theos/makefiles/common.mk
export ARCHS = armv7 arm64
export TARGET = iphone:clang:latest:8.0
export SDKVERSION=8.1
export TARGET = iphone:clang:latest:8.4
export SDKVERSION=8.4
APPLICATION_NAME = AssistantPlusApp
AssistantPlusApp_FILES = main.m AppDelegate.m MainViewController.m APActivatorListener.m ActivatorListenersViewController.m ListenerDetailViewController.m CustomReplyDetailViewController.m CustomRepliesViewController.m APCustomReply.m PluginsViewController.m CaptureGroupCommandDetailViewController.m CaptureGroupCommandsViewController.m APCaptureGroupCommand.m

View File

@ -28,6 +28,7 @@
- (id)initWithFilePath:(NSURL*)filePath andName:(NSString*)name;
- (BOOL)handleSpeech:(NSString*)text withTokens:(NSSet*)tokens withSession:(id<APSiriSession>)session;
- (void)handleReply:(NSString*)text withTokens:(NSSet*)tokens withSession:(id<APSiriSession>)session;
/// Register a command class
-(BOOL)registerCommand:(Class)cls;
/// Register a snippet class
@ -36,4 +37,6 @@
- (NSSet*)getRegisteredSnippets;
- (NSArray*)getRegisteredCommands;
- (void)assistantWasDismissed;
@end

View File

@ -92,6 +92,24 @@
return NO;
}
- (void)handleReply:(NSString*)text withTokens:(NSSet*)tokens withSession:(id<APSiriSession>)session {
for (NSObject<APPluginCommand>* cmd in commands) {
if ([cmd respondsToSelector:@selector(handleReply:withTokens:withSession:)]) {
[cmd handleReply:text withTokens:tokens withSession:session];
}
}
}
#pragma mark - Notifications
- (void)assistantWasDismissed {
for (NSObject<APPluginCommand>* cmd in commands) {
if ([cmd respondsToSelector:@selector(assistantWasDismissed)]) {
[cmd assistantWasDismissed];
}
}
}
#pragma mark - Snippet Presentation
-(NSObject<APPluginSnippet>*)allocSnippet:(NSString*)snippetClass properties:(NSDictionary *)props {
@ -154,5 +172,4 @@
return YES;
}
@end

View File

@ -16,13 +16,14 @@
NSMutableArray *captureGroupCommandsArray;
}
@property (strong, nonatomic) APSession *currSession;
@property (strong, nonatomic) APSession *currentSession;
+ (id)sharedManager;
- (BOOL)loadPlugins;
- (BOOL)handleCommand:(NSString*)command withTokens:(NSSet*)tokens withSession:(APSession*)currSession;
- (void)reloadCustomRepliesPlugin:(NSDictionary*)replies;
- (void)reloadActivatorListeners:(NSDictionary*)listeners;
- (void)assistantWasDismissed;
//1.0.1
- (void)siriSay:(NSString*)message;

View File

@ -60,13 +60,24 @@ static NSString *EVENT_PREFIX = @"APListener";
}
- (BOOL)handleCommand:(NSString*)command withTokens:(NSSet*)tokens withSession:(APSession*)currSession {
self.currSession = currSession;
self.currentSession = currSession;
//Clean up the command
NSString *userCommand = [command lowercaseString];
userCommand = [userCommand stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
//First check activator listeners
//First, check if a plugin is listening
if ([currSession isListeningAfterSpeaking] && currSession.currentPlugin) {
NSLog(@"AP: Resuming session");
if ([currSession.currentPlugin respondsToSelector:@selector(handleReply:withTokens:withSession:)]) {
[currSession.currentPlugin handleReply:userCommand withTokens:tokens withSession:currSession];
return YES;
} else {
currSession.currentPlugin = nil;
currSession.listenAfterSpeaking = NO;
}
}
//Then check activator listeners
for (APActivatorListener *currListener in activatorListenersArray) {
for (NSRegularExpression *currExpression in currListener.triggers) {
NSArray *arrayOfAllMatches = [currExpression matchesInString:userCommand options:0 range:NSMakeRange(0, [userCommand length])];
@ -107,12 +118,20 @@ static NSString *EVENT_PREFIX = @"APListener";
NSLog(@"AP: Got Command \"%@\"", userCommand);
for (APPlugin *currPlugin in plugins) {
if ([currPlugin handleSpeech:userCommand withTokens:tokens withSession:currSession]) {
currSession.currentPlugin = currPlugin;
return YES;
}
}
return NO;
}
- (void)assistantWasDismissed {
for (APPlugin *currPlugin in plugins) {
if ([currPlugin respondsToSelector:@selector(assistantWasDismissed)]) {
[currPlugin assistantWasDismissed];
}
}
}
#pragma mark - Message Handlers
- (NSDictionary*)getInstalledPlugins {
@ -152,7 +171,7 @@ static NSString *EVENT_PREFIX = @"APListener";
}
- (void)siriSay:(NSString*)message {
[self.currSession sendTextSnippet:message temporary:NO scrollToTop:YES dialogPhase:@"Completion"];
[self.currentSession sendTextSnippet:message temporary:NO scrollToTop:YES dialogPhase:@"Completion"];
}
#pragma mark - Activator Methods

View File

@ -10,8 +10,12 @@
#import "AssistantHeaders.h"
#import <CoreLocation/CoreLocation.h>
@class APPlugin;
@interface APSession : NSObject <APSiriSession, CLLocationManagerDelegate>
@property (nonatomic, strong) NSString *refId;
@property (nonatomic, getter=isListeningAfterSpeaking) BOOL listenAfterSpeaking;
@property (nonatomic, strong) APPlugin *currentPlugin;
@property (nonatomic, strong) AFConnection *connection;
@property (nonatomic, copy) void (^completionHandler)(NSDictionary *locationData);
@ -19,13 +23,18 @@
+(APSession*)sessionWithConnection:(AFConnection*)connection;
- (void)sendTextSnippet:(NSString*)text temporary:(BOOL)temporary scrollToTop:(BOOL)toTop dialogPhase:(NSString*)phase;
- (void)sendTextSnippet:(NSString*)text temporary:(BOOL)temporary scrollToTop:(BOOL)toTop dialogPhase:(NSString*)phase listenAfterSpeaking:(BOOL)shouldListen;
-(SOObject*)createTextSnippet:(NSString*)text;
- (void)sendAddViews:(NSArray*)views;
- (void)sendAddViews:(NSArray*)views dialogPhase:(NSString*)dialogPhase scrollToTop:(BOOL)toTop temporary:(BOOL)temporary;
-(SOObject*)createSnippet:(NSString*)snippetClass properties:(NSDictionary*)props;
- (void)sendCustomSnippet:(NSString*)snippetClass withProperties:(NSDictionary*)props;
- (void)sendRequestCompleted;
-(SOObject*)createSnippet:(NSString*)snippetClass properties:(NSDictionary*)props;
-(SOObject*)createAssistantUtteranceView:(NSString*)text;
- (void)sendRequestCompleted;
- (void)getCurrentLocationWithCompletion:(void (^)(NSDictionary *info))completion;
+(NSString*)generateRandomUUID;

View File

@ -21,6 +21,7 @@ static NSMutableDictionary *sessionDict;
self.refId = [referenceId copy];
if (!self.refId) self.refId = [@"00000000-0000-0000-0000-000000000000" copy];
self.connection = connection;
self.listenAfterSpeaking = NO;
}
return self;
}
@ -40,6 +41,10 @@ static NSMutableDictionary *sessionDict;
return currSession;
}
- (BOOL)isListeningAfterSpeaking {
return _listenAfterSpeaking;
}
#pragma mark - Public Methods
-(SOObject*)createTextSnippet:(NSString*)text {
@ -47,8 +52,12 @@ static NSMutableDictionary *sessionDict;
}
- (void)sendTextSnippet:(NSString*)text temporary:(BOOL)temporary scrollToTop:(BOOL)toTop dialogPhase:(NSString*)phase {
[self sendTextSnippet:text temporary:temporary scrollToTop:toTop dialogPhase:phase listenAfterSpeaking:NO];
}
- (void)sendTextSnippet:(NSString*)text temporary:(BOOL)temporary scrollToTop:(BOOL)toTop dialogPhase:(NSString*)phase listenAfterSpeaking:(BOOL)listen {
NSMutableArray* views = [NSMutableArray arrayWithCapacity:1];
[views addObject:[self createAssistantUtteranceView:text]];
[views addObject:[self createAssistantUtteranceView:text speakableText:text identifier:@"Misc" listenAfterSpeaking:listen]];
[self sendAddViews:views dialogPhase:phase scrollToTop:toTop temporary:temporary];
}
@ -57,6 +66,7 @@ static NSMutableDictionary *sessionDict;
}
- (void)sendRequestCompleted {
self.listenAfterSpeaking = NO;
NSMutableDictionary* dict = [self createAceRequestCompleted];
[self sendCommandToConnection:dict];
[sessionDict removeObjectForKey:self.refId];
@ -68,25 +78,21 @@ static NSMutableDictionary *sessionDict;
}
- (void)sendAddViews:(NSArray*)views {
return [self sendAddViews:views dialogPhase:@"Completion" scrollToTop:NO temporary:NO];
[self sendAddViews:views dialogPhase:@"Completion" scrollToTop:NO temporary:NO];
}
- (void)sendAddViews:(NSArray*)views dialogPhase:(NSString*)dialogPhase scrollToTop:(BOOL)toTop temporary:(BOOL)temporary {
self.listenAfterSpeaking = NO;
for (NSDictionary *currView in views) {
if ([currView[@"listenAfterSpeaking"] boolValue]) {
dialogPhase = @"Clarification";
self.listenAfterSpeaking = YES;
}
}
NSMutableDictionary* dict = [self createAceAddViews:views forPhase:dialogPhase scrollToTop:toTop temporary:temporary];
// listenAfterSpeaking hack!
// for (NSDictionary* view in views)
// {
// NSDictionary* props = [view objectForKey:@"properties"];
// if ([[props objectForKey:@"listenAfterSpeaking"] boolValue])
// {
// _listenAfterSpeaking = YES;
// break;
// }
// }
// send
[self sendCommandToConnection:dict];
}
#pragma mark - APLocationDaemon Communication
- (void)handleMessage:(NSString*)name withInfo:(NSDictionary*)locationData {
@ -135,7 +141,7 @@ static NSMutableDictionary *sessionDict;
// call the original method to handle our new object
if (self.connection == nil) { NSLog(@"AP: AFConnection is nil"); return; }
if ([dict[@"$class"] isEqualToString:@"CommandSucceeded"]) {
[self.connection sendReplyCommand:obj];
} else {
@ -171,7 +177,7 @@ static NSMutableDictionary *sessionDict;
if (properties != nil) {
//Only necessary for AceObjects
[objDict setObject:@"4.0" forKey:@"$v"];
[objDict setObject:@"4.3" forKey:@"$v"];
for (NSString *currKey in properties.allKeys) {
[objDict setObject:properties[currKey] forKey:currKey];
@ -213,22 +219,19 @@ static NSMutableDictionary *sessionDict;
return [self createAceObjectDictForGroup:@"com.apple.ace.assistant" class:@"AddViews" properties:props];
}
//NSMutableDictionary* SOCreateAceAddViewsUtteranceView(NSString* refId, NSString* text, NSString* speakableText, NSString* dialogPhase, BOOL scrollToTop, BOOL temporary) {
// NSMutableArray* views = [NSMutableArray arrayWithCapacity:1];
// [views addObject:[self createAssistantUtteranceView:text speakableText:speakableText identifier:@"Misc#ident"]];
//
// return [self createAceAddViews:views forPhase:dialogPhase scrollToTop:scrollToTop temporary:temporary];
//}
#pragma mark - AssistantUtteranceView Creation
-(NSMutableDictionary*)createAssistantUtteranceView:(NSString*)text speakableText:(NSString*)speakableText identifier:(NSString*)dialogIdentifier {
-(NSMutableDictionary*)createAssistantUtteranceView:(NSString*)text speakableText:(NSString*)speakableText identifier:(NSString*)dialogIdentifier listenAfterSpeaking:(BOOL)listen {
if (speakableText == nil) speakableText = text;
NSMutableDictionary* props = [NSMutableDictionary dictionaryWithObjectsAndKeys:
text,@"text", speakableText,@"speakableText", dialogIdentifier,@"dialogIdentifier", nil];
text,@"text", speakableText,@"speakableText", dialogIdentifier,@"dialogIdentifier", @(listen), @"listenAfterSpeaking", nil];
return [self createObjectDictForGroup:@"com.apple.ace.assistant" class:@"AssistantUtteranceView" properties:props];
}
-(NSMutableDictionary*)createAssistantUtteranceView:(NSString*)text speakableText:(NSString*)speakableText identifier:(NSString*)dialogIdentifier {
return [self createAssistantUtteranceView:text speakableText:speakableText identifier:dialogIdentifier listenAfterSpeaking:NO];
}
-(SOObject*)createAssistantUtteranceView:(NSString*)text {
return [self createAssistantUtteranceView:text speakableText:text identifier:@"Misc#Ident"];
}

View File

@ -12,6 +12,7 @@
@protocol APSiriSession <NSObject>
- (void)sendTextSnippet:(NSString*)text temporary:(BOOL)temporary scrollToTop:(BOOL)toTop dialogPhase:(NSString*)phase;
- (void)sendTextSnippet:(NSString*)text temporary:(BOOL)temporary scrollToTop:(BOOL)toTop dialogPhase:(NSString*)phase listenAfterSpeaking:(BOOL)listen;
- (void)sendAddViews:(NSArray*)views;
- (void)sendAddViews:(NSArray*)views dialogPhase:(NSString*)dialogPhase scrollToTop:(BOOL)toTop temporary:(BOOL)temporary;
-(NSMutableDictionary*)createSnippet:(NSString*)snippetClass properties:(NSDictionary*)props;
@ -32,6 +33,7 @@
+(id)sharedManager;
- (void)reloadCustomRepliesPlugin:(NSDictionary*)replies;
- (void)reloadActivatorListeners:(NSDictionary*)listeners;
- (void)assistantWasDismissed;
@end
@protocol APPluginManager <NSObject>
@ -55,9 +57,13 @@
@protocol APPluginCommand <NSObject>
@optional
-(BOOL)handleSpeech:(NSString*)text withTokens:(NSSet*)tokens withSession:(id<APSiriSession>)session;
-(void)handleReply:(NSString*)text withTokens:(NSSet*)tokens withSession:(id<APSiriSession>)session;
-(void)assistantWasDismissed;
@end
@protocol APPlugin <NSObject>
@required
-(id)initWithPluginManager:(id<APPluginManager>)system;
@optional
- (void)assistantWasDismissed;
@end

View File

@ -19,6 +19,8 @@
dialogPhase: Possible values are Completion, Reflection, Summary, Error, Clarification, and Acknowledgement */
- (void)sendTextSnippet:(NSString*)text temporary:(BOOL)temporary scrollToTop:(BOOL)toTop dialogPhase:(NSString*)phase;
- (void)sendTextSnippet:(NSString*)text temporary:(BOOL)temporary scrollToTop:(BOOL)toTop dialogPhase:(NSString*)phase listenAfterSpeaking:(BOOL)shouldListen;
/* Create an editable dictionary representing a text snippet. In order to send this
to the user you must add it to an NSArray and use sendAddviews: */
-(NSMutableDictionary*)createTextSnippet:(NSString*)text;

View File

@ -1,8 +1,8 @@
include theos/makefiles/common.mk
export ARCHS = armv7 arm64
export TARGET = iphone:clang:latest:8.0
export SDKVERSION=8.1
export TARGET = iphone:clang:latest:8.4
export SDKVERSION=8.4
BUNDLE_NAME = customreply
customreply_BUNDLE_EXTENSION = assistantPlugin

Binary file not shown.

Binary file not shown.