Support UserNotifications framework (#3040)
This commit is contained in:
parent
19bc15523f
commit
b612020576
|
@ -399,6 +399,7 @@
|
|||
C809AEE7291ECFD000BFDBE1 /* NSDataAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = C809AEE6291ECFD000BFDBE1 /* NSDataAdditions.mm */; };
|
||||
C841A28129197724009F18E8 /* NSKeyedUnarchiverAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = C841A28029197724009F18E8 /* NSKeyedUnarchiverAdditions.mm */; };
|
||||
C86BCD9928228A9600F45599 /* SparkleProxy.mm in Sources */ = {isa = PBXBuildFile; fileRef = C86BCD9828228A9600F45599 /* SparkleProxy.mm */; };
|
||||
C87369652809984200573C90 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C87369642809984200573C90 /* UserNotifications.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
C88771AD2803EE7B005C7523 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C88771A92803EE42005C7523 /* libz.tbd */; };
|
||||
C88771AE2803EE7C005C7523 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C88771A92803EE42005C7523 /* libz.tbd */; };
|
||||
C88771AF2803EE7D005C7523 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C88771A92803EE42005C7523 /* libz.tbd */; };
|
||||
|
@ -1183,6 +1184,7 @@
|
|||
C841A27F29197724009F18E8 /* NSKeyedUnarchiverAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSKeyedUnarchiverAdditions.h; sourceTree = "<group>"; };
|
||||
C841A28029197724009F18E8 /* NSKeyedUnarchiverAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = NSKeyedUnarchiverAdditions.mm; sourceTree = "<group>"; };
|
||||
C86BCD9828228A9600F45599 /* SparkleProxy.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SparkleProxy.mm; sourceTree = "<group>"; };
|
||||
C87369642809984200573C90 /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
|
||||
C88771A92803EE42005C7523 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
C88771AB2803EE53005C7523 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
|
||||
C887BEC02807FCE900867D3C /* create.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = create.cc; sourceTree = "<group>"; };
|
||||
|
@ -1239,6 +1241,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C87369652809984200573C90 /* UserNotifications.framework in Frameworks */,
|
||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
|
||||
4D3EA0AA08AE13C600EA10C2 /* IOKit.framework in Frameworks */,
|
||||
4D1838DD09DEC0E80047D688 /* libtransmission.a in Frameworks */,
|
||||
|
@ -1873,6 +1876,7 @@
|
|||
A2F35BBA15C5A0A100EBF632 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C87369642809984200573C90 /* UserNotifications.framework */,
|
||||
55869925257074EC00F77A43 /* libcurl.tbd */,
|
||||
C88771AB2803EE53005C7523 /* libiconv.tbd */,
|
||||
C88771A92803EE42005C7523 /* libz.tbd */,
|
||||
|
|
|
@ -444,6 +444,7 @@ target_link_libraries(${TR_NAME}-mac
|
|||
"-framework IOKit"
|
||||
"-framework Quartz"
|
||||
"-framework Security"
|
||||
"-weak_framework UserNotifications"
|
||||
)
|
||||
|
||||
if(NOT CMAKE_GENERATOR STREQUAL Xcode)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
@import IOKit;
|
||||
@import IOKit.pwr_mgt;
|
||||
@import Carbon;
|
||||
@import UserNotifications;
|
||||
|
||||
@import Sparkle;
|
||||
|
||||
|
@ -232,7 +233,7 @@ static void removeKeRangerRansomware()
|
|||
NSLog(@"OSX.KeRanger.A ransomware removal completed, proceeding to normal operation");
|
||||
}
|
||||
|
||||
@interface Controller ()
|
||||
@interface Controller ()<UNUserNotificationCenterDelegate>
|
||||
|
||||
@property(nonatomic) IBOutlet NSWindow* fWindow;
|
||||
@property(nonatomic) IBOutlet NSStackView* fStackView;
|
||||
|
@ -782,8 +783,6 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool
|
|||
|
||||
self.fBadger = [[Badger alloc] initWithLib:self.fLib];
|
||||
|
||||
NSUserNotificationCenter.defaultUserNotificationCenter.delegate = self;
|
||||
|
||||
//observe notifications
|
||||
NSNotificationCenter* nc = NSNotificationCenter.defaultCenter;
|
||||
|
||||
|
@ -842,6 +841,35 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool
|
|||
}
|
||||
}
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification*)notification
|
||||
{
|
||||
// user notifications
|
||||
if (@available(macOS 10.14, *))
|
||||
{
|
||||
UNUserNotificationCenter.currentNotificationCenter.delegate = self;
|
||||
UNNotificationAction* actionShow = [UNNotificationAction actionWithIdentifier:@"actionShow"
|
||||
title:NSLocalizedString(@"Show", "notification button")
|
||||
options:UNNotificationActionOptionForeground];
|
||||
UNNotificationCategory* categoryShow = [UNNotificationCategory categoryWithIdentifier:@"categoryShow" actions:@[ actionShow ]
|
||||
intentIdentifiers:@[]
|
||||
options:UNNotificationCategoryOptionNone];
|
||||
[UNUserNotificationCenter.currentNotificationCenter setNotificationCategories:[NSSet setWithObject:categoryShow]];
|
||||
[UNUserNotificationCenter.currentNotificationCenter
|
||||
requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge)
|
||||
completionHandler:^(BOOL granted, NSError* _Nullable error) {
|
||||
if (error.code > 0)
|
||||
{
|
||||
NSLog(@"UserNotifications not configured: %@", error.localizedDescription);
|
||||
}
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback on earlier versions
|
||||
NSUserNotificationCenter.defaultUserNotificationCenter.delegate = self;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification*)notification
|
||||
{
|
||||
NSApp.servicesProvider = self;
|
||||
|
@ -2338,11 +2366,37 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool
|
|||
self.fTotalTorrentsField.stringValue = totalTorrentsString;
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
|
||||
willPresentNotification:(UNNotification*)notification
|
||||
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler API_AVAILABLE(macos(10.14))
|
||||
{
|
||||
completionHandler(-1);
|
||||
}
|
||||
|
||||
- (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center shouldPresentNotification:(NSUserNotification*)notification
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(UNUserNotificationCenter*)center
|
||||
didReceiveNotificationResponse:(UNNotificationResponse*)response
|
||||
withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(macos(10.14))
|
||||
{
|
||||
if (!response.notification.request.content.userInfo.count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier])
|
||||
{
|
||||
[self didActivateNotificationByDefaultActionWithUserInfo:response.notification.request.content.userInfo];
|
||||
}
|
||||
else if ([response.actionIdentifier isEqualToString:@"actionShow"])
|
||||
{
|
||||
[self didActivateNotificationByActionShowWithUserInfo:response.notification.request.content.userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)userNotificationCenter:(NSUserNotificationCenter*)center didActivateNotification:(NSUserNotification*)notification
|
||||
{
|
||||
if (!notification.userInfo)
|
||||
|
@ -2352,29 +2406,67 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool
|
|||
|
||||
if (notification.activationType == NSUserNotificationActivationTypeActionButtonClicked) //reveal
|
||||
{
|
||||
Torrent* torrent = [self torrentForHash:notification.userInfo[@"Hash"]];
|
||||
NSString* location = torrent.dataLocation;
|
||||
if (!location)
|
||||
{
|
||||
location = notification.userInfo[@"Location"];
|
||||
}
|
||||
if (location)
|
||||
{
|
||||
[NSWorkspace.sharedWorkspace activateFileViewerSelectingURLs:@[ [NSURL fileURLWithPath:location] ]];
|
||||
}
|
||||
[self didActivateNotificationByActionShowWithUserInfo:notification.userInfo];
|
||||
}
|
||||
else if (notification.activationType == NSUserNotificationActivationTypeContentsClicked)
|
||||
{
|
||||
Torrent* torrent = [self torrentForHash:notification.userInfo[@"Hash"]];
|
||||
if (!torrent)
|
||||
[self didActivateNotificationByDefaultActionWithUserInfo:notification.userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didActivateNotificationByActionShowWithUserInfo:(NSDictionary<NSString*, id>*)userInfo
|
||||
{
|
||||
Torrent* torrent = [self torrentForHash:userInfo[@"Hash"]];
|
||||
NSString* location = torrent.dataLocation;
|
||||
if (!location)
|
||||
{
|
||||
location = userInfo[@"Location"];
|
||||
}
|
||||
if (location)
|
||||
{
|
||||
[NSWorkspace.sharedWorkspace activateFileViewerSelectingURLs:@[ [NSURL fileURLWithPath:location] ]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didActivateNotificationByDefaultActionWithUserInfo:(NSDictionary<NSString*, id>*)userInfo
|
||||
{
|
||||
Torrent* torrent = [self torrentForHash:userInfo[@"Hash"]];
|
||||
if (!torrent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//select in the table - first see if it's already shown
|
||||
NSInteger row = [self.fTableView rowForItem:torrent];
|
||||
if (row == -1)
|
||||
{
|
||||
//if it's not shown, see if it's in a collapsed row
|
||||
if ([self.fDefaults boolForKey:@"SortByGroup"])
|
||||
{
|
||||
return;
|
||||
__block TorrentGroup* parent = nil;
|
||||
[self.fDisplayedTorrents enumerateObjectsWithOptions:NSEnumerationConcurrent
|
||||
usingBlock:^(TorrentGroup* group, NSUInteger idx, BOOL* stop) {
|
||||
if ([group.torrents containsObject:torrent])
|
||||
{
|
||||
parent = group;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
if (parent)
|
||||
{
|
||||
[[self.fTableView animator] expandItem:parent];
|
||||
row = [self.fTableView rowForItem:torrent];
|
||||
}
|
||||
}
|
||||
//select in the table - first see if it's already shown
|
||||
NSInteger row = [self.fTableView rowForItem:torrent];
|
||||
|
||||
if (row == -1)
|
||||
{
|
||||
//if it's not shown, see if it's in a collapsed row
|
||||
//not found - must be filtering
|
||||
NSAssert([self.fDefaults boolForKey:@"FilterBar"], @"expected the filter to be enabled");
|
||||
[self.fFilterBar reset:YES];
|
||||
|
||||
row = [self.fTableView rowForItem:torrent];
|
||||
|
||||
//if it's not shown, it has to be in a collapsed row...again
|
||||
if ([self.fDefaults boolForKey:@"SortByGroup"])
|
||||
{
|
||||
__block TorrentGroup* parent = nil;
|
||||
|
@ -2392,41 +2484,13 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool
|
|||
row = [self.fTableView rowForItem:torrent];
|
||||
}
|
||||
}
|
||||
|
||||
if (row == -1)
|
||||
{
|
||||
//not found - must be filtering
|
||||
NSAssert([self.fDefaults boolForKey:@"FilterBar"], @"expected the filter to be enabled");
|
||||
[self.fFilterBar reset:YES];
|
||||
|
||||
row = [self.fTableView rowForItem:torrent];
|
||||
|
||||
//if it's not shown, it has to be in a collapsed row...again
|
||||
if ([self.fDefaults boolForKey:@"SortByGroup"])
|
||||
{
|
||||
__block TorrentGroup* parent = nil;
|
||||
[self.fDisplayedTorrents enumerateObjectsWithOptions:NSEnumerationConcurrent
|
||||
usingBlock:^(TorrentGroup* group, NSUInteger idx, BOOL* stop) {
|
||||
if ([group.torrents containsObject:torrent])
|
||||
{
|
||||
parent = group;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
if (parent)
|
||||
{
|
||||
[[self.fTableView animator] expandItem:parent];
|
||||
row = [self.fTableView rowForItem:torrent];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSAssert1(row != -1, @"expected a row to be found for torrent %@", torrent);
|
||||
|
||||
[self showMainWindow:nil];
|
||||
[self.fTableView selectAndScrollToRow:row];
|
||||
}
|
||||
|
||||
NSAssert1(row != -1, @"expected a row to be found for torrent %@", torrent);
|
||||
|
||||
[self showMainWindow:nil];
|
||||
[self.fTableView selectAndScrollToRow:row];
|
||||
}
|
||||
|
||||
- (Torrent*)torrentForHash:(NSString*)hash
|
||||
|
@ -2461,24 +2525,39 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool
|
|||
}
|
||||
}
|
||||
|
||||
NSString* title = NSLocalizedString(@"Download Complete", "notification title");
|
||||
NSString* body = torrent.name;
|
||||
NSString* location = torrent.dataLocation;
|
||||
|
||||
NSString* notificationTitle = NSLocalizedString(@"Download Complete", "notification title");
|
||||
NSUserNotification* notification = [[NSUserNotification alloc] init];
|
||||
notification.title = notificationTitle;
|
||||
notification.informativeText = torrent.name;
|
||||
|
||||
notification.hasActionButton = YES;
|
||||
notification.actionButtonTitle = NSLocalizedString(@"Show", "notification button");
|
||||
|
||||
NSMutableDictionary* userInfo = [NSMutableDictionary dictionaryWithObject:torrent.hashString forKey:@"Hash"];
|
||||
if (location)
|
||||
{
|
||||
userInfo[@"Location"] = location;
|
||||
}
|
||||
notification.userInfo = userInfo;
|
||||
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
||||
if (@available(macOS 10.14, *))
|
||||
{
|
||||
NSString* identifier = [@"Download Complete " stringByAppendingString:torrent.hashString];
|
||||
UNMutableNotificationContent* content = [UNMutableNotificationContent new];
|
||||
content.title = title;
|
||||
content.body = body;
|
||||
content.categoryIdentifier = @"categoryShow";
|
||||
content.userInfo = userInfo;
|
||||
|
||||
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:nil];
|
||||
[UNUserNotificationCenter.currentNotificationCenter addNotificationRequest:request withCompletionHandler:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback on earlier versions
|
||||
NSUserNotification* notification = [[NSUserNotification alloc] init];
|
||||
notification.title = title;
|
||||
notification.informativeText = body;
|
||||
notification.hasActionButton = YES;
|
||||
notification.actionButtonTitle = NSLocalizedString(@"Show", "notification button");
|
||||
notification.userInfo = userInfo;
|
||||
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
||||
}
|
||||
|
||||
if (!self.fWindow.mainWindow)
|
||||
{
|
||||
|
@ -2513,24 +2592,39 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool
|
|||
}
|
||||
}
|
||||
|
||||
NSString* title = NSLocalizedString(@"Seeding Complete", "notification title");
|
||||
NSString* body = torrent.name;
|
||||
NSString* location = torrent.dataLocation;
|
||||
|
||||
NSString* notificationTitle = NSLocalizedString(@"Seeding Complete", "notification title");
|
||||
NSUserNotification* userNotification = [[NSUserNotification alloc] init];
|
||||
userNotification.title = notificationTitle;
|
||||
userNotification.informativeText = torrent.name;
|
||||
|
||||
userNotification.hasActionButton = YES;
|
||||
userNotification.actionButtonTitle = NSLocalizedString(@"Show", "notification button");
|
||||
|
||||
NSMutableDictionary* userInfo = [NSMutableDictionary dictionaryWithObject:torrent.hashString forKey:@"Hash"];
|
||||
if (location)
|
||||
{
|
||||
userInfo[@"Location"] = location;
|
||||
}
|
||||
userNotification.userInfo = userInfo;
|
||||
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:userNotification];
|
||||
if (@available(macOS 10.14, *))
|
||||
{
|
||||
NSString* identifier = [@"Seeding Complete " stringByAppendingString:torrent.hashString];
|
||||
UNMutableNotificationContent* content = [UNMutableNotificationContent new];
|
||||
content.title = title;
|
||||
content.body = body;
|
||||
content.categoryIdentifier = @"categoryShow";
|
||||
content.userInfo = userInfo;
|
||||
|
||||
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:nil];
|
||||
[UNUserNotificationCenter.currentNotificationCenter addNotificationRequest:request withCompletionHandler:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback on earlier versions
|
||||
NSUserNotification* userNotification = [[NSUserNotification alloc] init];
|
||||
userNotification.title = title;
|
||||
userNotification.informativeText = body;
|
||||
userNotification.hasActionButton = YES;
|
||||
userNotification.actionButtonTitle = NSLocalizedString(@"Show", "notification button");
|
||||
userNotification.userInfo = userInfo;
|
||||
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:userNotification];
|
||||
}
|
||||
|
||||
//removing from the list calls fullUpdateUI
|
||||
if (torrent.removeWhenFinishSeeding)
|
||||
|
@ -3364,13 +3458,30 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool
|
|||
|
||||
if (![dict[@"ByUser"] boolValue])
|
||||
{
|
||||
NSUserNotification* notification = [[NSUserNotification alloc] init];
|
||||
notification.title = isLimited ? NSLocalizedString(@"Speed Limit Auto Enabled", "notification title") :
|
||||
NSLocalizedString(@"Speed Limit Auto Disabled", "notification title");
|
||||
notification.informativeText = NSLocalizedString(@"Bandwidth settings changed", "notification description");
|
||||
notification.hasActionButton = NO;
|
||||
NSString* title = isLimited ? NSLocalizedString(@"Speed Limit Auto Enabled", "notification title") :
|
||||
NSLocalizedString(@"Speed Limit Auto Disabled", "notification title");
|
||||
NSString* body = NSLocalizedString(@"Bandwidth settings changed", "notification description");
|
||||
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
||||
if (@available(macOS 10.14, *))
|
||||
{
|
||||
NSString* identifier = @"Bandwidth settings changed";
|
||||
UNMutableNotificationContent* content = [UNMutableNotificationContent new];
|
||||
content.title = title;
|
||||
content.body = body;
|
||||
|
||||
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:nil];
|
||||
[UNUserNotificationCenter.currentNotificationCenter addNotificationRequest:request withCompletionHandler:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback on earlier versions
|
||||
NSUserNotification* notification = [[NSUserNotification alloc] init];
|
||||
notification.title = title;
|
||||
notification.informativeText = body;
|
||||
notification.hasActionButton = NO;
|
||||
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3468,12 +3579,27 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool
|
|||
[self openFiles:@[ fullFile ] addType:ADD_AUTO forcePath:nil];
|
||||
|
||||
NSString* notificationTitle = NSLocalizedString(@"Torrent File Auto Added", "notification title");
|
||||
NSUserNotification* notification = [[NSUserNotification alloc] init];
|
||||
notification.title = notificationTitle;
|
||||
notification.informativeText = file;
|
||||
notification.hasActionButton = NO;
|
||||
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
||||
if (@available(macOS 10.14, *))
|
||||
{
|
||||
NSString* identifier = [@"Torrent File Auto Added " stringByAppendingString:file];
|
||||
UNMutableNotificationContent* content = [UNMutableNotificationContent new];
|
||||
content.title = notificationTitle;
|
||||
content.body = file;
|
||||
|
||||
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:nil];
|
||||
[UNUserNotificationCenter.currentNotificationCenter addNotificationRequest:request withCompletionHandler:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback on earlier versions
|
||||
NSUserNotification* notification = [[NSUserNotification alloc] init];
|
||||
notification.title = notificationTitle;
|
||||
notification.informativeText = file;
|
||||
notification.hasActionButton = NO;
|
||||
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue