| @@ -20,12 +20,14 @@ mac{ | |||||
| LIBS += -framework Foundation | LIBS += -framework Foundation | ||||
| OBJECTIVE_SOURCES += osx/notification.mm | |||||
| OBJECTIVE_SOURCES += osx/notification.mm\ | |||||
| osx/notificationimpl.mm | |||||
| SOURCES += osx/osxplatform.cpp | SOURCES += osx/osxplatform.cpp | ||||
| HEADERS += osx/notification.h\ | HEADERS += osx/notification.h\ | ||||
| osx/osxplatform.h | |||||
| osx/osxplatform.h\ | |||||
| osx/notificationimpl.h | |||||
| } | } | ||||
| SOURCES += main.cpp\ | SOURCES += main.cpp\ | ||||
| @@ -54,7 +56,6 @@ SOURCES += main.cpp\ | |||||
| chooseemojiwidget.cpp \ | chooseemojiwidget.cpp \ | ||||
| sendtextedit.cpp \ | sendtextedit.cpp \ | ||||
| feiqwin.cpp \ | feiqwin.cpp \ | ||||
| plugin/unreadchecker.cpp \ | |||||
| plugin/iplugin.cpp \ | plugin/iplugin.cpp \ | ||||
| plugin/rankuser.cpp \ | plugin/rankuser.cpp \ | ||||
| settings.cpp | settings.cpp | ||||
| @@ -94,7 +95,6 @@ HEADERS += mainwindow.h \ | |||||
| sendtextedit.h \ | sendtextedit.h \ | ||||
| plugin/iplugin.h \ | plugin/iplugin.h \ | ||||
| feiqwin.h \ | feiqwin.h \ | ||||
| plugin/unreadchecker.h \ | |||||
| plugin/rankuser.h \ | plugin/rankuser.h \ | ||||
| settings.h | settings.h | ||||
| @@ -2,8 +2,6 @@ | |||||
| #include "mainwindow.h" | #include "mainwindow.h" | ||||
| #include "plugin/iplugin.h" | #include "plugin/iplugin.h" | ||||
| #include "plugin/unreadchecker.h" | |||||
| FeiqWin::FeiqWin() | FeiqWin::FeiqWin() | ||||
| { | { | ||||
| @@ -34,11 +32,6 @@ Settings *FeiqWin::settings() | |||||
| return mMainWin->mSettings; | return mMainWin->mSettings; | ||||
| } | } | ||||
| int FeiqWin::getUnreadCount() | |||||
| { | |||||
| return mMainWin->getUnreadCount(); | |||||
| } | |||||
| void FeiqWin::init(MainWindow *mainWin) | void FeiqWin::init(MainWindow *mainWin) | ||||
| { | { | ||||
| mMainWin = mainWin; | mMainWin = mainWin; | ||||
| @@ -27,9 +27,6 @@ public: | |||||
| const FeiqModel* feiqModel(); | const FeiqModel* feiqModel(); | ||||
| Settings* settings(); | Settings* settings(); | ||||
| public: | |||||
| int getUnreadCount(); | |||||
| private: | private: | ||||
| void init(MainWindow* mainWin); | void init(MainWindow* mainWin); | ||||
| void unInit(); | void unInit(); | ||||
| @@ -80,6 +80,9 @@ MainWindow::MainWindow(QWidget *parent) : | |||||
| connect(ui->actionSendKnock, SIGNAL(triggered(bool)), this, SLOT(sendKnock())); | connect(ui->actionSendKnock, SIGNAL(triggered(bool)), this, SLOT(sendKnock())); | ||||
| connect(ui->actionSendFile, SIGNAL(triggered(bool)), this, SLOT(sendFile())); | connect(ui->actionSendFile, SIGNAL(triggered(bool)), this, SLOT(sendFile())); | ||||
| //初始化平台相关特性 | |||||
| PlatformDepend::instance().setMainWnd(this); | |||||
| //初始化飞秋引擎 | //初始化飞秋引擎 | ||||
| connect(this, SIGNAL(feiqViewEvent(shared_ptr<ViewEvent>)), this, SLOT(handleFeiqViewEvent(shared_ptr<ViewEvent>))); | connect(this, SIGNAL(feiqViewEvent(shared_ptr<ViewEvent>)), this, SLOT(handleFeiqViewEvent(shared_ptr<ViewEvent>))); | ||||
| @@ -105,13 +108,55 @@ void MainWindow::setFeiqWin(FeiqWin *feiqWin) | |||||
| mFeiqWin->init(this); | mFeiqWin->init(this); | ||||
| } | } | ||||
| void MainWindow::onNotifyClicked(const QString& fellowIp) | |||||
| { | |||||
| qDebug()<<fellowIp; | |||||
| auto fellow = mFeiq.getModel().findFirstFellowOf(fellowIp.toStdString()); | |||||
| if (fellow) | |||||
| openChartTo(fellow.get()); | |||||
| raise(); | |||||
| activateWindow(); | |||||
| showNormal(); | |||||
| } | |||||
| void MainWindow::onNotifyReplied(long notifyId, const QString &fellowIp, const QString &reply) | |||||
| { | |||||
| auto fellow = mFeiq.getModel().findFirstFellowOf(fellowIp.toStdString()); | |||||
| if (fellow) | |||||
| { | |||||
| //回复消息 | |||||
| auto content = make_shared<TextContent>(); | |||||
| content->text = reply.toStdString(); | |||||
| mFeiq.send(fellow, content); | |||||
| //设为已回复 | |||||
| auto msgRepliedTo = findUnshownMessage(notifyId); | |||||
| if (msgRepliedTo) | |||||
| { | |||||
| msgRepliedTo->replied=true; | |||||
| } | |||||
| //将自己的回复放入未显示列表 | |||||
| auto event = make_shared<MessageViewEvent>(); | |||||
| event->contents.push_back(content); | |||||
| event->fellow = nullptr; | |||||
| auto& msg = addUnshownMessage(fellow.get(), event); | |||||
| msg.read = true; | |||||
| updateUnshownHint(fellow.get()); | |||||
| } | |||||
| } | |||||
| void MainWindow::enterEvent(QEvent *event) | void MainWindow::enterEvent(QEvent *event) | ||||
| { | { | ||||
| auto fellow = mRecvTextEdit->curFellow(); | auto fellow = mRecvTextEdit->curFellow(); | ||||
| if (fellow) | if (fellow) | ||||
| { | { | ||||
| flushUnread(fellow); | |||||
| updateUnread(fellow); | |||||
| flushUnshown(fellow); | |||||
| updateUnshownHint(fellow); | |||||
| } | } | ||||
| PlatformDepend::instance().hideAllNotify(); | PlatformDepend::instance().hideAllNotify(); | ||||
| @@ -122,8 +167,8 @@ void MainWindow::openChartTo(const Fellow *fellow) | |||||
| mFellowList.top(*fellow); | mFellowList.top(*fellow); | ||||
| mRecvTextEdit->setCurFellow(fellow); | mRecvTextEdit->setCurFellow(fellow); | ||||
| setWindowTitle(mTitle + " - 与"+fellow->getName().c_str()+"会话中"); | setWindowTitle(mTitle + " - 与"+fellow->getName().c_str()+"会话中"); | ||||
| flushUnread(fellow); | |||||
| updateUnread(fellow); | |||||
| flushUnshown(fellow); | |||||
| updateUnshownHint(fellow); | |||||
| } | } | ||||
| shared_ptr<Fellow> MainWindow::checkCurFellow() | shared_ptr<Fellow> MainWindow::checkCurFellow() | ||||
| @@ -150,7 +195,9 @@ void MainWindow::onStateChanged(FileTask *fileTask) | |||||
| if (fileTask->getState()==FileTaskState::Finish) | if (fileTask->getState()==FileTaskState::Finish) | ||||
| { | { | ||||
| auto title = QString(fileTask->getTaskTypeDes().c_str())+"完成"; | auto title = QString(fileTask->getTaskTypeDes().c_str())+"完成"; | ||||
| PlatformDepend::instance().showNotify(title, fileTask->getContent()->filename.c_str()); | |||||
| PlatformDepend::instance().showNotify(title, | |||||
| fileTask->getContent()->filename.c_str(), | |||||
| fileTask->fellow()->getIp().c_str()); | |||||
| } | } | ||||
| else if (fileTask->getState()==FileTaskState::Error) | else if (fileTask->getState()==FileTaskState::Error) | ||||
| { | { | ||||
| @@ -158,7 +205,9 @@ void MainWindow::onStateChanged(FileTask *fileTask) | |||||
| auto content = QString(fileTask->getContent()->filename.c_str()); | auto content = QString(fileTask->getContent()->filename.c_str()); | ||||
| content += "\n"; | content += "\n"; | ||||
| content += fileTask->getDetailInfo().c_str(); | content += fileTask->getDetailInfo().c_str(); | ||||
| PlatformDepend::instance().showNotify(title, content); | |||||
| PlatformDepend::instance().showNotify(title, | |||||
| content, | |||||
| fileTask->fellow()->getIp().c_str()); | |||||
| } | } | ||||
| if (mDownloadFileDlg->isVisible()) | if (mDownloadFileDlg->isVisible()) | ||||
| @@ -200,23 +249,15 @@ void MainWindow::handleFeiqViewEvent(shared_ptr<ViewEvent> event) | |||||
| auto e = static_cast<FellowViewEvent*>(event.get()); | auto e = static_cast<FellowViewEvent*>(event.get()); | ||||
| auto fellow = e->fellow.get(); | auto fellow = e->fellow.get(); | ||||
| if (isActiveWindow()) | |||||
| if (isActiveWindow() && fellow == mRecvTextEdit->curFellow()) | |||||
| {//窗口可见,处理当前用户消息,其他用户消息则放入通知队列 | {//窗口可见,处理当前用户消息,其他用户消息则放入通知队列 | ||||
| if (fellow == mRecvTextEdit->curFellow()) | |||||
| { | |||||
| readEvent(event.get()); | |||||
| } | |||||
| else | |||||
| { | |||||
| mUnreadEvents[fellow].push_back(event); | |||||
| updateUnread(fellow); | |||||
| } | |||||
| readEvent(event.get()); | |||||
| } | } | ||||
| else | else | ||||
| {//窗口不可见,放入未读队列并通知 | {//窗口不可见,放入未读队列并通知 | ||||
| mUnreadEvents[fellow].push_back(event); | |||||
| updateUnread(fellow); | |||||
| notifyUnread(event.get()); | |||||
| auto& umsg = addUnshownMessage(fellow, event); | |||||
| notifyUnshown(umsg); | |||||
| updateUnshownHint(fellow); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -277,31 +318,39 @@ void MainWindow::userAddFellow(QString ip) | |||||
| mFeiq.sendImOnLine(fellow->getIp()); | mFeiq.sendImOnLine(fellow->getIp()); | ||||
| } | } | ||||
| void MainWindow::notifyUnread(const ViewEvent *event) | |||||
| void MainWindow::notifyUnshown(UnshownMessage& umsg) | |||||
| { | { | ||||
| auto event = umsg.event.get(); | |||||
| if (event->what == ViewEventType::SEND_TIMEO) | if (event->what == ViewEventType::SEND_TIMEO) | ||||
| { | { | ||||
| auto e = static_cast<const SendTimeoEvent*>(event); | auto e = static_cast<const SendTimeoEvent*>(event); | ||||
| auto fellow = e->fellow.get(); | auto fellow = e->fellow.get(); | ||||
| showNotification(fellow, "发送超时:"+simpleTextOf(e->content.get())); | |||||
| umsg.notifyId = showNotification(fellow, "发送超时:"+simpleTextOf(e->content.get())); | |||||
| } | } | ||||
| else if (event->what == ViewEventType::MESSAGE) | else if (event->what == ViewEventType::MESSAGE) | ||||
| { | { | ||||
| auto e = static_cast<const MessageViewEvent*>(event); | auto e = static_cast<const MessageViewEvent*>(event); | ||||
| auto fellow = e->fellow.get(); | auto fellow = e->fellow.get(); | ||||
| QString text=""; | |||||
| bool first=false; | |||||
| for (auto content : e->contents) | for (auto content : e->contents) | ||||
| { | { | ||||
| showNotification(fellow, simpleTextOf(content.get())); | |||||
| auto t = simpleTextOf(content.get()); | |||||
| if (first) | |||||
| text = t; | |||||
| else | |||||
| text = text+"\n"+t; | |||||
| } | } | ||||
| umsg.notifyId = showNotification(fellow, text); | |||||
| } | } | ||||
| } | } | ||||
| void MainWindow::showNotification(const Fellow *fellow, const QString &text) | |||||
| long MainWindow::showNotification(const Fellow *fellow, const QString &text) | |||||
| { | { | ||||
| QString content(text); | QString content(text); | ||||
| if (content.length()>20) | if (content.length()>20) | ||||
| content = content.left(20)+"..."; | content = content.left(20)+"..."; | ||||
| PlatformDepend::instance().showNotify(QString(fellow->getName().c_str())+":", content); | |||||
| return PlatformDepend::instance().showNotify(QString(fellow->getName().c_str())+":", content, fellow->getIp().c_str()); | |||||
| } | } | ||||
| void MainWindow::navigateToFileTask(IdType packetNo, IdType fileId, bool upload) | void MainWindow::navigateToFileTask(IdType packetNo, IdType fileId, bool upload) | ||||
| @@ -462,12 +511,12 @@ void MainWindow::initFeiq() | |||||
| qDebug()<<"feiq started"; | qDebug()<<"feiq started"; | ||||
| } | } | ||||
| void MainWindow::updateUnread(const Fellow *fellow) | |||||
| void MainWindow::updateUnshownHint(const Fellow *fellow) | |||||
| { | { | ||||
| auto it = mUnreadEvents.find(fellow); | |||||
| if (it != mUnreadEvents.end()) | |||||
| auto it = mUnshownEvents.find(fellow); | |||||
| if (it != mUnshownEvents.end()) | |||||
| { | { | ||||
| auto count = (*it).second.size(); | |||||
| auto count = it->second.size(); | |||||
| if (count == 0) | if (count == 0) | ||||
| { | { | ||||
| mFellowList.mark(*fellow, ""); | mFellowList.mark(*fellow, ""); | ||||
| @@ -483,26 +532,30 @@ void MainWindow::updateUnread(const Fellow *fellow) | |||||
| int MainWindow::getUnreadCount() | int MainWindow::getUnreadCount() | ||||
| { | { | ||||
| auto begin = mUnreadEvents.begin(); | |||||
| auto end = mUnreadEvents.end(); | |||||
| auto begin = mUnshownEvents.begin(); | |||||
| auto end = mUnshownEvents.end(); | |||||
| auto count = 0; | auto count = 0; | ||||
| for (auto it = begin; it != end; it++) | for (auto it = begin; it != end; it++) | ||||
| { | { | ||||
| count += it->second.size(); | |||||
| for (auto msg : it->second) | |||||
| { | |||||
| if (msg.isUnread()) | |||||
| ++count; | |||||
| } | |||||
| } | } | ||||
| return count; | return count; | ||||
| } | } | ||||
| void MainWindow::flushUnread(const Fellow *fellow) | |||||
| void MainWindow::flushUnshown(const Fellow *fellow) | |||||
| { | { | ||||
| auto it = mUnreadEvents.find(fellow); | |||||
| if (it != mUnreadEvents.end()) | |||||
| auto it = mUnshownEvents.find(fellow); | |||||
| if (it != mUnshownEvents.end()) | |||||
| { | { | ||||
| auto& list = (*it).second; | auto& list = (*it).second; | ||||
| while (!list.empty()) | while (!list.empty()) | ||||
| { | { | ||||
| auto event = list.front(); | |||||
| readEvent(event.get()); | |||||
| auto msg = list.front(); | |||||
| readEvent(msg.event.get()); | |||||
| list.pop_front(); | list.pop_front(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -525,7 +578,10 @@ void MainWindow::readEvent(const ViewEvent *event) | |||||
| auto time = e->when.time_since_epoch().count(); | auto time = e->when.time_since_epoch().count(); | ||||
| for (auto content : e->contents) | for (auto content : e->contents) | ||||
| { | { | ||||
| mRecvTextEdit->addFellowContent(content.get(), time); | |||||
| if (e->fellow == nullptr) | |||||
| mRecvTextEdit->addMyContent(content.get(), time); | |||||
| else | |||||
| mRecvTextEdit->addFellowContent(content.get(), time); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -550,3 +606,27 @@ QString MainWindow::simpleTextOf(const Content *content) | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| UnshownMessage &MainWindow::addUnshownMessage(const Fellow *fellow, shared_ptr<ViewEvent> event) | |||||
| { | |||||
| UnshownMessage msg; | |||||
| msg.event = event; | |||||
| mUnshownEvents[fellow].push_back(msg); | |||||
| return mUnshownEvents[fellow].back(); | |||||
| } | |||||
| UnshownMessage* MainWindow::findUnshownMessage(int id) | |||||
| { | |||||
| auto begin = mUnshownEvents.begin(); | |||||
| auto end = mUnshownEvents.end(); | |||||
| for (auto it = begin; it != end; it++) | |||||
| { | |||||
| for (auto& msg : it->second){ | |||||
| if (msg.notifyId == id) | |||||
| return &msg; | |||||
| } | |||||
| } | |||||
| return nullptr; | |||||
| } | |||||
| @@ -21,6 +21,19 @@ class MainWindow; | |||||
| class FeiqWin; | class FeiqWin; | ||||
| struct UnshownMessage | |||||
| { | |||||
| shared_ptr<ViewEvent> event; | |||||
| bool replied = false; | |||||
| bool read = false; | |||||
| long notifyId = 0; | |||||
| bool isUnread() | |||||
| { | |||||
| return !replied && !read; | |||||
| } | |||||
| }; | |||||
| Q_DECLARE_METATYPE(shared_ptr<ViewEvent>) | Q_DECLARE_METATYPE(shared_ptr<ViewEvent>) | ||||
| class MainWindow : public QMainWindow, IFeiqView | class MainWindow : public QMainWindow, IFeiqView | ||||
| { | { | ||||
| @@ -33,6 +46,10 @@ public: | |||||
| void setFeiqWin(FeiqWin* feiqWin); | void setFeiqWin(FeiqWin* feiqWin); | ||||
| public slots: | |||||
| void onNotifyClicked(const QString& fellowIp); | |||||
| void onNotifyReplied(long notifyId, const QString& fellowIp, const QString& reply); | |||||
| protected: | protected: | ||||
| void enterEvent(QEvent *event); | void enterEvent(QEvent *event); | ||||
| @@ -62,19 +79,22 @@ private slots: | |||||
| private: | private: | ||||
| void userAddFellow(QString ip); | void userAddFellow(QString ip); | ||||
| void notifyUnread(const ViewEvent* event); | |||||
| void showNotification(const Fellow* fellow, const QString& text); | |||||
| long showNotification(const Fellow* fellow, const QString& text); | |||||
| shared_ptr<Fellow> checkCurFellow(); | shared_ptr<Fellow> checkCurFellow(); | ||||
| void showResult(pair<bool, string> ret, const Content *content); | void showResult(pair<bool, string> ret, const Content *content); | ||||
| vector<const Fellow*> fellowSearchDriver(const QString& text); | vector<const Fellow*> fellowSearchDriver(const QString& text); | ||||
| void initFeiq(); | void initFeiq(); | ||||
| void updateUnread(const Fellow* fellow); | |||||
| int getUnreadCount(); | |||||
| void flushUnread(const Fellow* fellow); | |||||
| void readEvent(const ViewEvent* event); | void readEvent(const ViewEvent* event); | ||||
| void setBadgeNumber(int number); | void setBadgeNumber(int number); | ||||
| QString simpleTextOf(const Content* content); | QString simpleTextOf(const Content* content); | ||||
| UnshownMessage& addUnshownMessage(const Fellow *fellow, shared_ptr<ViewEvent> event); | |||||
| UnshownMessage *findUnshownMessage(int id); | |||||
| void notifyUnshown(UnshownMessage &umsg); | |||||
| void updateUnshownHint(const Fellow* fellow); | |||||
| int getUnreadCount(); | |||||
| void flushUnshown(const Fellow* fellow); | |||||
| // IFileTaskObserver interface | // IFileTaskObserver interface | ||||
| public: | public: | ||||
| void onStateChanged(FileTask *fileTask); | void onStateChanged(FileTask *fileTask); | ||||
| @@ -95,7 +115,7 @@ private: | |||||
| RecvTextEdit* mRecvTextEdit; | RecvTextEdit* mRecvTextEdit; | ||||
| SendTextEdit* mSendTextEdit; | SendTextEdit* mSendTextEdit; | ||||
| QString mTitle; | QString mTitle; | ||||
| unordered_map<const Fellow*, list<shared_ptr<ViewEvent>>> mUnreadEvents; | |||||
| unordered_map<const Fellow*, list<UnshownMessage>> mUnshownEvents; | |||||
| FeiqWin* mFeiqWin = nullptr; | FeiqWin* mFeiqWin = nullptr; | ||||
| }; | }; | ||||
| @@ -2,13 +2,18 @@ | |||||
| #define OSXNOTIFICATION_H | #define OSXNOTIFICATION_H | ||||
| #include <QString> | #include <QString> | ||||
| #include <QObject> | |||||
| class MainWindow; | |||||
| class Notification | class Notification | ||||
| { | { | ||||
| public: | public: | ||||
| explicit Notification(); | explicit Notification(); | ||||
| void show(const QString& title, const QString& content); | |||||
| int show(const QString& title, const QString& content, const QString &fellowIp); | |||||
| void hideAll(); | void hideAll(); | ||||
| public: | |||||
| void setMainWnd(MainWindow* mainWnd); | |||||
| }; | }; | ||||
| #endif // OSXNOTIFICATION_H | #endif // OSXNOTIFICATION_H | ||||
| @@ -1,22 +1,46 @@ | |||||
| #include "notification.h" | #include "notification.h" | ||||
| #include "notificationimpl.h" | |||||
| #include <QDebug> | |||||
| #include "../mainwindow.h" | |||||
| #import <cocoa/Cocoa.h> | |||||
| static NotificationImpl* impl = [[NotificationImpl alloc] init]; | |||||
| static void clickCallback(void* arg, NSString* fellowIp) | |||||
| { | |||||
| MainWindow* mainWnd = (MainWindow*)arg; | |||||
| const char* ip = [fellowIp UTF8String]; | |||||
| mainWnd->onNotifyClicked(ip); | |||||
| } | |||||
| static void replyCallback(void* arg, long notifyId, NSString* fellowIp, NSString* str) | |||||
| { | |||||
| const char* reply = [str UTF8String]; | |||||
| const char* ip = [fellowIp UTF8String]; | |||||
| MainWindow* mainWnd = (MainWindow*)arg; | |||||
| mainWnd->onNotifyReplied(notifyId, ip, reply); | |||||
| } | |||||
| Notification::Notification() | Notification::Notification() | ||||
| { | { | ||||
| } | } | ||||
| void Notification::show(const QString &title, const QString &content) | |||||
| int Notification::show(const QString &title, const QString &content, const QString& fellowIp) | |||||
| { | { | ||||
| NSUserNotification *userNotification = [[[NSUserNotification alloc] init] autorelease]; | |||||
| userNotification.title = title.toNSString(); | |||||
| userNotification.informativeText = content.toNSString(); | |||||
| NSUserNotificationCenter* center = [NSUserNotificationCenter defaultUserNotificationCenter]; | |||||
| [center deliverNotification:userNotification]; | |||||
| NSString* objcTitle = title.toNSString(); | |||||
| NSString* objcMessage = content.toNSString(); | |||||
| return [impl show: objcTitle message: objcMessage extra: fellowIp.toNSString()]; | |||||
| } | } | ||||
| void Notification::hideAll() | void Notification::hideAll() | ||||
| { | { | ||||
| [[NSUserNotificationCenter defaultUserNotificationCenter] removeAllDeliveredNotifications]; | |||||
| [impl hideAll]; | |||||
| } | |||||
| void Notification::setMainWnd(MainWindow *mainWnd) | |||||
| { | |||||
| impl->clickCallback = clickCallback; | |||||
| impl->replyCallback = replyCallback; | |||||
| impl->callbackArg = mainWnd; | |||||
| } | } | ||||
| @@ -0,0 +1,32 @@ | |||||
| #ifndef NOTIFICATIONIMPL_H | |||||
| #define NOTIFICATIONIMPL_H | |||||
| #ifdef __cplusplus | |||||
| extern "C"{ | |||||
| #endif | |||||
| #import <Foundation/Foundation.h> | |||||
| typedef void(*ClickCallback)(void*, NSString*); | |||||
| typedef void(*ReplyCallback)(void*, long, NSString*, NSString*); | |||||
| @interface NotificationImpl : NSObject | |||||
| { | |||||
| @public | |||||
| ClickCallback clickCallback; | |||||
| ReplyCallback replyCallback; | |||||
| void* callbackArg; | |||||
| @private | |||||
| int id; | |||||
| } | |||||
| -(instancetype)init; | |||||
| -(long)show: (NSString*)title message:(NSString*)msg extra:(NSString*)who; | |||||
| -(void)hideAll; | |||||
| @end | |||||
| #ifdef __cplusplus | |||||
| } | |||||
| #endif | |||||
| #endif // NOTIFICATIONIMPL_H | |||||
| @@ -0,0 +1,61 @@ | |||||
| #include "notificationimpl.h" | |||||
| #include <QDebug> | |||||
| @interface NotificationImpl () <NSUserNotificationCenterDelegate> | |||||
| @end | |||||
| @implementation NotificationImpl | |||||
| -(instancetype)init | |||||
| { | |||||
| self = [super init]; | |||||
| if(self) | |||||
| { | |||||
| id=0; | |||||
| [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self]; | |||||
| } | |||||
| return self; | |||||
| } | |||||
| -(long)show:(NSString*)title message:(NSString*)msg extra:(NSString*)who | |||||
| { | |||||
| NSUserNotification* notification = [[NSUserNotification alloc] init]; | |||||
| notification.title = title; | |||||
| if (who != nil && who.length > 0) | |||||
| { | |||||
| notification.userInfo=@{@"extra":who}; | |||||
| notification.hasReplyButton = true; | |||||
| } | |||||
| int myid = ++id; | |||||
| notification.identifier = [NSString stringWithFormat:@"%d",myid]; | |||||
| notification.informativeText = msg; | |||||
| [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification: notification]; | |||||
| return (long)myid; | |||||
| } | |||||
| -(void)hideAll | |||||
| { | |||||
| [[NSUserNotificationCenter defaultUserNotificationCenter] removeAllDeliveredNotifications]; | |||||
| } | |||||
| -(BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresent:(NSUserNotification *)notification | |||||
| { | |||||
| return YES; | |||||
| } | |||||
| -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification | |||||
| { | |||||
| NSString* who = [notification.userInfo objectForKey:@"extra"]; | |||||
| int myid = notification.identifier.intValue; | |||||
| if (notification.activationType == NSUserNotificationActivationTypeContentsClicked){ | |||||
| clickCallback(callbackArg, who); | |||||
| } | |||||
| else if (notification.activationType == NSUserNotificationActivationTypeReplied){ | |||||
| replyCallback(callbackArg, myid, who, notification.response.string); | |||||
| } | |||||
| } | |||||
| @end | |||||
| @@ -6,9 +6,9 @@ OsxPlatform::OsxPlatform() | |||||
| } | } | ||||
| void OsxPlatform::showNotify(const QString &title, const QString &content) | |||||
| long OsxPlatform::showNotify(const QString &title, const QString &content, const QString & fellowIp) | |||||
| { | { | ||||
| mNotify.show(title, content); | |||||
| return mNotify.show(title, content, fellowIp); | |||||
| } | } | ||||
| void OsxPlatform::hideAllNotify() | void OsxPlatform::hideAllNotify() | ||||
| @@ -23,3 +23,9 @@ void OsxPlatform::setBadgeNumber(int number) | |||||
| else | else | ||||
| QtMac::setBadgeLabelText(QString::number(number)); | QtMac::setBadgeLabelText(QString::number(number)); | ||||
| } | } | ||||
| void OsxPlatform::setMainWnd(MainWindow *mainWnd) | |||||
| { | |||||
| IPlatform::setMainWnd(mainWnd); | |||||
| mNotify.setMainWnd(mainWnd); | |||||
| } | |||||
| @@ -10,11 +10,12 @@ public: | |||||
| OsxPlatform(); | OsxPlatform(); | ||||
| public: | public: | ||||
| void showNotify(const QString& title, const QString& content) override; | |||||
| long showNotify(const QString& title, const QString& content, const QString &fellowIp) override; | |||||
| void hideAllNotify() override; | void hideAllNotify() override; | ||||
| void setBadgeNumber(int number) override; | void setBadgeNumber(int number) override; | ||||
| void setMainWnd(MainWindow *mainWnd) override; | |||||
| private: | private: | ||||
| Notification mNotify; | Notification mNotify; | ||||
| }; | }; | ||||
| @@ -7,10 +7,12 @@ | |||||
| class MockPlatform : public IPlatform | class MockPlatform : public IPlatform | ||||
| { | { | ||||
| public: | public: | ||||
| void showNotify(const QString& title, const QString& content) | |||||
| long showNotify(const QString& title, const QString& content, const QString& data) | |||||
| { | { | ||||
| (void)title; | (void)title; | ||||
| (void)content; | (void)content; | ||||
| (void)data; | |||||
| return 0; | |||||
| } | } | ||||
| void hideAllNotify() | void hideAllNotify() | ||||
| { | { | ||||
| @@ -43,9 +45,9 @@ PlatformDepend &PlatformDepend::instance() | |||||
| return me; | return me; | ||||
| } | } | ||||
| void PlatformDepend::showNotify(const QString &title, const QString &content) | |||||
| long PlatformDepend::showNotify(const QString &title, const QString &content, const QString &fellowIp) | |||||
| { | { | ||||
| mImpl->showNotify(title, content); | |||||
| return mImpl->showNotify(title, content, fellowIp); | |||||
| } | } | ||||
| void PlatformDepend::hideAllNotify() | void PlatformDepend::hideAllNotify() | ||||
| @@ -57,3 +59,9 @@ void PlatformDepend::setBadgeNumber(int number) | |||||
| { | { | ||||
| mImpl->setBadgeNumber(number); | mImpl->setBadgeNumber(number); | ||||
| } | } | ||||
| void PlatformDepend::setMainWnd(MainWindow *mainWnd) | |||||
| { | |||||
| IPlatform::setMainWnd(mainWnd); | |||||
| mImpl->setMainWnd(mainWnd); | |||||
| } | |||||
| @@ -2,15 +2,22 @@ | |||||
| #define PLATFORMDEPEND_H | #define PLATFORMDEPEND_H | ||||
| #include <QString> | #include <QString> | ||||
| class MainWindow; | |||||
| class IPlatform | class IPlatform | ||||
| { | { | ||||
| public: | public: | ||||
| virtual ~IPlatform(){} | virtual ~IPlatform(){} | ||||
| virtual void showNotify(const QString& title, const QString& content) = 0; | |||||
| virtual long showNotify(const QString& title, const QString& content, const QString & fellowIp) = 0; | |||||
| virtual void hideAllNotify() = 0; | virtual void hideAllNotify() = 0; | ||||
| virtual void setBadgeNumber(int number) = 0; | virtual void setBadgeNumber(int number) = 0; | ||||
| virtual void setMainWnd(MainWindow* mainWnd) | |||||
| { | |||||
| Q_UNUSED(mainWnd); | |||||
| } | |||||
| }; | }; | ||||
| class PlatformDepend : public IPlatform | class PlatformDepend : public IPlatform | ||||
| @@ -23,11 +30,12 @@ public: | |||||
| static PlatformDepend& instance(); | static PlatformDepend& instance(); | ||||
| public: | public: | ||||
| void showNotify(const QString& title, const QString& content) override; | |||||
| long showNotify(const QString& title, const QString& content, const QString & fellowIp) override; | |||||
| void hideAllNotify() override; | void hideAllNotify() override; | ||||
| void setBadgeNumber(int number) override; | void setBadgeNumber(int number) override; | ||||
| void setMainWnd(MainWindow* mainWnd) override; | |||||
| private: | private: | ||||
| IPlatform* mImpl; | IPlatform* mImpl; | ||||
| }; | }; | ||||
| @@ -1,39 +0,0 @@ | |||||
| #include "unreadchecker.h" | |||||
| #include <QTimerEvent> | |||||
| #include "platformdepend.h" | |||||
| #define PLUGIN_NAME "unread_checker" | |||||
| REGISTER_PLUGIN(PLUGIN_NAME, UnreadChecker) | |||||
| UnreadChecker::UnreadChecker() | |||||
| { | |||||
| } | |||||
| void UnreadChecker::timerEvent(QTimerEvent *event) | |||||
| { | |||||
| if (event->timerId() == mUnreadTimerId) | |||||
| { | |||||
| auto count = mFeiq->getUnreadCount(); | |||||
| if (count > 0) | |||||
| { | |||||
| PlatformDepend::instance().hideAllNotify(); | |||||
| PlatformDepend::instance().showNotify("未读提醒", QString("还有%1条未读消息").arg(count)); | |||||
| } | |||||
| } | |||||
| } | |||||
| void UnreadChecker::init() | |||||
| { | |||||
| IPlugin::init(); | |||||
| auto settings = mFeiq->settings(); | |||||
| mUnreadTimerInterval = settings->value(PLUGIN_NAME"/timer", "600").toInt(); | |||||
| if (mUnreadTimerInterval > 0) | |||||
| mUnreadTimerId = startTimer(mUnreadTimerInterval*1000, Qt::VeryCoarseTimer); | |||||
| } | |||||
| void UnreadChecker::unInit() | |||||
| { | |||||
| if (mUnreadTimerId > 0) | |||||
| killTimer(mUnreadTimerId); | |||||
| } | |||||
| @@ -1,25 +0,0 @@ | |||||
| #ifndef UNREADCHECKER_H | |||||
| #define UNREADCHECKER_H | |||||
| #include "iplugin.h" | |||||
| #include <QObject> | |||||
| class UnreadChecker : public QObject, public IPlugin | |||||
| { | |||||
| Q_OBJECT | |||||
| public: | |||||
| UnreadChecker(); | |||||
| void init() override; | |||||
| void unInit() override; | |||||
| protected: | |||||
| void timerEvent(QTimerEvent *event) override; | |||||
| private: | |||||
| int mUnreadTimerInterval; | |||||
| int mUnreadTimerId=-1; | |||||
| int mLastCheckCount=0; | |||||
| }; | |||||
| #endif // UNREADCHECKER_H | |||||