- Capture Group Commands

- Run commands with NSTask
This commit is contained in:
ZaidElkurdi 2015-04-17 15:41:42 -07:00
parent 611764adf4
commit 6ada354e53
39 changed files with 1052 additions and 11 deletions

View File

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:assistantplus_root_helper.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>EC9F4657-A65C-4A72-975C-EE3D32554A76</string>
<key>IDESourceControlProjectName</key>
<string>assistantplus_root_helper</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>1DDFB15FDAC578A4447EF06D6A0EB8914E453AB8</key>
<string>https://bitbucket.org/ZaidElkurdi/assistantplus.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>assistant+/assistantplus_root_helper/assistantplus_root_helper.xcodeproj</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>1DDFB15FDAC578A4447EF06D6A0EB8914E453AB8</key>
<string>../../../..</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>https://bitbucket.org/ZaidElkurdi/assistantplus.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>1DDFB15FDAC578A4447EF06D6A0EB8914E453AB8</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>1DDFB15FDAC578A4447EF06D6A0EB8914E453AB8</string>
<key>IDESourceControlWCCName</key>
<string>Assistant2</string>
</dict>
</array>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
//
// APCaptureGroupCommand.h
// AssistantPlusApp
//
// Created by Zaid Elkurdi on 4/14/15.
// Copyright (c) 2015 Zaid Elkurdi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface APCaptureGroupCommand : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSArray *variables;
@property (nonatomic, strong) NSArray *conditionals;
@property (nonatomic, strong) NSString *trigger;
@property (nonatomic, strong) NSString *command;
@property (nonatomic, strong) NSString *uuid;
-(id)initWithDictionary:(NSDictionary*)dict;
- (NSDictionary*)dictionaryRepresentation;
@end

View File

@ -0,0 +1,41 @@
//
// APCaptureGroupCommand.m
// AssistantPlusApp
//
// Created by Zaid Elkurdi on 4/14/15.
// Copyright (c) 2015 Zaid Elkurdi. All rights reserved.
//
#import "APCaptureGroupCommand.h"
@implementation APCaptureGroupCommand
-(id)initWithDictionary:(NSDictionary*)dict {
if (self = [super init]) {
NSString *name = dict[@"name"];
NSArray *variables = dict[@"variables"];
NSArray *conditionals = dict[@"conditionals"];
NSString *command = dict[@"command"];
NSString *trigger = dict[@"trigger"];
NSString *uuid = dict[@"uuid"];
self.name = name;
self.variables = variables ? variables : [NSArray array];
self.conditionals = conditionals ? conditionals : [NSArray array];
self.command = command ? command : @"";
self.trigger = trigger ? trigger : @"";
self.uuid = uuid ? uuid : [NSString stringWithFormat:@"%@", [NSUUID UUID]];
}
return self;
}
- (NSDictionary*)dictionaryRepresentation {
return @{@"name" : self.name ? self.name : @"Untitled",
@"variables" : self.variables ? self.variables : [NSArray array],
@"conditionals" : self.conditionals ? self.conditionals : [NSArray array],
@"command" : self.command ? self.command : @"",
@"trigger" : self.trigger ? self.trigger : @"",
@"uuid" : self.uuid ? self.uuid : [NSString stringWithFormat:@"%@", [NSUUID UUID]]};
}
@end

View File

@ -3,7 +3,7 @@
// AssistantPlusApp
//
// Created by Zaid Elkurdi on 3/22/15.
// Copyright (c) 2015 Zaid Elkurdi. All rights reserved.
// Copyright (c) 2015 Zaid Elkurdi. All rights reserve.
//
#import <UIKit/UIKit.h>

View File

@ -20,6 +20,12 @@
B86E67181ACE7AC0007C6014 /* APCustomReply.m in Sources */ = {isa = PBXBuildFile; fileRef = B88C0AE51AC32CEF00D4D107 /* APCustomReply.m */; };
B86E67191ACE7AC0007C6014 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B88C0A871ABF7D6200D4D107 /* main.m */; };
B86E671B1ACE7C66007C6014 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B86E671A1ACE7C66007C6014 /* Default-568h@2x.png */; };
B8B2D2411ADD875900FEE8C3 /* CaptureGroupCommandsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B8B2D2401ADD875900FEE8C3 /* CaptureGroupCommandsViewController.m */; };
B8B2D2471ADD879500FEE8C3 /* APCaptureGroupCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = B8B2D2461ADD879500FEE8C3 /* APCaptureGroupCommand.m */; };
B8B2D24A1ADD87AB00FEE8C3 /* CaptureGroupCommandDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B8B2D2491ADD87AB00FEE8C3 /* CaptureGroupCommandDetailViewController.m */; };
B8B2D24B1ADD8EE900FEE8C3 /* CaptureGroupCommandsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B8B2D2401ADD875900FEE8C3 /* CaptureGroupCommandsViewController.m */; };
B8B2D24C1ADD8EED00FEE8C3 /* CaptureGroupCommandDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B8B2D2491ADD87AB00FEE8C3 /* CaptureGroupCommandDetailViewController.m */; };
B8B2D24D1ADD8EF100FEE8C3 /* APCaptureGroupCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = B8B2D2461ADD879500FEE8C3 /* APCaptureGroupCommand.m */; };
B8EC46D41AC6422100ED3836 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B88C0A7C1ABF79AA00D4D107 /* AppDelegate.m */; };
B8EC46D51AC6422100ED3836 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B88C0A7F1ABF79AA00D4D107 /* MainViewController.m */; };
B8EC46D61AC6422100ED3836 /* ActivatorListenersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B88C0ACD1ABF8F7C00D4D107 /* ActivatorListenersViewController.m */; };
@ -82,6 +88,12 @@
B88C0AE21AC32C2A00D4D107 /* CustomReplyDetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomReplyDetailViewController.m; sourceTree = SOURCE_ROOT; };
B88C0AE41AC32CEF00D4D107 /* APCustomReply.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APCustomReply.h; sourceTree = SOURCE_ROOT; };
B88C0AE51AC32CEF00D4D107 /* APCustomReply.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APCustomReply.m; sourceTree = SOURCE_ROOT; };
B8B2D23F1ADD875900FEE8C3 /* CaptureGroupCommandsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CaptureGroupCommandsViewController.h; sourceTree = SOURCE_ROOT; };
B8B2D2401ADD875900FEE8C3 /* CaptureGroupCommandsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CaptureGroupCommandsViewController.m; sourceTree = SOURCE_ROOT; };
B8B2D2451ADD879500FEE8C3 /* APCaptureGroupCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APCaptureGroupCommand.h; sourceTree = SOURCE_ROOT; };
B8B2D2461ADD879500FEE8C3 /* APCaptureGroupCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APCaptureGroupCommand.m; sourceTree = SOURCE_ROOT; };
B8B2D2481ADD87AB00FEE8C3 /* CaptureGroupCommandDetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CaptureGroupCommandDetailViewController.h; sourceTree = SOURCE_ROOT; };
B8B2D2491ADD87AB00FEE8C3 /* CaptureGroupCommandDetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CaptureGroupCommandDetailViewController.m; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -174,6 +186,10 @@
B88C0A7E1ABF79AA00D4D107 /* MainViewController.h */,
B88C0A7F1ABF79AA00D4D107 /* MainViewController.m */,
B834EFF31AC5EF2C00CF009E /* LaunchScreen2.xib */,
B8B2D23F1ADD875900FEE8C3 /* CaptureGroupCommandsViewController.h */,
B8B2D2401ADD875900FEE8C3 /* CaptureGroupCommandsViewController.m */,
B8B2D2481ADD87AB00FEE8C3 /* CaptureGroupCommandDetailViewController.h */,
B8B2D2491ADD87AB00FEE8C3 /* CaptureGroupCommandDetailViewController.m */,
B86E66D81ACD1991007C6014 /* PluginsViewController.h */,
B86E66D91ACD1991007C6014 /* PluginsViewController.m */,
B88C0ADE1AC32C2000D4D107 /* CustomRepliesViewController.h */,
@ -188,6 +204,8 @@
B88C0AD21ABF968B00D4D107 /* APActivatorListener.m */,
B88C0AE41AC32CEF00D4D107 /* APCustomReply.h */,
B88C0AE51AC32CEF00D4D107 /* APCustomReply.m */,
B8B2D2451ADD879500FEE8C3 /* APCaptureGroupCommand.h */,
B8B2D2461ADD879500FEE8C3 /* APCaptureGroupCommand.m */,
B88C0A871ABF7D6200D4D107 /* main.m */,
B88C0AB61ABF838500D4D107 /* Info.plist */,
B88C0AC11ABF864D00D4D107 /* LaunchScreen.xib */,
@ -353,12 +371,15 @@
buildActionMask = 2147483647;
files = (
B8EC46D41AC6422100ED3836 /* AppDelegate.m in Sources */,
B8B2D2411ADD875900FEE8C3 /* CaptureGroupCommandsViewController.m in Sources */,
B8EC46D51AC6422100ED3836 /* MainViewController.m in Sources */,
B8EC46D61AC6422100ED3836 /* ActivatorListenersViewController.m in Sources */,
B8EC46D71AC6422100ED3836 /* CustomRepliesViewController.m in Sources */,
B8B2D24A1ADD87AB00FEE8C3 /* CaptureGroupCommandDetailViewController.m in Sources */,
B8EC46D81AC6422100ED3836 /* CustomReplyDetailViewController.m in Sources */,
B86E66DA1ACD1991007C6014 /* PluginsViewController.m in Sources */,
B8EC46D91AC6422100ED3836 /* ListenerDetailViewController.m in Sources */,
B8B2D2471ADD879500FEE8C3 /* APCaptureGroupCommand.m in Sources */,
B8EC46DA1AC6422100ED3836 /* APActivatorListener.m in Sources */,
B8EC46DB1AC6422100ED3836 /* APCustomReply.m in Sources */,
B8EC46DC1AC6422100ED3836 /* main.m in Sources */,
@ -378,12 +399,15 @@
buildActionMask = 2147483647;
files = (
B86E67101ACE7AC0007C6014 /* AppDelegate.m in Sources */,
B8B2D24B1ADD8EE900FEE8C3 /* CaptureGroupCommandsViewController.m in Sources */,
B86E67111ACE7AC0007C6014 /* MainViewController.m in Sources */,
B86E67121ACE7AC0007C6014 /* PluginsViewController.m in Sources */,
B86E67131ACE7AC0007C6014 /* CustomRepliesViewController.m in Sources */,
B86E67141ACE7AC0007C6014 /* CustomReplyDetailViewController.m in Sources */,
B8B2D24C1ADD8EED00FEE8C3 /* CaptureGroupCommandDetailViewController.m in Sources */,
B86E67151ACE7AC0007C6014 /* ActivatorListenersViewController.m in Sources */,
B86E67161ACE7AC0007C6014 /* ListenerDetailViewController.m in Sources */,
B8B2D24D1ADD8EF100FEE8C3 /* APCaptureGroupCommand.m in Sources */,
B86E67171ACE7AC0007C6014 /* APActivatorListener.m in Sources */,
B86E67181ACE7AC0007C6014 /* APCustomReply.m in Sources */,
B86E67191ACE7AC0007C6014 /* main.m in Sources */,

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges</key>
<true/>
<key>SnapshotAutomaticallyBeforeSignificantChanges</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,19 @@
//
// CaptureGroupCommandDetailViewController.h
// AssistantPlusApp
//
// Created by Zaid Elkurdi on 4/14/15.
// Copyright (c) 2015 Zaid Elkurdi. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "APCaptureGroupCommand.h"
@protocol CommandDetailDelegate <NSObject>
- (void)commandDidChange:(APCaptureGroupCommand*)command;
@end
@interface CaptureGroupCommandDetailViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UIActionSheetDelegate, UITextFieldDelegate>
@property (assign) id<CommandDetailDelegate> delegate;
- (id)initWithCommand:(APCaptureGroupCommand*)command;
@end

View File

@ -0,0 +1,487 @@
//
// CaptureGroupCommandDetailViewController.m
// AssistantPlusApp
//
// Created by Zaid Elkurdi on 4/14/15.
// Copyright (c) 2015 Zaid Elkurdi. All rights reserved.
//
#import "CaptureGroupCommandDetailViewController.h"
typedef enum {
APNameCell = 1,
APTriggerCell = 2,
APCommandCell = 3
} APTextCellType;
typedef enum {
APWhenValue = 1,
APSetValue = 2,
} APConditionalEditingType;
@interface CaptureGroupCommandDetailViewController ()
@property (strong, nonatomic) APCaptureGroupCommand *currCommand;
@property (strong, nonatomic) UITextField *nameField;
@property (strong, nonatomic) UITextField *triggerField;
@property (strong, nonatomic) UITextField *commandField;
@property (strong, nonatomic) UITableView *tableView;
@property (strong, nonatomic) NSMutableArray *mutableVariables;
@property (strong, nonatomic) NSMutableArray *mutableConditionals;
@property (nonatomic) BOOL didChange;
@property (nonatomic) NSInteger conditionalToEdit;
@property (nonatomic) APConditionalEditingType editingType;
@end
@implementation CaptureGroupCommandDetailViewController
- (id)initWithCommand:(APCaptureGroupCommand*)command {
if (self = [super init]) {
self.currCommand = command;
self.mutableVariables = command.variables ? [command.variables mutableCopy] : [NSMutableArray array];
if (command.conditionals && command.conditionals.count > 0) {
self.mutableConditionals = [[NSMutableArray alloc] init];
for (NSArray *currConditional in command.conditionals) {
[self.mutableConditionals addObject:[currConditional mutableCopy]];
}
} else {
self.mutableConditionals = [NSMutableArray array];
}
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
UIColor *backgroundColor = [UIColor colorWithWhite:.9f alpha:1.0];
self.view.backgroundColor = backgroundColor;
self.tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStyleGrouped];
self.tableView.dataSource = self;
self.tableView.delegate = self;
CGFloat expectedHeight = [[self getHelpMessage] boundingRectWithSize:CGSizeMake(self.view.frame.size.width-20, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName : [UIFont fontWithName:@"Helvetica" size:14]}
context:nil].size.height;
UIView *msgView = [[UIView alloc] initWithFrame:CGRectMake(0, 10, self.view.frame.size.width, expectedHeight+30)];
UILabel *msgLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 20, self.view.frame.size.width-20, expectedHeight)];
msgLabel.lineBreakMode = NSLineBreakByWordWrapping;
msgLabel.numberOfLines = 0;
msgLabel.text = [self getHelpMessage];
msgLabel.textAlignment = NSTextAlignmentLeft;
msgLabel.font = [UIFont fontWithName:@"Helvetica" size:14];
msgLabel.textColor = [UIColor darkGrayColor];
[msgView addSubview:msgLabel];
self.tableView.tableFooterView = msgView;
[self.view addSubview:self.tableView];
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addPressed:)];
[self.navigationItem setRightBarButtonItem:addButton];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(saveChangesIfNecessary)
name:UIApplicationWillResignActiveNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self saveChangesIfNecessary];
}
- (void)saveChangesIfNecessary {
if (self.didChange) {
self.currCommand.conditionals = self.mutableConditionals;
self.currCommand.trigger = self.triggerField.text;
self.currCommand.variables = self.mutableVariables;
self.currCommand.name = self.nameField.text;
self.currCommand.command = self.commandField.text;
[self.delegate commandDidChange:self.currCommand];
}
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 5;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return 1;
} else if (section == 1) {
return 1;
} else if (section == 2) {
return self.mutableVariables.count;
} else if (section == 3) {
return self.mutableConditionals.count;
} else {
return 1;
}
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
return [self createTextCell:APNameCell];
} else if (indexPath.section == 1) {
return [self createTextCell:APTriggerCell];
} else if (indexPath.section == 2) {
return [self createVariableCellForIndex:indexPath.row];
} else if (indexPath.section == 3) {
return [self createConditionalCellForIndex:indexPath.row];
} else if (indexPath.section == 4) {
return [self createTextCell:APCommandCell];
}
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 3) {
return 200;
}
return 50;
}
- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
switch (section) {
case 0:
return @"";
break;
case 1:
return @"";
case 2:
return @"Variables";
case 3:
return @"Conditionals";
case 4:
return @"Command";
default:
return @"";
}
}
#pragma mark - Cell Helpers
- (UITableViewCell*)createTextCell:(APTextCellType)cellType {
UITableViewCell *cell = [[UITableViewCell alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, 60, 50)];
UITextField *nameField = [[UITextField alloc] initWithFrame:CGRectMake(80, 2, self.view.frame.size.width-60, 50)];
nameField.delegate = self;
nameField.tag = -1;
nameField.returnKeyType = UIReturnKeyDone;
if (cellType == APNameCell) {
nameLabel.text = @"Name:";
nameField.text = self.currCommand.name;
self.nameField = nameField;
CGRect oldFrame = self.nameField.frame;
oldFrame.origin.x = 70;
oldFrame.size.width = self.view.frame.size.width - 70;
nameField.frame = oldFrame;
self.nameField.frame = oldFrame;
} else if (cellType == APTriggerCell) {
nameLabel.text = @"Trigger:";
nameField.text = self.currCommand.trigger;
self.triggerField = nameField;
} else if (cellType == APCommandCell) {
nameLabel.hidden = YES;
nameField.text = self.currCommand.command;
self.commandField = nameField;
CGRect oldFrame = self.commandField.frame;
oldFrame.origin.x = 5;
oldFrame.size.width = self.view.frame.size.width - 5;
self.commandField.frame = oldFrame;
}
[cell.contentView addSubview:nameLabel];
[cell.contentView addSubview:nameField];
return cell;
}
- (UITableViewCell*)createVariableCellForIndex:(NSInteger)index {
UITableViewCell *cell = [[UITableViewCell alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UITextField *nameField = [[UITextField alloc] initWithFrame:CGRectMake(10, 2, self.view.frame.size.width-10, 50)];
nameField.delegate = self;
nameField.tag = 100+index;
nameField.returnKeyType = UIReturnKeyDone;
nameField.placeholder = @"Unnamed Variable";
NSString *variableName = [self.mutableVariables objectAtIndex:index];
if (variableName.length > 0) {
nameField.text = variableName;
} else {
nameField.text = @"";
}
[cell.contentView addSubview:nameField];
return cell;
}
- (UITableViewCell*)createConditionalCellForIndex:(NSInteger)index {
UITableViewCell *cell = [[UITableViewCell alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UILabel *whenlabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, 70, 50)];
whenlabel.text = @"When:";
UILabel *equalsLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 50, 70, 50)];
equalsLabel.text = @"Equals:";
UILabel *setLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 100, 70, 50)];
setLabel.text = @"Set:";
UILabel *toLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 150, 70, 50)];
toLabel.text = @"To:";
UIButton *whenField = [UIButton buttonWithType:UIButtonTypeCustom];
whenField.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
whenField.frame = CGRectMake(70, 2, self.view.frame.size.width-15, 50);
whenField.tag = index;
[whenField addTarget:self action:@selector(whenButtonPressedForIndex:) forControlEvents:UIControlEventTouchUpInside];
NSString *whenVariableName = self.mutableConditionals[index][0];
if (whenVariableName && whenVariableName.length > 0) {
[whenField setTitle:whenVariableName forState:UIControlStateNormal];
[whenField setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
} else {
[whenField setTitle:@"Select Variable..." forState:UIControlStateNormal];
[whenField setTitleColor:[UIColor colorWithWhite:0.7 alpha:1.0] forState:UIControlStateNormal];
}
UITextField *equalsField = [[UITextField alloc] initWithFrame:CGRectMake(80, 57, self.view.frame.size.width-80, 35)];
equalsField.returnKeyType = UIReturnKeyDone;
equalsField.font = [UIFont systemFontOfSize:17];
equalsField.tag = 1000 + index;
equalsField.placeholder = @"A Value";
NSString *equalsValue = self.mutableConditionals[index][1];
if (equalsValue.length > 0) {
equalsField.text = equalsValue;
} else {
equalsField.text = @"";
}
equalsField.delegate = self;
UIButton *setField = [UIButton buttonWithType:UIButtonTypeCustom];
setField.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
setField.frame = CGRectMake(50, 100, self.view.frame.size.width-75, 50);
setField.tag = index;
[setField addTarget:self action:@selector(setButtonPressedForIndex:) forControlEvents:UIControlEventTouchUpInside];
NSString *setVariableName = self.mutableConditionals[index][2];
if (setVariableName && setVariableName.length > 0) {
[setField setTitle:setVariableName forState:UIControlStateNormal];
[setField setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
} else {
[setField setTitle:@"Select Variable..." forState:UIControlStateNormal];
[setField setTitleColor:[UIColor colorWithWhite:0.7 alpha:1.0] forState:UIControlStateNormal];
}
UITextField *toField = [[UITextField alloc] initWithFrame:CGRectMake(40, 158, self.view.frame.size.width-80, 35)];
toField.returnKeyType = UIReturnKeyDone;
toField.tag = 2000 + index;
toField.font = [UIFont systemFontOfSize:17];
toField.placeholder = @"A Value";
NSString *toValue = self.mutableConditionals[index][3];
if (toValue.length > 0) {
toField.text = toValue;
} else {
toField.text = @"";
}
toField.delegate = self;
[cell.contentView addSubview:whenlabel];
[cell.contentView addSubview:equalsLabel];
[cell.contentView addSubview:setLabel];
[cell.contentView addSubview:toLabel];
[cell.contentView addSubview:equalsField];
[cell.contentView addSubview:toField];
[cell.contentView addSubview:whenField];
[cell.contentView addSubview:setField];
return cell;
}
#pragma mark - UITableViewDelegate
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 || indexPath.section == 1 || indexPath.section == 4) {
return NO;
}
return YES;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleDelete;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
if (indexPath.section == 2) {
[self.mutableVariables removeObjectAtIndex:indexPath.row];
} else if (indexPath.section == 3) {
[self.mutableConditionals removeObjectAtIndex:indexPath.row];
}
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
self.didChange = YES;
}
}
#pragma mark - UI Delegates
- (void)addPressed:(id)sender {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Add new..." delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:nil, nil];
[actionSheet addButtonWithTitle:@"Variable"];
[actionSheet addButtonWithTitle:@"Conditional"];
actionSheet.cancelButtonIndex = 0;
actionSheet.tag = 1;
[actionSheet showInView:self.view];
}
- (void)whenButtonPressedForIndex:(UIButton*)button {
self.conditionalToEdit = button.tag;
self.editingType = APWhenValue;
[self displayVariableSelection];
}
- (void)setButtonPressedForIndex:(UIButton*)button {
self.conditionalToEdit = button.tag;
self.editingType = APSetValue;
[self displayVariableSelection];
}
- (void)displayVariableSelection {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Select Variable..." delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:nil, nil];
for (NSString *name in self.mutableVariables) {
if (name.length > 0) {
[actionSheet addButtonWithTitle:name];
}
}
actionSheet.tag = 2;
actionSheet.cancelButtonIndex = 0;
[actionSheet showInView:self.view];
}
- (void)addOptionsSheetClickedButtonAtIndex:(NSInteger)buttonIndex {
NSInteger section;
NSInteger row;
if (buttonIndex == 1) {
//variable
section = 2;
[self.mutableVariables addObject:@""];
row = self.mutableVariables.count-1;
} else if (buttonIndex == 2) {
//conditional
section = 3;
[self.mutableConditionals addObject:[NSMutableArray arrayWithObjects:@"", @"", @"", @"", nil]];
row = self.mutableConditionals.count-1;
} else {
//Is cancel button
return;
}
NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:row inSection:section];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}
- (void)variableSelectionSheetClickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *variableName = [self.mutableVariables objectAtIndex:buttonIndex-1];
if (self.editingType == APSetValue) {
[[self.mutableConditionals objectAtIndex:self.conditionalToEdit] setObject:variableName atIndexedSubscript:2];
} else if (self.editingType == APWhenValue) {
[[self.mutableConditionals objectAtIndex:self.conditionalToEdit] setObject:variableName atIndexedSubscript:0];
}
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForItem:self.conditionalToEdit inSection:3]] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
return;
}
if (actionSheet.tag == 1) {
[self addOptionsSheetClickedButtonAtIndex:buttonIndex];
} else if (actionSheet.tag == 2) {
[self variableSelectionSheetClickedButtonAtIndex:buttonIndex];
}
[self.view endEditing:YES];
self.didChange = YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if (textField == self.commandField) {
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:4] atScrollPosition:UITableViewScrollPositionTop animated:YES];
} else if (textField == self.nameField) {
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
} else if (textField == self.triggerField) {
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
return YES;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
self.didChange = YES;
NSString *newText = [textField.text stringByReplacingCharactersInRange:range withString:string];
if (textField.tag - 2000 >= 0) {
[[self.mutableConditionals objectAtIndex:textField.tag-2000] setObject:newText atIndexedSubscript:3];
} else if (textField.tag - 1000 >= 0) {
[[self.mutableConditionals objectAtIndex:textField.tag-1000] setObject:newText atIndexedSubscript:1];
} else if (textField.tag - 100 >= 0) {
[self.mutableVariables setObject:newText atIndexedSubscript:textField.tag-100];
} else if (textField == self.nameField) {
self.currCommand.name = newText;
} else if (textField == self.triggerField) {
self.currCommand.trigger = newText;
}
return YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - Helpers
- (NSString*)getHelpMessage {
return @"Enabled: For a listener to appear in Activator it must be enabled\n"
"\nPassthrough: If enabled, Assistant+ will continue searching for another Activator listener, custom reply, or plugin to handle the command. If it doesn't find anything to handle the command, Siri will go to its default action. You can add a voice confirmation for your Activator listener if you create a custom reply for the same trigger and then enable passthrough for your listener\n"
"\nName: A name to describe your listener. This can be anything and is purely for informational purposes\n"
"\nTrigger: The command that will trigger the Activator listener, you must have at least one for the listener to appear in Activator. You may use wildcards in the trigger by using (.*). For example, '(.*)turn on the lights' will trigger on \"Turn on the lights\", \"Siri turn on the lights\", \"Hey Siri please turn on the lights\", etc.\n"
"\nOnce you create an Activator listener here you must go to Activator and assign it to an event.";
}
@end

View File

@ -0,0 +1,14 @@
//
// CaptureGroupCommandsViewController.h
// AssistantPlusApp
//
// Created by Zaid Elkurdi on 4/14/15.
// Copyright (c) 2015 Zaid Elkurdi. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "CaptureGroupCommandDetailViewController.h"
@interface CaptureGroupCommandsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, CommandDetailDelegate>
@end

View File

@ -0,0 +1,168 @@
//
// CaptureGroupCommandsViewController.m
// AssistantPlusApp
//
// Created by Zaid Elkurdi on 4/14/15.
// Copyright (c) 2015 Zaid Elkurdi. All rights reserved.
//
#import "CaptureGroupCommandsViewController.h"
#import "APCaptureGroupCommand.h"
#import "CPDistributedMessagingCenter.h"
@interface CaptureGroupCommandsViewController ()
@property (strong, nonatomic) UITableView *commandsTable;
@end
@implementation CaptureGroupCommandsViewController {
NSMutableArray *savedCommands;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Commands";
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addNewCommand:)];
[self.navigationItem setRightBarButtonItem:addButton];
self.commandsTable = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
self.commandsTable.delegate = self;
self.commandsTable.dataSource = self;
self.commandsTable.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
UIColor *backgroundColor = [UIColor colorWithWhite:.9f alpha:1.0];
self.commandsTable.backgroundColor = backgroundColor;
[self.view addSubview:self.commandsTable];
[self loadCommandsFromFile];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if ([self.commandsTable indexPathForSelectedRow]) {
[self.commandsTable deselectRowAtIndexPath:[self.commandsTable indexPathForSelectedRow] animated:YES];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)loadCommandsFromFile {
savedCommands = [[NSMutableArray alloc] init];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:@"captureGroupCommands"]) {
NSArray *commands = [defaults objectForKey:@"captureGroupCommands"];
for (NSDictionary *currCommand in commands) {
APCaptureGroupCommand *command = [[APCaptureGroupCommand alloc] initWithDictionary:currCommand];
[savedCommands addObject:command];
}
}
}
- (void)saveCommandsToFile {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *toSave = [[NSMutableArray alloc] init];
if (savedCommands) {
for (APCaptureGroupCommand *currCommand in savedCommands) {
[toSave addObject:[currCommand dictionaryRepresentation]];
}
[defaults setObject:toSave forKey:@"captureGroupCommands"];
[defaults synchronize];
}
#if !(TARGET_IPHONE_SIMULATOR)
NSLog(@"Sending back to springobard!");
CPDistributedMessagingCenter* center = [CPDistributedMessagingCenter centerNamed:@"com.zaid.applus.springboard"];
[center sendMessageName:@"UpdateCaptureGroupCommands" userInfo:@{@"captureGroupCommands" : toSave}];
#endif
}
#pragma mark - Button Handlers
- (void)addNewCommand:(id)sender {
APCaptureGroupCommand *newCommand = [[APCaptureGroupCommand alloc] init];
[savedCommands addObject:newCommand];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:savedCommands.count-1 inSection:0];
[CATransaction begin];
[self.commandsTable beginUpdates];
[CATransaction setCompletionBlock: ^{
[self tableView:self.commandsTable didSelectRowAtIndexPath:newIndexPath];
}];
[self.commandsTable insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.commandsTable endUpdates];
[CATransaction commit];
}
#pragma mark - UITableViewDataSource
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"commandCell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"commandCell"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
APCaptureGroupCommand *currCommand = [savedCommands objectAtIndex:indexPath.row];
cell.textLabel.text = currCommand.name.length > 0 ? currCommand.name : @"Untitled Command";
cell.detailTextLabel.text = currCommand.trigger.length > 0 ? currCommand.trigger : @"No Trigger Yet";
return cell;
}
#pragma mark - UITableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
APCaptureGroupCommand *selectedCommand = [savedCommands objectAtIndex:indexPath.row];
CaptureGroupCommandDetailViewController *detailVC = [[CaptureGroupCommandDetailViewController alloc] initWithCommand:selectedCommand];
detailVC.delegate = self;
[self.navigationController pushViewController:detailVC animated:YES];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return savedCommands.count;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
APCaptureGroupCommand *toDelete = [savedCommands objectAtIndex:indexPath.row];
[savedCommands removeObject:toDelete];
[self saveCommandsToFile];
[self.commandsTable beginUpdates];
[self.commandsTable deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.commandsTable endUpdates];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 60;
}
#pragma mark - CommandDelegate
- (void)commandDidChange:(APCaptureGroupCommand *)command{
for (NSInteger currIndex = 0; currIndex < savedCommands.count; currIndex++) {
APCaptureGroupCommand *currCommand = [savedCommands objectAtIndex:currIndex];
if ([currCommand.uuid isEqualToString:command.uuid]) {
NSLog(@"Replacing %@", currCommand);
[savedCommands replaceObjectAtIndex:currIndex withObject:currCommand];
break;
}
}
[self saveCommandsToFile];
[self.commandsTable reloadData];
}
@end

View File

@ -3,6 +3,7 @@
#import "CustomRepliesViewController.h"
#import "CPDistributedMessagingCenter.h"
#import "PluginsViewController.h"
#import "CaptureGroupCommandsViewController.h"
@implementation MainViewController
@ -54,6 +55,9 @@
cellTitle = @"Custom Replies";
break;
case 2:
cellTitle = @"Capture Group Commands";
break;
case 3:
cellTitle = @"Installed Plugins";
default:
break;
@ -64,7 +68,7 @@
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
return 4;
}
- (CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section {
@ -97,7 +101,10 @@
case 1:
[self goToNewVC:[[CustomRepliesViewController alloc] init]];
break;
case 2: {
case 2:
[self goToNewVC:[[CaptureGroupCommandsViewController alloc] init]];
break;
case 3: {
#if !(TARGET_IPHONE_SIMULATOR)
CPDistributedMessagingCenter *center = [CPDistributedMessagingCenter centerNamed:@"com.zaid.applus.springboard"];
NSDictionary *installed = [center sendMessageAndReceiveReplyName:@"getInstalledPlugins" userInfo:nil];

View File

@ -5,7 +5,7 @@ export TARGET = iphone:clang:latest:8.0
export SDKVERSION=8.1
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
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
AssistantPlusApp_FRAMEWORKS = UIKit CoreGraphics QuartzCore
AssistantPlusApp_PRIVATE_FRAMEWORKS = AppSupport
AssistantPlusApp_CFLAGS = -fobjc-arc

View File

@ -0,0 +1,21 @@
//
// APCaptureGroupCommand.h
// AssistantPlusApp
//
// Created by Zaid Elkurdi on 4/14/15.
// Copyright (c) 2015 Zaid Elkurdi. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface APCaptureGroupCommand : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSArray *variables;
@property (nonatomic, strong) NSArray *conditionals;
@property (nonatomic, strong) NSRegularExpression *trigger;
@property (nonatomic, strong) NSString *command;
@property (nonatomic, strong) NSString *uuid;
-(id)initWithDictionary:(NSDictionary*)dict;
-(NSString*)buildCommandWithValues:(NSArray*)values;
@end

View File

@ -0,0 +1,108 @@
//
// APCaptureGroupCommand.m
// AssistantPlusApp
//
// Created by Zaid Elkurdi on 4/14/15.
// Copyright (c) 2015 Zaid Elkurdi. All rights reserved.
//
#import "APCaptureGroupCommand.h"
@implementation APCaptureGroupCommand {
NSArray *variableRanges;
}
-(id)initWithDictionary:(NSDictionary*)dict {
if (self = [super init]) {
NSString *name = dict[@"name"];
NSArray *variables = dict[@"variables"];
NSArray *conditionals = dict[@"conditionals"];
NSString *command = dict[@"command"];
NSString *trigger = dict[@"trigger"];
NSString *uuid = dict[@"uuid"];
self.name = name;
self.variables = variables ? variables : [NSArray array];
self.conditionals = conditionals ? conditionals : [NSArray array];
self.command = command ? command : @"";
self.trigger = [NSRegularExpression regularExpressionWithPattern:trigger options:NSRegularExpressionCaseInsensitive error:nil];
self.uuid = uuid ? uuid : [NSString stringWithFormat:@"%@", [NSUUID UUID]];
[self buildRangeDictionary];
}
return self;
}
- (void)buildRangeDictionary {
NSMutableArray *newVariableRanges = [[NSMutableArray alloc] init];
for (NSString *currVariable in self.variables) {
NSRange currRange = [self.command rangeOfString:[NSString stringWithFormat:@"[%@]", currVariable]];
if (currRange.location != NSNotFound) {
[newVariableRanges addObject:@[currVariable, [NSValue valueWithRange:currRange]]];
}
}
//Sort the variables by location in order to calculate offset easily
variableRanges = [newVariableRanges sortedArrayUsingComparator:^NSComparisonResult(NSArray *first, NSArray *second) {
NSRange firstRange = [first[1] rangeValue];
NSRange secondRange = [second[1] rangeValue];
return firstRange.location > secondRange.location;
}];
}
-(NSString*)buildCommandWithValues:(NSArray*)values {
//First, map the captured values to their variable names
NSMutableDictionary *variablesToValues = [[NSMutableDictionary alloc] init];
NSInteger currIndex = 0;
NSLog(@"Values: %@", values);
for (NSString *currValue in values) {
NSLog(@"On: %@", currValue);
if (currIndex < self.variables.count) {
NSLog(@"Adding: %@", currValue);
NSString *currVariable = self.variables[currIndex];
NSLog(@"Assigning to %@", currVariable);
variablesToValues[currVariable] = currValue;
}
currIndex++;
}
//Second, check the conditionals to see
for (NSArray *currRule in self.conditionals) {
NSString *conditionalVariable = currRule[0];
NSString *conditionalValue = currRule[1];
NSString *targetVariable = currRule[2];
NSString *targetValue = currRule[3];
if (!conditionalVariable || !targetVariable || !conditionalValue || !targetValue) {
continue;
}
NSString *actualValue = variablesToValues[conditionalVariable];
if (actualValue) {
if ([actualValue compare:conditionalValue options:NSCaseInsensitiveSearch] == NSOrderedSame) {
variablesToValues[targetVariable] = targetValue;
}
}
}
NSLog(@"Var to Val: %@", variablesToValues);
NSMutableString *mutableCommand = [self.command mutableCopy];
NSInteger offset = 0;
for (NSArray *currVariablePair in variableRanges) {
NSString *currVariable = currVariablePair[0];
NSString *currValue = variablesToValues[currVariable];
NSLog(@"Currently on %@ %@", currVariable, currValue);
if (!currVariable || !currValue) {
continue;
}
NSRange rangeToReplace = [currVariablePair[1] rangeValue];
rangeToReplace.location += offset;
[mutableCommand replaceCharactersInRange:rangeToReplace withString:currValue];
offset += currValue.length - rangeToReplace.length;
}
return mutableCommand;
}
@end

View File

@ -13,6 +13,7 @@
@interface APPluginSystem : NSObject<APPluginSystem, LAEventDataSource> {
NSMutableArray *plugins;
NSMutableArray *activatorListenersArray;
NSMutableArray *captureGroupCommandsArray;
}
@property (strong, nonatomic) APSession *currSession;
@ -26,5 +27,8 @@
//1.0.1
- (void)siriSay:(NSString*)message;
//1.0.2
- (void)reloadCaptureGroupCommands:(NSDictionary*)commands;
- (NSDictionary*)getInstalledPlugins;
@end

View File

@ -9,6 +9,8 @@
#import "APPluginSystem.h"
#import "APPlugin.h"
#import "APActivatorListener.h"
#import "APCaptureGroupCommand.h"
#import "CPDistributedMessagingCenter.h"
static NSString *PREFERENCE_PATH = @"/var/mobile/Library/Preferences/com.assistantplus.app.plist";
static NSString *EVENT_PREFIX = @"APListener";
@ -28,6 +30,7 @@ static NSString *EVENT_PREFIX = @"APListener";
NSDictionary *pref = [NSDictionary dictionaryWithContentsOfFile:PREFERENCE_PATH];
[sharedManager reloadActivatorListeners:pref];
[sharedManager reloadCaptureGroupCommands:pref];
});
return sharedManager;
}
@ -58,9 +61,12 @@ static NSString *EVENT_PREFIX = @"APListener";
- (BOOL)handleCommand:(NSString*)command withTokens:(NSSet*)tokens withSession:(APSession*)currSession {
self.currSession = currSession;
//First check activator listeners
//Clean up the command
NSString *userCommand = [command lowercaseString];
userCommand = [userCommand stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
//First 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])];
@ -77,6 +83,27 @@ static NSString *EVENT_PREFIX = @"APListener";
}
}
//Then check Capture Group Commands
for (APCaptureGroupCommand *currCommand in captureGroupCommandsArray) {
NSRegularExpression *currExpression = currCommand.trigger;
NSArray *arrayOfAllMatches = [currExpression matchesInString:userCommand options:0 range:NSMakeRange(0, [userCommand length])];
for (NSTextCheckingResult *match in arrayOfAllMatches) {
if (match.numberOfRanges > 0) {
NSMutableArray *variableMatches = [[NSMutableArray alloc] init];
for (NSInteger currIndex = 1; currIndex < match.numberOfRanges; currIndex++) {
NSString *variableValue = [[userCommand substringWithRange:[match rangeAtIndex:currIndex]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSLog(@"Match %ld: %@", (long)currIndex, variableValue);
[variableMatches addObject:variableValue];
}
NSString *commandToExecute = [currCommand buildCommandWithValues:variableMatches];
CPDistributedMessagingCenter* center = [CPDistributedMessagingCenter centerNamed:@"com.zaid.applus.springboard"];
[center sendMessageName:@"runCommand" userInfo:@{@"command" : commandToExecute}];
return YES;
}
}
}
//Go through the plugins
NSLog(@"AP: Got Command \"%@\"", userCommand);
for (APPlugin *currPlugin in plugins) {
if ([currPlugin handleSpeech:userCommand withTokens:tokens withSession:currSession]) {
@ -108,6 +135,22 @@ static NSString *EVENT_PREFIX = @"APListener";
}
}
- (void)reloadCaptureGroupCommands:(NSDictionary*)commands {
NSLog(@"Loading capture group commands!");
captureGroupCommandsArray = [[NSMutableArray alloc] init];
if ([commands objectForKey:@"captureGroupCommands"]) {
for (NSDictionary *currCommand in [commands objectForKey:@"captureGroupCommands"]) {
id triggerValue = currCommand[@"trigger"];
id commandValue = currCommand[@"command"];
if (triggerValue && commandValue) {
APCaptureGroupCommand *command = [[APCaptureGroupCommand alloc] initWithDictionary:currCommand];
[captureGroupCommandsArray addObject:command];
}
}
}
}
- (void)siriSay:(NSString*)message {
[self.currSession sendTextSnippet:message temporary:NO scrollToTop:YES dialogPhase:@"Completion"];
}

View File

@ -18,4 +18,5 @@
- (void)getCurrentLocationWithCompletion:(void (^)(NSDictionary *info))completion;
- (void)loadPlugins;
- (void)gotCurrentLocation:(NSString*)msg withInfo:(NSDictionary*)info;
- (void)runCommand:(NSString*)msg withInfo:(NSDictionary*)info;
@end

View File

@ -16,6 +16,12 @@
- (void)_relaunchSpringBoardNow;
@end
@interface NSTask : NSObject
- (void)setLaunchPath:(NSString*)path;
- (void)setArguments:(NSArray*)args;
- (void)launch;
@end
@implementation APSpringboardUtils {
APPluginSystem *pluginManager;
@ -33,9 +39,11 @@
[center registerForMessageName:@"RetrievedLocation" target:sharedObj selector:@selector(gotCurrentLocation:withInfo:)];
[center registerForMessageName:@"UpdateActivatorListeners" target:sharedObj selector:@selector(updateActivatorListeners:withListeners:)];
[center registerForMessageName:@"UpdateCustomReplies" target:sharedObj selector:@selector(updateCustomReplies:withReplies:)];
[center registerForMessageName:@"UpdateCaptureGroupCommands" target:sharedObj selector:@selector(updateCaptureGroupCommands:withCommands:)];
[center registerForMessageName:@"respringForListeners" target:sharedObj selector:@selector(respring)];
[center registerForMessageName:@"getInstalledPlugins" target:sharedObj selector:@selector(getInstalledPlugins:withInfo:)];
[center registerForMessageName:@"siriSay" target:sharedObj selector:@selector(siriSay:withMessage:)];
[center registerForMessageName:@"runCommand" target:sharedObj selector:@selector(runCommand:withInfo:)];
}
}
return sharedObj;
@ -54,6 +62,10 @@
[pluginManager reloadActivatorListeners:listeners];
}
- (void)updateCaptureGroupCommands:(NSString*)msg withCommands:(NSDictionary*)commands {
[pluginManager reloadCaptureGroupCommands:commands];
}
- (void)updateCustomReplies:(NSString*)msg withReplies:(NSDictionary*)dict {
[pluginManager reloadCustomRepliesPlugin:dict];
}
@ -92,6 +104,15 @@
[self stopLocationDaemon];
}
- (void)runCommand:(NSString*)msg withInfo:(NSDictionary*)info {
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/sh"];
NSArray *arguments = @[@"-c",
info[@"command"]];
[task setArguments:arguments];
[task launch];
}
- (void)startLocationDaemon {
system("/Applications/AssistantPlusApp.app/assistantplus_root_helper start");
}

View File

@ -24,6 +24,7 @@
@protocol APSharedUtils <NSObject>
+ (id)sharedAPUtils;
- (void)getCurrentLocationWithCompletion:(void (^)(NSDictionary *info))completion;
- (void)runCommand:(NSString*)msg withInfo:(NSDictionary*)info;
@end
@protocol APPluginSystem <NSObject>

View File

@ -5,7 +5,7 @@ export TARGET_IPHONEOS_DEPLOYMENT_VERSION = 8.0
TWEAK_NAME = AssistantPlusPluginManager
AssistantPlusPluginManager_CFLAGS = -fobjc-arc
AssistantPlusPluginManager_FILES = Tweak.xm APPluginSystem.m APPlugin.m APSpringboardUtils.m APActivatorListener.m
AssistantPlusPluginManager_FILES = Tweak.xm APPluginSystem.m APPlugin.m APSpringboardUtils.m APActivatorListener.m APCaptureGroupCommand.m
AssistantPlusPluginManager_PRIVATE_FRAMEWORKS = AssistantServices SAObjects AppSupport
AssistantPlusPluginManager_FRAMEWORKS = Foundation UIKit CoreLocation
AssistantPlusPluginManager_LIBRARIES = substrate activator

View File

@ -13,6 +13,12 @@
<FileRef
location = "container:APPlugin.m">
</FileRef>
<FileRef
location = "group:APCaptureGroupCommand.h">
</FileRef>
<FileRef
location = "group:APCaptureGroupCommand.m">
</FileRef>
<FileRef
location = "container:APPluginSystem.h">
</FileRef>

Binary file not shown.

View File

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

View File

@ -6,5 +6,5 @@ Description: Control Spotify using Siri! Currently spotifySiriControls supports
Maintainer: Zaid Elkurdi
Author: Zaid Elkurdi
Section: Tweaks
Version: 1.0.0-13
Installed-Size: 616
Version: 1.0.0-27
Installed-Size: 888