2016-10-02 12:30:28 +03:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
|
|
|
|
|
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
It is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
In addition, as a special exception, the copyright holders give permission
|
|
|
|
to link the code of portions of this program with the OpenSSL library.
|
|
|
|
|
|
|
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
2017-01-11 22:31:31 +04:00
|
|
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
2016-10-02 12:30:28 +03:00
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "platform/mac/notifications_manager_mac.h"
|
|
|
|
|
2016-10-02 16:54:27 +03:00
|
|
|
#include "pspecific.h"
|
2016-10-02 18:44:54 +03:00
|
|
|
#include "platform/mac/mac_utilities.h"
|
2016-10-04 21:18:08 +03:00
|
|
|
#include "styles/style_window.h"
|
2016-10-02 18:44:54 +03:00
|
|
|
|
|
|
|
#include <Cocoa/Cocoa.h>
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2016-10-02 20:06:34 +03:00
|
|
|
NeverFreedPointer<Platform::Notifications::Manager> ManagerInstance;
|
2016-10-02 18:44:54 +03:00
|
|
|
|
|
|
|
} // namespace
|
2016-10-02 12:30:28 +03:00
|
|
|
|
2016-10-02 20:06:34 +03:00
|
|
|
NSImage *qt_mac_create_nsimage(const QPixmap &pm);
|
|
|
|
|
|
|
|
@interface NotificationDelegate : NSObject<NSUserNotificationCenterDelegate> {
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) init;
|
|
|
|
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification;
|
|
|
|
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NotificationDelegate {
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) init {
|
|
|
|
if (self = [super init]) {
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification {
|
|
|
|
auto manager = ManagerInstance.data();
|
|
|
|
if (!manager) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSDictionary *notificationUserInfo = [notification userInfo];
|
|
|
|
NSNumber *launchIdObject = [notificationUserInfo objectForKey:@"launch"];
|
|
|
|
auto notificationLaunchId = launchIdObject ? [launchIdObject unsignedLongLongValue] : 0ULL;
|
|
|
|
DEBUG_LOG(("Received notification with instance %1").arg(notificationLaunchId));
|
|
|
|
if (notificationLaunchId != Global::LaunchId()) { // other app instance notification
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSNumber *peerObject = [notificationUserInfo objectForKey:@"peer"];
|
|
|
|
auto notificationPeerId = peerObject ? [peerObject unsignedLongLongValue] : 0ULL;
|
|
|
|
if (!notificationPeerId) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"];
|
|
|
|
auto notificationMsgId = msgObject ? [msgObject intValue] : 0;
|
|
|
|
if (notification.activationType == NSUserNotificationActivationTypeReplied) {
|
|
|
|
auto notificationReply = QString::fromUtf8([[[notification response] string] UTF8String]);
|
|
|
|
manager->notificationReplied(notificationPeerId, notificationMsgId, notificationReply);
|
|
|
|
} else if (notification.activationType == NSUserNotificationActivationTypeContentsClicked) {
|
|
|
|
manager->notificationActivated(notificationPeerId, notificationMsgId);
|
|
|
|
}
|
|
|
|
|
|
|
|
[center removeDeliveredNotification: notification];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
namespace Platform {
|
|
|
|
namespace Notifications {
|
|
|
|
|
2016-10-02 12:30:28 +03:00
|
|
|
void start() {
|
2016-10-07 16:37:31 +03:00
|
|
|
if (cPlatform() != dbipMacOld) {
|
2016-10-12 22:34:25 +03:00
|
|
|
ManagerInstance.createIfNull();
|
2016-10-02 18:44:54 +03:00
|
|
|
}
|
2016-10-02 12:30:28 +03:00
|
|
|
}
|
|
|
|
|
2016-10-02 20:06:34 +03:00
|
|
|
Manager *manager() {
|
2016-10-02 18:44:54 +03:00
|
|
|
return ManagerInstance.data();
|
2016-10-02 12:30:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void finish() {
|
2016-10-02 18:44:54 +03:00
|
|
|
ManagerInstance.clear();
|
2016-10-02 12:30:28 +03:00
|
|
|
}
|
|
|
|
|
2016-10-02 16:54:27 +03:00
|
|
|
void defaultNotificationShown(QWidget *widget) {
|
|
|
|
widget->hide();
|
|
|
|
objc_holdOnTop(widget->winId());
|
|
|
|
widget->show();
|
2016-10-02 18:44:54 +03:00
|
|
|
psShowOverAll(widget, false);
|
2016-10-02 16:54:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
class Manager::Impl {
|
|
|
|
public:
|
2016-10-02 20:06:34 +03:00
|
|
|
Impl();
|
2016-10-08 11:38:53 +03:00
|
|
|
void showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton);
|
2016-10-02 16:54:27 +03:00
|
|
|
void clearAll();
|
|
|
|
void clearFromHistory(History *history);
|
2016-10-02 20:06:34 +03:00
|
|
|
void updateDelegate();
|
2016-10-02 16:54:27 +03:00
|
|
|
|
|
|
|
~Impl();
|
|
|
|
|
|
|
|
private:
|
2016-10-02 20:06:34 +03:00
|
|
|
NotificationDelegate *_delegate;
|
2016-10-02 16:54:27 +03:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2016-10-02 20:06:34 +03:00
|
|
|
Manager::Impl::Impl() : _delegate([[NotificationDelegate alloc] init]) {
|
|
|
|
}
|
|
|
|
|
2016-10-08 11:38:53 +03:00
|
|
|
void Manager::Impl::showNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
2016-10-02 18:44:54 +03:00
|
|
|
@autoreleasepool {
|
2016-10-02 16:54:27 +03:00
|
|
|
|
2016-10-02 18:44:54 +03:00
|
|
|
NSUserNotification *notification = [[[NSUserNotification alloc] init] autorelease];
|
|
|
|
if ([notification respondsToSelector:@selector(setIdentifier:)]) {
|
|
|
|
auto identifier = QString::number(Global::LaunchId()) + '_' + QString::number(peer->id) + '_' + QString::number(msgId);
|
|
|
|
auto identifierValue = Q2NSString(identifier);
|
|
|
|
[notification setIdentifier:identifierValue];
|
|
|
|
}
|
2016-10-02 16:54:27 +03:00
|
|
|
[notification setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedLongLong:peer->id],@"peer",[NSNumber numberWithInt:msgId],@"msgid",[NSNumber numberWithUnsignedLongLong:Global::LaunchId()],@"launch",nil]];
|
|
|
|
|
2016-10-02 18:44:54 +03:00
|
|
|
[notification setTitle:Q2NSString(title)];
|
|
|
|
[notification setSubtitle:Q2NSString(subtitle)];
|
|
|
|
[notification setInformativeText:Q2NSString(msg)];
|
2016-10-08 11:38:53 +03:00
|
|
|
if (!hideNameAndPhoto && [notification respondsToSelector:@selector(setContentImage:)]) {
|
2016-10-02 16:54:27 +03:00
|
|
|
auto userpic = peer->genUserpic(st::notifyMacPhotoSize);
|
2016-10-02 18:44:54 +03:00
|
|
|
NSImage *img = [qt_mac_create_nsimage(userpic) autorelease];
|
2016-10-02 16:54:27 +03:00
|
|
|
[notification setContentImage:img];
|
|
|
|
}
|
|
|
|
|
2016-10-08 11:38:53 +03:00
|
|
|
if (!hideReplyButton && [notification respondsToSelector:@selector(setHasReplyButton:)]) {
|
2016-10-02 16:54:27 +03:00
|
|
|
[notification setHasReplyButton:YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
[notification setSoundName:nil];
|
|
|
|
|
2016-10-02 18:44:54 +03:00
|
|
|
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
2016-10-02 16:54:27 +03:00
|
|
|
[center deliverNotification:notification];
|
|
|
|
|
2016-10-02 18:44:54 +03:00
|
|
|
}
|
2016-10-02 16:54:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void Manager::Impl::clearAll() {
|
2016-10-02 18:44:54 +03:00
|
|
|
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
|
|
|
NSArray *notificationsList = [center deliveredNotifications];
|
2016-10-02 20:06:34 +03:00
|
|
|
for (id notification in notificationsList) {
|
|
|
|
NSDictionary *notificationUserInfo = [notification userInfo];
|
|
|
|
NSNumber *launchIdObject = [notificationUserInfo objectForKey:@"launch"];
|
|
|
|
auto notificationLaunchId = launchIdObject ? [launchIdObject unsignedLongLongValue] : 0ULL;
|
|
|
|
if (notificationLaunchId == Global::LaunchId()) {
|
|
|
|
[center removeDeliveredNotification:notification];
|
2016-10-02 18:44:54 +03:00
|
|
|
}
|
|
|
|
}
|
2016-10-02 16:54:27 +03:00
|
|
|
[center removeAllDeliveredNotifications];
|
|
|
|
}
|
|
|
|
|
|
|
|
void Manager::Impl::clearFromHistory(History *history) {
|
|
|
|
unsigned long long peerId = history->peer->id;
|
|
|
|
|
2016-10-02 18:44:54 +03:00
|
|
|
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
|
|
|
NSArray *notificationsList = [center deliveredNotifications];
|
2016-10-02 20:06:34 +03:00
|
|
|
for (id notification in notificationsList) {
|
|
|
|
NSDictionary *notificationUserInfo = [notification userInfo];
|
|
|
|
NSNumber *launchIdObject = [notificationUserInfo objectForKey:@"launch"];
|
|
|
|
NSNumber *peerObject = [notificationUserInfo objectForKey:@"peer"];
|
|
|
|
auto notificationLaunchId = launchIdObject ? [launchIdObject unsignedLongLongValue] : 0ULL;
|
|
|
|
auto notificationPeerId = peerObject ? [peerObject unsignedLongLongValue] : 0ULL;
|
|
|
|
if (notificationPeerId == peerId && notificationLaunchId == Global::LaunchId()) {
|
|
|
|
[center removeDeliveredNotification:notification];
|
2016-10-02 16:54:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-02 20:06:34 +03:00
|
|
|
void Manager::Impl::updateDelegate() {
|
|
|
|
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
|
|
|
[center setDelegate:_delegate];
|
|
|
|
}
|
|
|
|
|
2016-10-02 18:44:54 +03:00
|
|
|
Manager::Impl::~Impl() {
|
2016-10-02 20:06:34 +03:00
|
|
|
[_delegate release];
|
2016-10-02 18:44:54 +03:00
|
|
|
}
|
|
|
|
|
2016-10-02 16:54:27 +03:00
|
|
|
Manager::Manager() : _impl(std_::make_unique<Impl>()) {
|
|
|
|
}
|
|
|
|
|
2016-10-02 20:06:34 +03:00
|
|
|
void Manager::updateDelegate() {
|
|
|
|
_impl->updateDelegate();
|
|
|
|
}
|
|
|
|
|
2016-10-02 16:54:27 +03:00
|
|
|
Manager::~Manager() = default;
|
|
|
|
|
2016-10-08 11:38:53 +03:00
|
|
|
void Manager::doShowNativeNotification(PeerData *peer, MsgId msgId, const QString &title, const QString &subtitle, const QString &msg, bool hideNameAndPhoto, bool hideReplyButton) {
|
|
|
|
_impl->showNotification(peer, msgId, title, subtitle, msg, hideNameAndPhoto, hideReplyButton);
|
2016-10-02 16:54:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void Manager::doClearAllFast() {
|
|
|
|
_impl->clearAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Manager::doClearFromHistory(History *history) {
|
|
|
|
_impl->clearFromHistory(history);
|
|
|
|
}
|
|
|
|
|
2016-10-02 12:30:28 +03:00
|
|
|
} // namespace Notifications
|
|
|
|
} // namespace Platform
|