From 8446d3967cd3c1eda8c364af08a99998e9aa1b20 Mon Sep 17 00:00:00 2001 From: vijay Date: Fri, 8 May 2020 17:08:10 -0700 Subject: [PATCH] feat(ios): move application shortcut under Ti.UI.Shortcut to have parity Fixes TIMOB-26818 --- iphone/Classes/TiUIShortcutItemProxy.h | 32 ++++ iphone/Classes/TiUIShortcutItemProxy.m | 130 ++++++++++++++ iphone/Classes/TiUIShortcutProxy.h | 34 ++++ iphone/Classes/TiUIShortcutProxy.m | 158 ++++++++++++++++++ iphone/Classes/TiUIiOSProxy.m | 1 + iphone/Classes/defines.h | 2 + .../iphone/Titanium.xcodeproj/project.pbxproj | 12 ++ 7 files changed, 369 insertions(+) create mode 100644 iphone/Classes/TiUIShortcutItemProxy.h create mode 100644 iphone/Classes/TiUIShortcutItemProxy.m create mode 100644 iphone/Classes/TiUIShortcutProxy.h create mode 100644 iphone/Classes/TiUIShortcutProxy.m diff --git a/iphone/Classes/TiUIShortcutItemProxy.h b/iphone/Classes/TiUIShortcutItemProxy.h new file mode 100644 index 00000000000..f3a56e91c69 --- /dev/null +++ b/iphone/Classes/TiUIShortcutItemProxy.h @@ -0,0 +1,32 @@ +/** +* Appcelerator Titanium Mobile +* Copyright (c) 2020 by Appcelerator, Inc. All Rights Reserved. +* Licensed under the terms of the Apache Public License +* Please see the LICENSE included with this distribution for details. +*/ +#if defined(USE_TI_UISHORTCUT) || defined(USE_TI_UISHORTCUTITEM) +#import + +NS_ASSUME_NONNULL_BEGIN +@protocol TiUIShortcutItemProxyExports + +READONLY_PROPERTY(NSString *, title, Title); +READONLY_PROPERTY(NSString *, description, Description); +READONLY_PROPERTY(NSDictionary *, data, Data); +READONLY_PROPERTY(id, icon, Icon); +READONLY_PROPERTY(NSString *, id, Id); + +@end + +@interface TiUIShortcutItemProxy : ObjcProxy { + UIApplicationShortcutItem *_shortcutItem; +} + +// Internal use only +- (id)initWithShortcutItem:(UIApplicationShortcutItem *)item; +- (UIApplicationShortcutItem *)shortcutItem; + +@end + +NS_ASSUME_NONNULL_END +#endif diff --git a/iphone/Classes/TiUIShortcutItemProxy.m b/iphone/Classes/TiUIShortcutItemProxy.m new file mode 100644 index 00000000000..8e1af970008 --- /dev/null +++ b/iphone/Classes/TiUIShortcutItemProxy.m @@ -0,0 +1,130 @@ +/** +* Appcelerator Titanium Mobile +* Copyright (c) 2020 by Appcelerator, Inc. All Rights Reserved. +* Licensed under the terms of the Apache Public License +* Please see the LICENSE included with this distribution for details. +*/ +#if defined(USE_TI_UISHORTCUT) || defined(USE_TI_UISHORTCUTITEM) + +#import "TiUIShortcutItemProxy.h" +#import +#import +#ifdef USE_TI_CONTACTS +#import "TiContactsPerson.h" +#import +#endif +@implementation TiUIShortcutItemProxy + +- (NSString *)apiName +{ + return @"Ti.UI.ShortcutItem"; +} + +- (void)dealloc +{ + RELEASE_TO_NIL(_shortcutItem); + + [super dealloc]; +} + +- (id)_initWithPageContext:(id)context_ args:(NSArray *)args +{ + if (self = [self _initWithPageContext:context_]) { + ENSURE_SINGLE_ARG(args, NSDictionary); + if ([args valueForKey:@"id"] == nil) { + NSLog(@"[ERROR] Ti.UI.ShortcutItem: The \"id\" property is required."); + return; + } + + if ([args valueForKey:@"title"] == nil) { + NSLog(@"[ERROR] Ti.UI.ShortcutItem: The \"title\" property is required."); + return; + } + + _shortcutItem = [[UIApplicationShortcutItem alloc] initWithType:[args valueForKey:@"id"] + localizedTitle:[args valueForKey:@"title"] + localizedSubtitle:[args valueForKey:@"description"] + icon:[self findIcon:[args valueForKey:@"icon"]] + userInfo:[args valueForKey:@"data"]]; + } + return self; +} + +- (id)initWithShortcutItem:(UIApplicationShortcutItem *)item +{ + if (self = [super init]) { + _shortcutItem = [item retain]; + } + return self; +} + +- (UIApplicationShortcutIcon *)findIcon:(id)value +{ + if (value == nil) { + return nil; + } + +#ifdef USE_TI_CONTACTS + if ([value isKindOfClass:[TiContactsPerson class]]) { + ENSURE_TYPE(value, TiContactsPerson); + return [UIApplicationShortcutIcon iconWithContact:[(TiContactsPerson *)value nativePerson]]; + } +#endif + + if ([value isKindOfClass:[UIApplicationShortcutIcon class]]) { + return (UIApplicationShortcutIcon *)value; + } + + if ([value isKindOfClass:[NSNumber class]]) { + NSInteger iconIndex = [value integerValue]; + return [UIApplicationShortcutIcon iconWithType:iconIndex]; + } + + if ([value isKindOfClass:[NSString class]]) { + value = ([value hasPrefix:@"/"]) ? [value substringFromIndex:1] : value; + return [UIApplicationShortcutIcon iconWithTemplateImageName:value]; + } + +#if IS_SDK_IOS_13 + if ([value isKindOfClass:[TiBlob class]] && [TiUtils isIOSVersionOrGreater:@"13.0"]) { + TiBlob *blob = (TiBlob *)value; + if (blob.type == TiBlobTypeSystemImage) { + return [UIApplicationShortcutIcon iconWithSystemImageName:blob.systemImageName]; + } + } +#endif + NSLog(@"[ERROR] Ti.UI.ApplicationShortcuts: Invalid icon provided, defaulting to use no icon."); + return nil; +} + +- (UIApplicationShortcutItem *)shortcutItem +{ + return _shortcutItem; +} + +- (NSString *)id +{ + return _shortcutItem.type; +} + +- (NSString *)title +{ + return _shortcutItem.localizedTitle; +} + +- (NSString *)description +{ + return _shortcutItem.localizedSubtitle; +} + +- (NSDictionary *)data +{ + return _shortcutItem.userInfo; +} + +- (id)icon +{ + return _shortcutItem.icon; +} +@end +#endif diff --git a/iphone/Classes/TiUIShortcutProxy.h b/iphone/Classes/TiUIShortcutProxy.h new file mode 100644 index 00000000000..87e28c141ea --- /dev/null +++ b/iphone/Classes/TiUIShortcutProxy.h @@ -0,0 +1,34 @@ +/** +* Appcelerator Titanium Mobile +* Copyright (c) 2020 by Appcelerator, Inc. All Rights Reserved. +* Licensed under the terms of the Apache Public License +* Please see the LICENSE included with this distribution for details. +*/ + +#if defined(USE_TI_UISHORTCUT) || defined(USE_TI_UISHORTCUTITEM) + +#import + +@class TiUIShortcutItemProxy; + +NS_ASSUME_NONNULL_BEGIN + +@protocol TiUIShortcutProxyExports +READONLY_PROPERTY(NSArray *, items, Items); +READONLY_PROPERTY(NSArray *, staticItems, StaticItems); + +- (TiUIShortcutItemProxy *)getById:(NSString *)identifier; + +- (void)remove:(TiUIShortcutItemProxy *)shortcut; + +- (void)removeAll; +- (void)add:(TiUIShortcutItemProxy *)shortcut; + +@end + +@interface TiUIShortcutProxy : ObjcProxy + +@end + +NS_ASSUME_NONNULL_END +#endif diff --git a/iphone/Classes/TiUIShortcutProxy.m b/iphone/Classes/TiUIShortcutProxy.m new file mode 100644 index 00000000000..d110836e2e3 --- /dev/null +++ b/iphone/Classes/TiUIShortcutProxy.m @@ -0,0 +1,158 @@ +/** +* Appcelerator Titanium Mobile +* Copyright (c) 2020 by Appcelerator, Inc. All Rights Reserved. +* Licensed under the terms of the Apache Public License +* Please see the LICENSE included with this distribution for details. +*/ +#if defined(USE_TI_UISHORTCUT) || defined(USE_TI_UISHORTCUTITEM) + +#import "TiUIShortcutProxy.h" +#import "TiUIShortcutItemProxy.h" +#import + +@implementation TiUIShortcutProxy + +- (NSString *)apiName +{ + return @"Ti.UI.Shortcut"; +} + +- (id)init +{ + if (self = [super init]) { + } + return self; +} + +- (void)_destroy +{ + TiThreadPerformOnMainThread( + ^{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + }, + YES); + [super _destroy]; +} + +- (void)_listenerAdded:(NSString *)type count:(int)count +{ + if (count == 1 && [type isEqualToString:@"click"]) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector + (didReceiveApplicationShortcutNotification1:) + name:kTiApplicationShortcut + object:nil]; + [self retain]; + } +} + +- (void)_listenerRemoved:(NSString *)type count:(int)count +{ + if (count == 0 && [type isEqualToString:@"click"]) { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self release]; + } +} + +- (NSArray *)items +{ + NSMutableArray *shortcutsToReturn = [NSMutableArray array]; + NSArray *shortcuts = [UIApplication sharedApplication].shortcutItems; + + for (UIApplicationShortcutItem *item in shortcuts) { + [shortcutsToReturn addObject:[[[TiUIShortcutItemProxy alloc] initWithShortcutItem:item] autorelease]]; + } + + return shortcutsToReturn; +} + +- (NSArray *)staticItems +{ + NSMutableArray *shortcutsToReturn = [NSMutableArray array]; + NSArray *shortcuts = [NSBundle mainBundle].infoDictionary[@"UIApplicationShortcutItems"]; + + if (shortcuts == nil || [shortcuts count] == 0) { + return @[]; + } + + for (id item in shortcuts) { + // We need to map the plist-keys manually for static shortcuts + NSString *type = [item valueForKey:@"UIApplicationShortcutItemType"]; + NSString *title = [item valueForKey:@"UIApplicationShortcutItemTitle"]; + NSString *subtitle = [item valueForKey:@"UIApplicationShortcutItemSubtitle"]; + UIApplicationShortcutIcon *icon = [UIApplicationShortcutIcon iconWithType:[TiUtils intValue:[item valueForKey:@"UIApplicationShortcutItemIconType"]]]; + NSDictionary *userInfo = [item valueForKey:@"UIApplicationShortcutItemUserInfo"]; + + UIApplicationShortcutItem *shortcut = [[[UIApplicationShortcutItem alloc] initWithType:type + localizedTitle:title + localizedSubtitle:subtitle + icon:icon + userInfo:userInfo] autorelease]; + + [shortcutsToReturn addObject:[[[TiUIShortcutItemProxy alloc] initWithShortcutItem:shortcut] autorelease]]; + } + + return shortcutsToReturn; +} + +- (TiUIShortcutItemProxy *)getById:(NSString *)identifier +{ + NSArray *shortcuts = [UIApplication sharedApplication].shortcutItems; + for (UIApplicationShortcutItem *item in shortcuts) { + if ([item.type isEqualToString:[TiUtils stringValue:identifier]]) { + return [[[TiUIShortcutItemProxy alloc] initWithShortcutItem:item] autorelease]; + } + } + + return nil; +} + +- (void)remove:(TiUIShortcutItemProxy *)shortcut +{ + NSString *key = [shortcut shortcutItem].type; + + NSMutableArray *shortcuts = (NSMutableArray *)[UIApplication sharedApplication].shortcutItems; + for (UIApplicationShortcutItem *item in shortcuts) { + if ([item.type isEqualToString:[shortcut shortcutItem].type]) { + [shortcuts removeObject:item]; + break; + } + } + [UIApplication sharedApplication].shortcutItems = shortcuts; +} + +- (void)removeAll +{ + [UIApplication sharedApplication].shortcutItems = nil; +} + +- (void)add:(TiUIShortcutItemProxy *)shortcut +{ + NSMutableArray *shortcuts = (NSMutableArray *)[UIApplication sharedApplication].shortcutItems; + + // Remove previous shortcutitem of same id if exists + __block NSUInteger index = shortcuts.count; + [shortcuts enumerateObjectsUsingBlock:^(UIApplicationShortcutItem *_Nonnull item, NSUInteger idx, BOOL *_Nonnull stop) { + if ([item.type isEqualToString:[shortcut shortcutItem].type]) { + index = idx; + [shortcuts removeObject:item]; + *stop = true; + } + }]; + [shortcuts insertObject:[shortcut shortcutItem] atIndex:index]; + [UIApplication sharedApplication].shortcutItems = shortcuts; +} + +- (void)didReceiveApplicationShortcutNotification1:(NSNotification *)info +{ + if ([self _hasListeners:@"click"]) { + UIApplicationShortcutItem *shortcut = [[[UIApplicationShortcutItem alloc] initWithType:[[info userInfo] valueForKey:@"type"] + localizedTitle:[[info userInfo] valueForKey:@"title"] + localizedSubtitle:[[info userInfo] valueForKey:@"subtitle"] + icon:nil + userInfo:[[info userInfo] objectForKey:@"userInfo"]] autorelease]; + [self fireEvent:@"click" withDict:@{ @"item" : [[[TiUIShortcutItemProxy alloc] initWithShortcutItem:shortcut] autorelease] }]; + } +} +@end +#endif diff --git a/iphone/Classes/TiUIiOSProxy.m b/iphone/Classes/TiUIiOSProxy.m index cdf073de38a..59f86a06aac 100644 --- a/iphone/Classes/TiUIiOSProxy.m +++ b/iphone/Classes/TiUIiOSProxy.m @@ -750,6 +750,7 @@ - (id)createDynamicItemBehavior:(id)args #ifdef USE_TI_UIIOSAPPLICATIONSHORTCUTS - (id)createApplicationShortcuts:(id)args { + DEPRECATED_REPLACED(@"UI.iOS.ApplicationShortcuts", @"9.1.0", @"UI.Shortcut"); return [[[TiUIiOSApplicationShortcutsProxy alloc] _initWithPageContext:[self executionContext] args:args] autorelease]; } #endif diff --git a/iphone/Classes/defines.h b/iphone/Classes/defines.h index 3f62a11308a..a1868cd6597 100644 --- a/iphone/Classes/defines.h +++ b/iphone/Classes/defines.h @@ -118,6 +118,8 @@ #define USE_TI_UIIOSTRANSITIONANIMATION #define USE_TI_UIREFRESHCONTROL #define USE_TI_UIIOSAPPLICATIONSHORTCUTS +#define USE_TI_UISHORTCUT +#define USE_TI_UISHORTCUTITEM #define USE_TI_UIIOSBLURVIEW #define USE_TI_NETWORKREGISTERFORPUSHNOTIFICATIONS diff --git a/iphone/iphone/Titanium.xcodeproj/project.pbxproj b/iphone/iphone/Titanium.xcodeproj/project.pbxproj index 21a75de1512..2e790f63cd7 100644 --- a/iphone/iphone/Titanium.xcodeproj/project.pbxproj +++ b/iphone/iphone/Titanium.xcodeproj/project.pbxproj @@ -209,6 +209,8 @@ 84EB08011A71932D00D35815 /* TiUIiOSSplitWindowProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 84EB08001A71932D00D35815 /* TiUIiOSSplitWindowProxy.m */; }; 84EB08061A71948C00D35815 /* TiUIiOSSplitWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 84EB08051A71948C00D35815 /* TiUIiOSSplitWindow.m */; }; AD3174C21D015DA9000D5F1A /* TiCalendarAttendee.m in Sources */ = {isa = PBXBuildFile; fileRef = AD3174C11D015DA9000D5F1A /* TiCalendarAttendee.m */; }; + B1E5DCF82463401A007817F8 /* TiUIShortcutProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = B1E5DCF72463401A007817F8 /* TiUIShortcutProxy.m */; }; + B1E5DCFC24634057007817F8 /* TiUIShortcutItemProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = B1E5DCFB24634057007817F8 /* TiUIShortcutItemProxy.m */; }; B421C4121113AA9300DBCB42 /* TiUIScrollableViewProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = B421C4111113AA9300DBCB42 /* TiUIScrollableViewProxy.m */; }; B421C4161113AAA900DBCB42 /* TiUIScrollableView.m in Sources */ = {isa = PBXBuildFile; fileRef = B421C4151113AAA900DBCB42 /* TiUIScrollableView.m */; }; B4F97B6F111A41B600E2F72C /* TiUIScrollViewProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = B4F97B6E111A41B600E2F72C /* TiUIScrollViewProxy.m */; }; @@ -695,6 +697,10 @@ 84EB08051A71948C00D35815 /* TiUIiOSSplitWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiUIiOSSplitWindow.m; sourceTree = ""; }; AD3174C01D015DA9000D5F1A /* TiCalendarAttendee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiCalendarAttendee.h; sourceTree = ""; }; AD3174C11D015DA9000D5F1A /* TiCalendarAttendee.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiCalendarAttendee.m; sourceTree = ""; }; + B1E5DCF62463401A007817F8 /* TiUIShortcutProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TiUIShortcutProxy.h; sourceTree = ""; }; + B1E5DCF72463401A007817F8 /* TiUIShortcutProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TiUIShortcutProxy.m; sourceTree = ""; }; + B1E5DCFA24634057007817F8 /* TiUIShortcutItemProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TiUIShortcutItemProxy.h; sourceTree = ""; }; + B1E5DCFB24634057007817F8 /* TiUIShortcutItemProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TiUIShortcutItemProxy.m; sourceTree = ""; }; B421C4101113AA9300DBCB42 /* TiUIScrollableViewProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiUIScrollableViewProxy.h; sourceTree = ""; }; B421C4111113AA9300DBCB42 /* TiUIScrollableViewProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiUIScrollableViewProxy.m; sourceTree = ""; }; B421C4141113AAA900DBCB42 /* TiUIScrollableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiUIScrollableView.h; sourceTree = ""; }; @@ -1990,6 +1996,10 @@ children = ( DBF4B139200FD93400777136 /* TiUIApplicationShortcutsProxy.h */, DBF4B13A200FD93400777136 /* TiUIApplicationShortcutsProxy.m */, + B1E5DCF62463401A007817F8 /* TiUIShortcutProxy.h */, + B1E5DCF72463401A007817F8 /* TiUIShortcutProxy.m */, + B1E5DCFA24634057007817F8 /* TiUIShortcutItemProxy.h */, + B1E5DCFB24634057007817F8 /* TiUIShortcutItemProxy.m */, ); name = "Application Shortcuts"; sourceTree = ""; @@ -2132,6 +2142,7 @@ 24CA897E111161050084E2DE /* PLSqliteDatabase.m in Sources */, 24CA897F111161050084E2DE /* PLSqlitePreparedStatement.m in Sources */, 24CA8980111161050084E2DE /* PLSqliteResultSet.m in Sources */, + B1E5DCFC24634057007817F8 /* TiUIShortcutItemProxy.m in Sources */, CA0D39E81B7F709E009D534C /* TiAppiOSSearchableItemProxy.m in Sources */, 84A0100917FC9C2B00D4BF94 /* TiAnchorAttachBehavior.m in Sources */, B63761701BC5CA4A0070A695 /* TiLayoutView.m in Sources */, @@ -2309,6 +2320,7 @@ 2B94603713F0A2AE000C5BEA /* TiUIiOSCoverFlowViewProxy.m in Sources */, DBF30944210F37080001F770 /* TiWindowProxy+Addons.m in Sources */, 1DCC542F13FF0B0800DF3EE5 /* TIDOMCharacterDataProxy.m in Sources */, + B1E5DCF82463401A007817F8 /* TiUIShortcutProxy.m in Sources */, 1D19459613FF3BC400E2B4D0 /* TIDOMDOMImplementationProxy.m in Sources */, 0BF9338A1CA0948D0091C7EC /* TiUIiOSStepper.m in Sources */, 1D19459B13FF3BE500E2B4D0 /* TIDOMDocumentTypeProxy.m in Sources */,