Merge branch 'dev' into player

Conflicts:
	Telegram/SourceFiles/application.cpp
	Telegram/SourceFiles/core/utils.h
	Telegram/SourceFiles/localstorage.cpp
	Telegram/SourceFiles/pspecific_mac_p.mm
This commit is contained in:
John Preston 2016-10-08 12:10:33 +03:00
commit e616c39608
164 changed files with 6265 additions and 3911 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -68,7 +68,7 @@ semiboldButtonBlueText: #2b99d5;
wndMinHeight: 480px;
wndDefWidth: 800px;
wndDefHeight: 600px;
wndShadow: sprite(209px, 46px, 19px, 19px);
wndShadow: icon {{ "window_shadow", windowShadowFg }};
wndShadowShift: 1px;
layerAlpha: 0.5;
@ -298,10 +298,11 @@ solidScroll: flatScroll {
duration: 150;
hiding: 0;
}
defaultDropdownShadow: icon {{ "dropdown_shadow", windowShadowFg }};
defaultPopupMenu: PopupMenu {
skip: 5px;
shadow: sprite(241px, 46px, 6px, 6px);
shadow: defaultDropdownShadow;
shadowShift: 1px;
itemBg: white;
@ -320,7 +321,7 @@ defaultPopupMenu: PopupMenu {
separatorWidth: 1px;
separatorFg: #f1f1f1;
arrow: sprite(0px, 126px, 4px, 7px);
arrow: icon {{ "dropdown_submenu_arrow", #373737 }};
duration: 120;
@ -689,7 +690,7 @@ btnIntroNext: flatButton(btnDefNext, btnDefBig) {
radius: buttonRadius;
}
boxShadow: sprite(363px, 50px, 15px, 15px);
boxShadow: icon {{ "box_shadow", windowShadowFg }};
boxShadowShift: 2px;
introCountry: countryInput {
@ -1213,12 +1214,12 @@ btnBotKbHide: iconedButton(btnAttachEmoji) {
downIcon: sprite(373px, 95px, 23px, 14px);
downIconPos: point(5px, 17px);
}
broadcastToggle: flatCheckbox {
silentToggle: flatCheckbox {
textColor: black;
bgColor: white;
disColor: black;
width: 34px;
width: 33px;
height: 46px;
duration: 200;
bgFunc: transition(easeOutCirc);
@ -1226,24 +1227,14 @@ broadcastToggle: flatCheckbox {
font: normalFont;
imageRect: sprite(18px, 125px, 22px, 21px);
chkImageRect: sprite(40px, 125px, 22px, 21px);
overImageRect: sprite(40px, 104px, 22px, 21px);
chkOverImageRect: sprite(40px, 125px, 22px, 21px);
disImageRect: sprite(18px, 125px, 22px, 21px);
chkDisImageRect: sprite(18px, 125px, 22px, 21px);
imagePos: point(6px, 12px);
}
silentToggle: flatCheckbox(broadcastToggle) {
width: 33px;
imageRect: sprite(354px, 242px, 21px, 21px);
chkImageRect: sprite(354px, 221px, 21px, 21px);
overImageRect: sprite(375px, 242px, 21px, 21px);
chkOverImageRect: sprite(375px, 221px, 21px, 21px);
disImageRect: sprite(354px, 242px, 21px, 21px);
chkDisImageRect: sprite(354px, 221px, 21px, 21px);
imagePos: point(6px, 12px);
}
btnRecordAudio: sprite(379px, 390px, 16px, 24px);
btnRecordAudioActive: sprite(379px, 366px, 16px, 24px);
@ -1411,15 +1402,7 @@ btnCancelSearch: iconedButton(btnAddContact) {
downIcon: sprite(188px, 43px, 18px, 18px);
}
notifyBG: white;
notifyBorder: #f1f1f1;
notifyBorderWidth: 1px;
notifySlowHide: 4000;
notifyPhotoSize: 62px;
notifyMacPhotoSize: 64px;
notifyPhotoPos: point(9px, 9px);
notifyClosePos: point(1px, 2px);
notifyClose: iconedButton(btnDefIconed) {
simpleClose: iconedButton(btnDefIconed) {
icon: sprite(167px, 130px, 10px, 10px);
iconPos: point(10px, 10px);
downIcon: sprite(167px, 130px, 10px, 10px);
@ -1428,17 +1411,6 @@ notifyClose: iconedButton(btnDefIconed) {
width: 30px;
height: 30px;
}
notifyItemTop: 12px;
notifyTextLeft: 12px;
notifyTextTop: 7px;
notifySlowHideFunc: transition(easeInCirc);
notifyWaitShortHide: 0;
notifyWaitLongHide: 20000;
notifyFastAnim: 150;
notifyWidth: 316px;
notifyHeight: 80px;
notifyDeltaX: 6px;
notifyDeltaY: 7px;
boxPhotoPadding: margins(28px, 28px, 28px, 18px);
boxPhotoCompressedPadding: margins(0px, 2px, 0px, 22px);
@ -1540,17 +1512,15 @@ dropdownDef: dropdown {
borderColor: #ebebeb;
padding: margins(10px, 10px, 10px, 10px);
shadow: sprite(241px, 46px, 6px, 6px);
shadow: defaultDropdownShadow;
shadowShift: 1px;
duration: 150;
width: 0px;
}
defaultInnerDropdownShadow: icon {{ "dropdown_shadow", windowShadowFg }};
defaultInnerDropdown: InnerDropdown {
padding: margins(10px, 10px, 10px, 10px);
shadow: defaultInnerDropdownShadow;
shadow: defaultDropdownShadow;
shadowShift: 1px;
duration: 150;
@ -1840,7 +1810,7 @@ mvControlSize: 90px;
mvIconSize: size(60px, 56px);
mvDropdown: dropdown(dropdownDef) {
shadow: sprite(0px, 0px, 0px, 0px);
shadow: icon {};
padding: margins(11px, 12px, 11px, 12px);
border: 0px;
@ -1865,7 +1835,7 @@ mvButton: iconedButton(btnDefIconed) {
duration: 0;
}
mvPopupMenu: PopupMenu(defaultPopupMenu) {
shadow: sprite(0px, 0px, 0px, 0px);
shadow: icon {};
itemBg: #383838;
itemBgOver: #505050;
@ -2044,7 +2014,7 @@ sessionInfoFont: msgFont;
sessionInfoColor: #888888;
sessionTerminateTop: 30px;
sessionTerminateSkip: 18px;
sessionTerminate: iconedButton(notifyClose) {
sessionTerminate: iconedButton(simpleClose) {
iconPos: point(3px, 3px);
downIconPos: point(3px, 4px);
width: 16px;
@ -2058,6 +2028,8 @@ webPageDescriptionFont: normalFont;
webPagePhotoSize: 100px;
webPagePhotoDelta: 8px;
mediaPlayerSuppressDuration: 150;
botDescSkip: 8px;
suppressAll: 0.2;

View File

@ -233,7 +233,7 @@ dropdown {
borderColor: color;
padding: margins;
shadow: sprite;
shadow: icon;
shadowShift: pixels;
duration: int;
@ -255,7 +255,7 @@ InnerDropdown {
PopupMenu {
skip: pixels;
shadow: sprite;
shadow: icon;
shadowShift: pixels;
itemBg: color;
@ -273,7 +273,7 @@ PopupMenu {
separatorWidth: pixels;
separatorFg: color;
arrow: sprite;
arrow: icon;
duration: int;

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

View File

@ -244,10 +244,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_settings_show_name" = "Show sender's name";
"lng_settings_show_preview" = "Show message preview";
"lng_settings_use_windows" = "Use Windows notifications";
"lng_settings_use_native_notifications" = "Use native notifications";
"lng_settings_advanced_notifications" = "Notifications position and count";
"lng_settings_notifications_position" = "Location on the screen";
"lng_settings_notifications_count" = "Notifications count";
"lng_settings_sound_notify" = "Play sound";
"lng_settings_include_muted" = "Include muted chats in unread count";
"lng_notification_preview" = "You have a new message";
"lng_notification_reply" = "Reply";
"lng_notification_hide_all" = "Hide all";
"lng_notification_sample" = "This is a sample notification";
"lng_settings_section_general" = "General";
"lng_settings_change_lang" = "Change language";
@ -567,7 +574,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_action_changed_title" = "{from} changed group name to «{title}»";
"lng_action_changed_title_channel" = "Channel name was changed to «{title}»";
"lng_action_created_chat" = "{from} created group «{title}»";
"lng_action_created_channel" = "Channel «{title}» created";
"lng_action_created_channel" = "Channel created";
"lng_action_group_migrate" = "The group was upgraded to a supergroup";
"lng_action_pinned_message" = "{from} pinned «{text}»";
"lng_action_pinned_media" = "{from} pinned {media}";
@ -584,6 +591,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_action_pinned_media_game" = "the game «{game}»";
"lng_action_game_score" = "{from} scored {count:#|#|#} in {game}";
"lng_action_game_you_scored" = "You scored {count:#|#|#} in {game}";
"lng_action_game_score_no_game" = "{from} scored {count:#|#|#}";
"lng_action_game_you_scored_no_game" = "You scored {count:#|#|#}";
"lng_profile_migrate_reached" = "{count:_not_used_|# member|# members} limit reached";
"lng_profile_migrate_body" = "To get over this limit, you can upgrade your group to a supergroup.";

View File

@ -772,12 +772,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_allow_bot" = "허용";
"lng_bot_start" = "시작";
"lng_bot_choose_group" = "Select a Group";
"lng_bot_choose_group" = "그룹방 선택";
"lng_bot_no_groups" = "그룹이 존재하지 않습니다.";
"lng_bot_groups_not_found" = "그룹을 찾을 수 없습니다.";
"lng_bot_sure_invite" = "<<{group}>>에 봇을 추가 하시겠습니까?";
"lng_bot_already_in_group" = "봇이 이미 그룹의 멤버입니다.";
"lng_bot_choose_chat" = "Select a Chat";
"lng_bot_choose_chat" = "채팅방 선택";
"lng_bot_no_chats" = "채팅방이 없습니다.";
"lng_bot_chats_not_found" = "채팅방을 찾 을 수 없음";
"lng_bot_sure_share_game" = "{user}에게 게임을 공유하겠습니까?";
@ -787,10 +787,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_user_typing" = "{user}님이 입력중입니다.";
"lng_users_typing" = "{user}님과 {second_user}님이 입력중입니다.";
"lng_many_typing" = "{count:_not_used_|#명이|#명이} 입력중입니다";
"lng_playing_game" = "playing a game";
"lng_user_playing_game" = "{user} is playing a game";
"lng_users_playing_game" = "{user} and {second_user} are playing a game";
"lng_many_playing_game" = "{count:_not_used_|# is|# are} playing a game";
"lng_playing_game" = "게임 중";
"lng_user_playing_game" = "{user}님이 게임 중입니다.";
"lng_users_playing_game" = "{user}님과 {second_user}님이 게임 중입니다.";
"lng_many_playing_game" = "{count:_not_used_|#명이|#명이} 게임 중입니다";
"lng_send_action_record_video" = "비디오 녹화 중";
"lng_user_action_record_video" = "{user}님이 녹화중입니다";
"lng_send_action_upload_video" = "비디오 전송 중";

View File

@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,8,5
PRODUCTVERSION 0,10,8,5
FILEVERSION 0,10,13,0
PRODUCTVERSION 0,10,13,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.10.8.5"
VALUE "FileVersion", "0.10.13.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.8.5"
VALUE "ProductVersion", "0.10.13.0"
END
END
BLOCK "VarFileInfo"

View File

@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,8,5
PRODUCTVERSION 0,10,8,5
FILEVERSION 0,10,13,0
PRODUCTVERSION 0,10,13,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -43,10 +43,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Updater"
VALUE "FileVersion", "0.10.8.5"
VALUE "FileVersion", "0.10.13.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.8.5"
VALUE "ProductVersion", "0.10.13.0"
END
END
BLOCK "VarFileInfo"

View File

@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "core/single_timer.h"
class ApiWrap : public QObject, public RPCSender {
Q_OBJECT

View File

@ -42,6 +42,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "numbers.h"
#include "observer_peer.h"
#include "window/chat_background.h"
#include "window/notifications_manager.h"
namespace {
App::LaunchState _launchState = App::Launched;
@ -1991,13 +1992,10 @@ namespace {
if (::mousedItem == item) {
mousedItem(nullptr);
}
if (App::wnd()) {
App::wnd()->notifyItemRemoved(item);
}
}
void historyUnregItem(HistoryItem *item) {
MsgsData *data = fetchMsgsData(item->channelId(), false);
auto data = fetchMsgsData(item->channelId(), false);
if (!data) return;
auto i = data->find(item->id);
@ -2013,10 +2011,13 @@ namespace {
std::swap(items, j.value());
::dependentItems.erase(j);
for_const (HistoryItem *dependent, items) {
for_const (auto dependent, items) {
dependent->dependencyItemRemoved(item);
}
}
if (auto manager = Window::Notifications::manager()) {
manager->clearFromItem(item);
}
if (App::main() && !App::quitting()) {
App::main()->itemRemoved(item);
}

View File

@ -28,6 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "lang.h"
#include "boxes/confirmbox.h"
#include "ui/filedialog.h"
#include "ui/popupmenu.h"
#include "langloaderplain.h"
#include "localstorage.h"
#include "autoupdater.h"
@ -35,6 +36,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "observer_peer.h"
#include "window/chat_background.h"
#include "media/player/media_player_instance.h"
#include "window/notifications_manager.h"
#include "history/history_location_manager.h"
namespace {
@ -303,9 +305,8 @@ void Application::readClients() {
if (!startUrl.isEmpty()) {
cSetStartUrl(startUrl);
}
if (!cStartUrl().isEmpty() && App::main() && App::self()) {
App::main()->openLocalUrl(cStartUrl());
cSetStartUrl(QString());
if (auto main = App::main()) {
main->checkStartUrl();
}
}
@ -332,8 +333,11 @@ void Application::closeApplication() {
if (App::launchState() == App::QuitProcessed) return;
App::setLaunchState(App::QuitProcessed);
delete AppObject;
AppObject = 0;
if (auto manager = Window::Notifications::manager()) {
manager->clearAllFast();
}
delete base::take(AppObject);
Sandbox::finish();
@ -729,6 +733,7 @@ AppClass::AppClass() : QObject()
anim::startManager();
historyInit();
Media::Player::start();
Window::Notifications::start();
DEBUG_LOG(("Application Info: inited..."));
@ -742,7 +747,8 @@ AppClass::AppClass() : QObject()
DEBUG_LOG(("Application Info: starting app..."));
QMimeDatabase().mimeTypeForName(qsl("text/plain")); // create mime database
// Create mime database, so it won't be slow later.
QMimeDatabase().mimeTypeForName(qsl("text/plain"));
_window = new MainWindow();
_window->createWinId();
@ -1080,8 +1086,8 @@ void AppClass::checkMapVersion() {
if (Local::oldMapVersion() < AppVersion) {
if (Local::oldMapVersion()) {
QString versionFeatures;
if ((cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 10003) {
versionFeatures = QString::fromUtf8("\xe2\x80\x94 New cute design for the Settings page");
if ((cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 10012) {
versionFeatures = QString::fromUtf8("Windows and Linux:\n\xe2\x80\x94 Quick reply from notifications\n\xe2\x80\x94 Hide all notifications button added\n\xe2\x80\x94 Change notifications location and maximum count\n\nLinux:\n\xe2\x80\x94 You can enable native notifications in Settings");
} else if (!(cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 10005) {
versionFeatures = langNewVersionText();
} else {
@ -1098,8 +1104,9 @@ void AppClass::checkMapVersion() {
AppClass::~AppClass() {
Shortcuts::finish();
auto window = createAndSwap(_window);
delete window;
delete base::take(_window);
Window::Notifications::finish();
anim::stopManager();
@ -1110,8 +1117,8 @@ AppClass::~AppClass() {
MTP::finish();
AppObject = nullptr;
deleteAndMark(_uploader);
deleteAndMark(_translator);
delete base::take(_uploader);
delete base::take(_translator);
Window::chatBackground()->reset();
@ -1128,9 +1135,9 @@ AppClass *AppClass::app() {
}
MainWindow *AppClass::wnd() {
return AppObject ? AppObject->_window : 0;
return AppObject ? AppObject->_window : nullptr;
}
MainWidget *AppClass::main() {
return (AppObject && AppObject->_window) ? AppObject->_window->mainWidget() : 0;
return (AppObject && AppObject->_window) ? AppObject->_window->mainWidget() : nullptr;
}

View File

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mainwindow.h"
#include "pspecific.h"
#include "core/single_timer.h"
class UpdateChecker;
class Application : public QApplication {

View File

@ -160,7 +160,7 @@ void AbstractBox::resizeMaxHeight(int32 newWidth, int32 maxHeight) {
move(r.left(), newTop);
}
}
parentWidget()->update(geometry().united(g).marginsAdded(QMargins(st::boxShadow.pxWidth(), st::boxShadow.pxHeight(), st::boxShadow.pxWidth(), st::boxShadow.pxHeight())));
parentWidget()->update(geometry().united(g).marginsAdded(QMargins(st::boxShadow.width(), st::boxShadow.height(), st::boxShadow.width(), st::boxShadow.height())));
}
}
}

View File

@ -1405,7 +1405,7 @@ void RevokePublicLinkBox::mousePressEvent(QMouseEvent *e) {
}
void RevokePublicLinkBox::mouseReleaseEvent(QMouseEvent *e) {
auto pressed = createAndSwap(_pressed);
auto pressed = base::take(_pressed);
setCursor((_selected || _pressed) ? style::cur_pointer : style::cur_default);
if (pressed && pressed == _selected) {
auto text_method = pressed->isMegagroup() ? lng_channels_too_much_public_revoke_confirm_group : lng_channels_too_much_public_revoke_confirm_channel;

View File

@ -89,3 +89,24 @@ shareColumnSkip: 6px;
shareSelectDuration: 150;
shareActivateDuration: 150;
shareScrollDuration: 300;
notificationsBoxHeight: 450px;
notificationsBoxMonitorTop: 63px;
notificationsBoxMonitor: icon {{ "monitor", #000000 }};
notificationsBoxScreenTop: 10px;
notificationsBoxScreenSize: size(280px, 160px);
notificationsBoxScreenBg: titleBg;
notificationsBoxCountLabelTop: 80px;
notificationsBoxCountTop: 30px;
notificationsSampleSkip: 5px;
notificationsSampleTopSkip: 5px;
notificationsSampleBottomSkip: 5px;
notificationsSampleMargin: 2px;
notificationSampleOpacity: 0.5;
notificationSampleSize: size(64px, 16px);
notificationSampleUserpicFg: #40ace3;
notificationSampleCloseFg: #d7d7d7;
notificationSampleTextFg: #d7d7d7;
notificationSampleNameFg: #939393;

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#include "abstractbox.h"
#include "core/single_timer.h"
namespace Dialogs {
class Row;

View File

@ -0,0 +1,421 @@
/*
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
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "boxes/notifications_box.h"
#include "lang.h"
#include "ui/buttons/round_button.h"
#include "ui/widgets/discrete_slider.h"
#include "styles/style_boxes.h"
#include "styles/style_dialogs.h"
#include "styles/style_window.h"
#include "application.h"
#include "localstorage.h"
namespace {
constexpr int kMaxNotificationsCount = 5;
} // namespace
class NotificationsBox::SampleWidget : public QWidget {
public:
SampleWidget(NotificationsBox *owner, const QPixmap &cache) : QWidget(nullptr)
, _owner(owner)
, _cache(cache) {
resize(cache.width() / cache.devicePixelRatio(), cache.height() / cache.devicePixelRatio());
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
setAttribute(Qt::WA_TransparentForMouseEvents);
setAttribute(Qt::WA_OpaquePaintEvent);
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint);
setWindowOpacity(0.);
show();
}
void detach() {
_owner = nullptr;
hideFast();
}
void showFast() {
_hiding = false;
startAnimation();
}
void hideFast() {
_hiding = true;
startAnimation();
}
protected:
virtual void paintEvent(QPaintEvent *e) {
Painter p(this);
p.drawPixmap(0, 0, _cache);
}
private:
void startAnimation() {
_opacity.start([this] { animationCallback(); }, _hiding ? 1. : 0., _hiding ? 0. : 1., st::notifyFastAnim);
}
void animationCallback() {
setWindowOpacity(_opacity.current(_hiding ? 0. : 1.));
if (!_opacity.animating() && _hiding) {
if (_owner) {
_owner->removeSample(this);
}
hide();
destroyDelayed();
}
}
void destroyDelayed() {
if (_deleted) return;
_deleted = true;
// Ubuntu has a lag if deleteLater() called immediately.
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
QTimer::singleShot(1000, [this] { delete this; });
#else // Q_OS_LINUX32 || Q_OS_LINUX64
deleteLater();
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
}
NotificationsBox *_owner;
QPixmap _cache;
FloatAnimation _opacity;
bool _hiding = false;
bool _deleted = false;
};
NotificationsBox::NotificationsBox() : AbstractBox()
, _chosenCorner(Global::NotificationsCorner())
, _oldCount(snap(Global::NotificationsCount(), 1, kMaxNotificationsCount))
, _countSlider(this)
, _done(this, lang(lng_about_done), st::defaultBoxButton) {
_sampleOpacities.reserve(kMaxNotificationsCount);
for (int i = 0; i != kMaxNotificationsCount; ++i) {
_countSlider->addSection(QString::number(i + 1));
_sampleOpacities.push_back(FloatAnimation());
}
_countSlider->setActiveSectionFast(_oldCount - 1);
_countSlider->setSectionActivatedCallback([this] { countChanged(); });
setMouseTracking(true);
_done->setClickedCallback([this] { onClose(); });
prepareNotificationSampleSmall();
prepareNotificationSampleLarge();
setMaxHeight(st::notificationsBoxHeight);
prepare();
}
void NotificationsBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (paint(p)) return;
auto contentLeft = getContentLeft();
p.setFont(st::boxTitleFont);
p.setPen(st::boxTitleFg);
p.drawTextLeft(contentLeft, st::boxTitlePosition.y(), width(), lang(lng_settings_notifications_position));
auto screenRect = getScreenRect();
p.fillRect(screenRect.x(), screenRect.y(), st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height(), st::notificationsBoxScreenBg);
auto monitorTop = st::notificationsBoxMonitorTop;
st::notificationsBoxMonitor.paint(p, contentLeft, monitorTop, width());
for (int corner = 0; corner != 4; ++corner) {
auto screenCorner = static_cast<Notify::ScreenCorner>(corner);
auto isLeft = Notify::IsLeftCorner(screenCorner);
auto isTop = Notify::IsTopCorner(screenCorner);
auto sampleLeft = isLeft ? (screenRect.x() + st::notificationsSampleSkip) : (screenRect.x() + screenRect.width() - st::notificationsSampleSkip - st::notificationSampleSize.width());
auto sampleTop = isTop ? (screenRect.y() + st::notificationsSampleTopSkip) : (screenRect.y() + screenRect.height() - st::notificationsSampleBottomSkip - st::notificationSampleSize.height());
if (corner == static_cast<int>(_chosenCorner)) {
auto count = currentCount();
for (int i = 0; i != kMaxNotificationsCount; ++i) {
auto opacity = _sampleOpacities[i].current(getms(), (i < count) ? 1. : 0.);
p.setOpacity(opacity);
p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall);
sampleTop += (isTop ? 1 : -1) * (st::notificationSampleSize.height() + st::notificationsSampleMargin);
}
} else {
p.setOpacity(st::notificationSampleOpacity);
p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall);
p.setOpacity(1.);
}
}
auto labelTop = screenRect.y() + screenRect.height() + st::notificationsBoxCountLabelTop;
p.drawTextLeft(contentLeft, labelTop, width(), lang(lng_settings_notifications_count));
}
void NotificationsBox::countChanged() {
auto count = currentCount();
auto moreSamples = (count > _oldCount);
auto from = moreSamples ? 0. : 1.;
auto to = moreSamples ? 1. : 0.;
auto indexDelta = moreSamples ? 1 : -1;
auto animatedDelta = moreSamples ? 0 : -1;
for (; _oldCount != count; _oldCount += indexDelta) {
_sampleOpacities[_oldCount + animatedDelta].start([this] { update(); }, from, to, st::notifyFastAnim);
}
if (currentCount() != Global::NotificationsCount()) {
Global::SetNotificationsCount(currentCount());
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::MaxCount);
Local::writeUserSettings();
}
}
int NotificationsBox::getContentLeft() const {
return (width() - st::notificationsBoxMonitor.width()) / 2;
}
QRect NotificationsBox::getScreenRect() const {
auto screenLeft = (width() - st::notificationsBoxScreenSize.width()) / 2;
auto screenTop = st::notificationsBoxMonitorTop + st::notificationsBoxScreenTop;
return QRect(screenLeft, screenTop, st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height());
}
void NotificationsBox::resizeEvent(QResizeEvent *e) {
_done->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _done->height());
auto screenRect = getScreenRect();
auto sliderTop = screenRect.y() + screenRect.height() + st::notificationsBoxCountLabelTop + st::notificationsBoxCountTop;
auto contentLeft = getContentLeft();
_countSlider->resizeToWidth(width() - 2 * contentLeft);
_countSlider->move(contentLeft, sliderTop);
AbstractBox::resizeEvent(e);
}
void NotificationsBox::prepareNotificationSampleSmall() {
auto width = st::notificationSampleSize.width();
auto height = st::notificationSampleSize.height();
auto sampleImage = QImage(width * cIntRetinaFactor(), height * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
sampleImage.setDevicePixelRatio(cRetinaFactor());
sampleImage.fill(st::notifyBg->c);
{
Painter p(&sampleImage);
p.setPen(Qt::NoPen);
p.setRenderHint(QPainter::HighQualityAntialiasing);
auto padding = height / 8;
auto userpicSize = height - 2 * padding;
p.setBrush(st::notificationSampleUserpicFg);
p.drawEllipse(rtlrect(padding, padding, userpicSize, userpicSize, width));
auto rowLeft = height;
auto rowHeight = padding;
auto nameTop = (height - 5 * padding) / 2;
auto nameWidth = height;
p.setBrush(st::notificationSampleNameFg);
p.drawRoundedRect(rtlrect(rowLeft, nameTop, nameWidth, rowHeight, width), rowHeight / 2, rowHeight / 2);
auto rowWidth = (width - rowLeft - 3 * padding);
auto rowTop = nameTop + rowHeight + padding;
p.setBrush(st::notificationSampleTextFg);
p.drawRoundedRect(rtlrect(rowLeft, rowTop, rowWidth, rowHeight, width), rowHeight / 2, rowHeight / 2);
rowTop += rowHeight + padding;
p.drawRoundedRect(rtlrect(rowLeft, rowTop, rowWidth, rowHeight, width), rowHeight / 2, rowHeight / 2);
auto closeLeft = width - 2 * padding;
p.fillRect(rtlrect(closeLeft, padding, padding, padding, width), st::notificationSampleCloseFg);
}
_notificationSampleSmall = App::pixmapFromImageInPlace(std_::move(sampleImage));
_notificationSampleSmall.setDevicePixelRatio(cRetinaFactor());
}
void NotificationsBox::prepareNotificationSampleUserpic() {
if (_notificationSampleUserpic.isNull()) {
_notificationSampleUserpic = App::pixmapFromImageInPlace(App::wnd()->iconLarge().scaled(st::notifyPhotoSize * cIntRetinaFactor(), st::notifyPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
_notificationSampleUserpic.setDevicePixelRatio(cRetinaFactor());
}
}
void NotificationsBox::prepareNotificationSampleLarge() {
int w = st::notifyWidth, h = st::notifyMinHeight;
auto sampleImage = QImage(w * cIntRetinaFactor(), h * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
sampleImage.setDevicePixelRatio(cRetinaFactor());
sampleImage.fill(st::notifyBg->c);
{
Painter p(&sampleImage);
p.fillRect(0, 0, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(w - st::notifyBorderWidth, 0, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
prepareNotificationSampleUserpic();
p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), _notificationSampleUserpic);
int itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width;
auto rectForName = rtlrect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height, w);
auto notifyText = st::dialogsTextFont->elided(lang(lng_notification_sample), itemWidth);
p.setFont(st::dialogsTextFont);
p.setPen(st::dialogsTextFgService);
p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText);
p.setPen(st::dialogsNameFg);
p.setFont(st::msgNameFont);
auto notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width());
p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle);
p.setOpacity(st::notifyClose.opacity);
p.drawSpriteLeft(w - st::notifyClosePos.x() - st::notifyClose.width + st::notifyClose.iconPos.x(), st::notifyClosePos.y() + st::notifyClose.iconPos.y(), w, st::notifyClose.icon);
}
_notificationSampleLarge = App::pixmapFromImageInPlace(std_::move(sampleImage));
}
void NotificationsBox::removeSample(SampleWidget *widget) {
for (auto &samples : _cornerSamples) {
for (int i = 0, size = samples.size(); i != size; ++i) {
if (samples[i] == widget) {
for (int j = i + 1; j != size; ++j) {
samples[j]->detach();
}
samples.resize(i);
break;
}
}
}
}
void NotificationsBox::mouseMoveEvent(QMouseEvent *e) {
auto screenRect = getScreenRect();
auto cornerWidth = screenRect.width() / 3;
auto cornerHeight = screenRect.height() / 3;
auto topLeft = rtlrect(screenRect.x(), screenRect.y(), cornerWidth, cornerHeight, width());
auto topRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y(), cornerWidth, cornerHeight, width());
auto bottomRight = rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width());
auto bottomLeft = rtlrect(screenRect.x(), screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width());
if (topLeft.contains(e->pos())) {
setOverCorner(Notify::ScreenCorner::TopLeft);
} else if (topRight.contains(e->pos())) {
setOverCorner(Notify::ScreenCorner::TopRight);
} else if (bottomRight.contains(e->pos())) {
setOverCorner(Notify::ScreenCorner::BottomRight);
} else if (bottomLeft.contains(e->pos())) {
setOverCorner(Notify::ScreenCorner::BottomLeft);
} else {
clearOverCorner();
}
}
void NotificationsBox::leaveEvent(QEvent *e) {
clearOverCorner();
}
void NotificationsBox::setOverCorner(Notify::ScreenCorner corner) {
if (_isOverCorner) {
if (corner == _overCorner) {
return;
}
for_const (auto widget, _cornerSamples[static_cast<int>(_overCorner)]) {
widget->hideFast();
}
} else {
_isOverCorner = true;
setCursor(style::cur_pointer);
Global::SetNotificationsDemoIsShown(true);
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DemoIsShown);
}
_overCorner = corner;
auto &samples = _cornerSamples[static_cast<int>(_overCorner)];
auto samplesAlready = samples.size();
auto samplesNeeded = currentCount();
auto samplesLeave = qMin(samplesAlready, samplesNeeded);
for (int i = 0; i != samplesLeave; ++i) {
samples[i]->showFast();
}
if (samplesNeeded > samplesLeave) {
auto r = psDesktopRect();
auto isLeft = Notify::IsLeftCorner(_overCorner);
auto isTop = Notify::IsTopCorner(_overCorner);
auto sampleLeft = (isLeft == rtl()) ? (r.x() + r.width() - st::notifyWidth - st::notifyDeltaX) : (r.x() + st::notifyDeltaX);
auto sampleTop = isTop ? (r.y() + st::notifyDeltaY) : (r.y() + r.height() - st::notifyDeltaY - st::notifyMinHeight);
for (int i = samplesLeave; i != samplesNeeded; ++i) {
auto widget = std_::make_unique<SampleWidget>(this, _notificationSampleLarge);
widget->move(sampleLeft, sampleTop + (isTop ? 1 : -1) * i * (st::notifyMinHeight + st::notifyDeltaY));
widget->showFast();
samples.push_back(widget.release());
}
} else {
for (int i = samplesLeave; i != samplesAlready; ++i) {
samples[i]->hideFast();
}
}
}
void NotificationsBox::clearOverCorner() {
if (_isOverCorner) {
_isOverCorner = false;
setCursor(style::cur_default);
Global::SetNotificationsDemoIsShown(false);
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::DemoIsShown);
for_const (auto &samples, _cornerSamples) {
for_const (auto widget, samples) {
widget->hideFast();
}
}
}
}
int NotificationsBox::currentCount() const {
return _countSlider->activeSection() + 1;
}
void NotificationsBox::mousePressEvent(QMouseEvent *e) {
_isDownCorner = _isOverCorner;
_downCorner = _overCorner;
}
void NotificationsBox::mouseReleaseEvent(QMouseEvent *e) {
auto isDownCorner = base::take(_isDownCorner);
if (isDownCorner && _isOverCorner && _downCorner == _overCorner && _downCorner != _chosenCorner) {
_chosenCorner = _downCorner;
update();
if (_chosenCorner != Global::NotificationsCorner()) {
Global::SetNotificationsCorner(_chosenCorner);
Global::RefNotifySettingsChanged().notify(Notify::ChangeType::Corner);
Local::writeUserSettings();
}
}
}
NotificationsBox::~NotificationsBox() {
for_const (auto &samples, _cornerSamples) {
for_const (auto widget, samples) {
widget->detach();
}
}
clearOverCorner();
}

View File

@ -0,0 +1,79 @@
/*
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
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "abstractbox.h"
class BoxButton;
class LinkButton;
namespace Ui {
class DiscreteSlider;
} // namespace Ui
class NotificationsBox : public AbstractBox {
public:
NotificationsBox();
~NotificationsBox();
protected:
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void leaveEvent(QEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
private:
using ScreenCorner = Notify::ScreenCorner;
void countChanged();
void setOverCorner(ScreenCorner corner);
void clearOverCorner();
class SampleWidget;
void removeSample(SampleWidget *widget);
int currentCount() const;
QRect getScreenRect() const;
int getContentLeft() const;
void prepareNotificationSampleSmall();
void prepareNotificationSampleLarge();
void prepareNotificationSampleUserpic();
QPixmap _notificationSampleUserpic;
QPixmap _notificationSampleSmall;
QPixmap _notificationSampleLarge;
ScreenCorner _chosenCorner;
std_::vector_of_moveable<FloatAnimation> _sampleOpacities;
bool _isOverCorner = false;
ScreenCorner _overCorner = ScreenCorner::TopLeft;
bool _isDownCorner = false;
ScreenCorner _downCorner = ScreenCorner::TopLeft;
int _oldCount;
ChildWidget<Ui::DiscreteSlider> _countSlider;
ChildWidget<BoxButton> _done;
QVector<SampleWidget*> _cornerSamples[4];
};

View File

@ -83,11 +83,11 @@ void ReportBox::onChange() {
connect(_reasonOtherText, SIGNAL(submitted(bool)), this, SLOT(onReport()));
connect(_reasonOtherText, SIGNAL(cancelled()), this, SLOT(onClose()));
}
_reasonOtherText->setFocus();
} else if (_reasonOtherText) {
_reasonOtherText.destroy();
updateMaxHeight();
}
_reasonOtherText->setFocus();
}
void ReportBox::doSetInnerFocus() {

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#include "abstractbox.h"
#include "core/single_timer.h"
class ConfirmBox;

View File

@ -337,7 +337,7 @@ private:
int _dragging = -1;
int _above = -1;
BoxShadow _aboveShadow;
Ui::RectShadow _aboveShadow;
int32 _scrollbar = 0;
};

View File

@ -769,10 +769,6 @@ structure::Value ParsedFile::readIconValue() {
}
}
if (parts.empty()) {
logErrorUnexpectedToken() << "at least one icon part";
return {};
}
return { structure::data::icon { parts } };
}
file_.putBack();

View File

@ -97,9 +97,6 @@ enum {
MediaOverviewStartPerPage = 5,
MediaOverviewPreloadCount = 4,
// a new message from the same sender is attached to previous within 15 minutes
AttachMessageToPreviousSecondsDelta = 900,
AudioSimultaneousLimit = 4,
AudioCheckPositionTimeout = 100, // 100ms per check audio pos
AudioCheckPositionDelta = 2400, // update position called each 2400 samples
@ -215,7 +212,7 @@ Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n\
8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n\
Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n\
-----END RSA PUBLIC KEY-----"};
keysCount = arraysize(keys);
keysCount = base::array_size(keys);
return keys;
}
@ -292,6 +289,10 @@ static const int32 ApiId = 17349;
static const char *ApiHash = "344583e45741c457fe1862106095a5eb";
#endif
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
#error "Only little endian is supported!"
#endif // Q_BYTE_ORDER == Q_BIG_ENDIAN
#ifndef BETA_VERSION_MACRO
#error "Beta version macro is not defined."
#endif
@ -375,9 +376,7 @@ enum {
WaitForChannelGetDifference = 1000, // 1s wait after show channel history before sending getChannelDifference
MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory
NotifyWindowsCount = 3, // 3 desktop notifies at the same time
NotifySettingSaveTimeout = 1000, // wait 1 second before saving notify setting to server
NotifyDeletePhotoAfter = 60000, // delete notify photo after 1 minute
UpdateChunk = 100 * 1024, // 100kb parts when downloading the update
IdleMsecs = 60 * 1000, // after 60secs without user input we think we are idle

View File

@ -27,6 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/qthelp_regex.h"
#include "core/qthelp_url.h"
#include "localstorage.h"
#include "ui/popupmenu.h"
QString UrlClickHandler::copyToClipboardContextItemText() const {
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);

View File

@ -20,9 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#ifndef OS_MAC_OLD
#include <memory>
#endif // OS_MAC_OLD
#include "core/stl_subset.h"
namespace base {
namespace internal {
@ -392,191 +390,3 @@ public:
};
} // namespace base
// While we still use rpcDone() and rpcFail()
#include "mtproto/rpc_sender.h"
template <typename FunctionType>
struct LambdaUniqueHelper;
template <typename Lambda, typename R, typename ...Args>
struct LambdaUniqueHelper<R(Lambda::*)(Args...) const> {
using UniqueType = base::lambda_unique<R(Args...)>;
};
template <typename FunctionType>
using LambdaGetUnique = typename LambdaUniqueHelper<FunctionType>::UniqueType;
template <typename Base, typename FunctionType>
class RPCHandlerImplementation : public Base {
protected:
using Lambda = base::lambda_unique<FunctionType>;
using Parent = RPCHandlerImplementation<Base, FunctionType>;
public:
RPCHandlerImplementation(Lambda &&handler) : _handler(std_::move(handler)) {
}
protected:
Lambda _handler;
};
template <typename FunctionType>
using RPCDoneHandlerImplementation = RPCHandlerImplementation<RPCAbstractDoneHandler, FunctionType>;
template <typename R>
class RPCDoneHandlerImplementationBare : public RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*)> { // done(from, end)
public:
using RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(from, end) : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationBareReq : public RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*, mtpRequestId)> { // done(from, end, req_id)
public:
using RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*, mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(from, end, requestId) : void(0);
}
};
template <typename R, typename T>
class RPCDoneHandlerImplementationPlain : public RPCDoneHandlerImplementation<R(const T&)> { // done(result)
public:
using RPCDoneHandlerImplementation<R(const T&)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(T(from, end)) : void(0);
}
};
template <typename R, typename T>
class RPCDoneHandlerImplementationReq : public RPCDoneHandlerImplementation<R(const T&, mtpRequestId)> { // done(result, req_id)
public:
using RPCDoneHandlerImplementation<R(const T&, mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(T(from, end), requestId) : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationNo : public RPCDoneHandlerImplementation<R()> { // done()
public:
using RPCDoneHandlerImplementation<R()>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler() : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationNoReq : public RPCDoneHandlerImplementation<R(mtpRequestId)> { // done(req_id)
public:
using RPCDoneHandlerImplementation<R(mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(requestId) : void(0);
}
};
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const mtpPrime*, const mtpPrime*)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBare<R>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const mtpPrime*, const mtpPrime*, mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBareReq<R>(std_::move(lambda)));
}
template <typename R, typename T>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const T&)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationPlain<R, T>(std_::move(lambda)));
}
template <typename R, typename T>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const T&, mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationReq<R, T>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R()> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNo<R>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNoReq<R>(std_::move(lambda)));
}
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
RPCDoneHandlerPtr rpcDone(Lambda &&lambda) {
return rpcDone_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}
template <typename FunctionType>
using RPCFailHandlerImplementation = RPCHandlerImplementation<RPCAbstractFailHandler, FunctionType>;
class RPCFailHandlerImplementationPlain : public RPCFailHandlerImplementation<bool(const RPCError&)> { // fail(error)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return _handler ? _handler(error) : true;
}
};
class RPCFailHandlerImplementationReq : public RPCFailHandlerImplementation<bool(const RPCError&, mtpRequestId)> { // fail(error, req_id)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler(error, requestId) : true;
}
};
class RPCFailHandlerImplementationNo : public RPCFailHandlerImplementation<bool()> { // fail()
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler() : true;
}
};
class RPCFailHandlerImplementationNoReq : public RPCFailHandlerImplementation<bool(mtpRequestId)> { // fail(req_id)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler(requestId) : true;
}
};
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(const RPCError&)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationPlain(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(const RPCError&, mtpRequestId)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationReq(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool()> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationNo(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(mtpRequestId)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationNoReq(std_::move(lambda)));
}
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
RPCFailHandlerPtr rpcFail(Lambda &&lambda) {
return rpcFail_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}

View File

@ -60,7 +60,7 @@ public:
Subscription() = default;
Subscription(const Subscription &) = delete;
Subscription &operator=(const Subscription &) = delete;
Subscription(Subscription &&other) : _node(createAndSwap(other._node)), _removeMethod(other._removeMethod) {
Subscription(Subscription &&other) : _node(base::take(other._node)), _removeMethod(other._removeMethod) {
}
Subscription &operator=(Subscription &&other) {
qSwap(_node, other._node);
@ -258,7 +258,7 @@ public:
private:
void callHandlers() {
_handling = true;
auto events = createAndSwap(_events);
auto events = base::take(_events);
for (auto &event : events) {
this->notifyEnumerate([this, &event]() {
this->_current->handler(event);
@ -305,7 +305,7 @@ public:
private:
void callHandlers() {
_handling = true;
auto eventsCount = createAndSwap(_eventsCount);
auto eventsCount = base::take(_eventsCount);
for (int i = 0; i != eventsCount; ++i) {
this->notifyEnumerate([this]() {
this->_current->handler();
@ -352,7 +352,7 @@ protected:
}
~Subscriber() {
auto subscriptions = createAndSwap(_subscriptions);
auto subscriptions = base::take(_subscriptions);
for (auto &subscription : subscriptions) {
subscription.destroy();
}

View File

@ -0,0 +1,80 @@
/*
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
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "core/single_timer.h"
#include "application.h"
SingleTimer::SingleTimer() {
QTimer::setSingleShot(true);
if (App::app()) {
connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust()));
_inited = true;
}
}
void SingleTimer::setTimeoutHandler(base::lambda_unique<void()> &&handler) {
if (_handler && !handler) {
disconnect(this, SIGNAL(timeout()), this, SLOT(onTimeout()));
} else if (handler && !_handler) {
connect(this, SIGNAL(timeout()), this, SLOT(onTimeout()));
}
_handler = std_::move(handler);
}
void SingleTimer::adjust() {
uint64 n = getms(true);
if (isActive()) {
if (n >= _finishing) {
start(0);
} else {
start(_finishing - n);
}
}
}
void SingleTimer::onTimeout() {
if (_handler) {
_handler();
}
}
void SingleTimer::start(int msec) {
_finishing = getms(true) + (msec < 0 ? 0 : uint64(msec));
if (!_inited && App::app()) {
connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust()));
_inited = true;
}
QTimer::start(msec);
}
void SingleTimer::startIfNotActive(int msec) {
if (isActive()) {
int remains = remainingTime();
if (remains > msec) {
start(msec);
} else if (!remains) {
start(1);
}
} else {
start(msec);
}
}

View File

@ -0,0 +1,50 @@
/*
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
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "core/basic_types.h"
#include "core/lambda_wrap.h"
class SingleTimer : public QTimer { // single shot timer with check
Q_OBJECT
public:
SingleTimer();
void setSingleShot(bool); // is not available
void start(); // is not available
void setTimeoutHandler(base::lambda_unique<void()> &&handler);
public slots:
void start(int msec);
void startIfNotActive(int msec);
private slots:
void adjust();
void onTimeout();
private:
uint64 _finishing = 0;
bool _inited = false;
base::lambda_unique<void()> _handler;
};

View File

@ -345,36 +345,6 @@ uint64 getms(bool checked) {
#endif
}
SingleTimer::SingleTimer() : _finishing(0), _inited(false) {
QTimer::setSingleShot(true);
if (App::app()) {
connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust()));
_inited = true;
}
}
void SingleTimer::start(int msec) {
_finishing = getms(true) + (msec < 0 ? 0 : uint64(msec));
if (!_inited && App::app()) {
connect(App::app(), SIGNAL(adjustSingleTimers()), this, SLOT(adjust()));
_inited = true;
}
QTimer::start(msec);
}
void SingleTimer::startIfNotActive(int msec) {
if (isActive()) {
int remains = remainingTime();
if (remains > msec) {
start(msec);
} else if (!remains) {
start(1);
}
} else {
start(msec);
}
}
uint64 msgid() {
#ifdef Q_OS_WIN
LARGE_INTEGER li;

View File

@ -22,23 +22,21 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/basic_types.h"
namespace base {
template <typename T, size_t N>
inline constexpr size_t arraysize(T(&ArrahSizeHelper)[N]) {
inline constexpr size_t array_size(T(&)[N]) {
return N;
}
template <typename T>
void deleteAndMark(T *&link) {
delete link;
link = reinterpret_cast<T*>(0x00000BAD);
inline T take(T &source) {
T result = T();
std_::swap_moveable(result, source);
return std_::move(result);
}
template <typename T>
T *getPointerAndReset(T *&ptr) {
T *result = nullptr;
qSwap(result, ptr);
return result;
}
} // namespace base
template <typename Enum>
inline QFlags<Enum> qFlags(Enum v) {
@ -87,13 +85,6 @@ inline void accumulate_max(T &a, const T &b) { if (a < b) a = b; }
template <typename T>
inline void accumulate_min(T &a, const T &b) { if (a > b) a = b; }
template <typename T>
T createAndSwap(T &value) {
T result = T();
std_::swap_moveable(result, value);
return std_::move(result);
}
static volatile int *t_assert_nullptr = nullptr;
inline void t_noop() {}
inline void t_assert_fail(const char *message, const char *file, int32 line) {
@ -172,37 +163,6 @@ void finish();
bool checkms(); // returns true if time has changed
uint64 getms(bool checked = false);
class SingleTimer : public QTimer { // single shot timer with check
Q_OBJECT
public:
SingleTimer();
void setSingleShot(bool); // is not available
void start(); // is not available
public slots:
void start(int msec);
void startIfNotActive(int msec);
void adjust() {
uint64 n = getms(true);
if (isActive()) {
if (n >= _finishing) {
start(0);
} else {
start(_finishing - n);
}
}
}
private:
uint64 _finishing;
bool _inited;
};
const static uint32 _md5_block_size = 64;
class HashMd5 {
public:
@ -508,7 +468,7 @@ public:
return _p;
}
T *release() {
return getPointerAndReset(_p);
return base::take(_p);
}
void reset(T *p = nullptr) {
delete _p;
@ -551,7 +511,7 @@ public:
return _p;
}
T *release() {
return getPointerAndReset(_p);
return base::take(_p);
}
void reset(T *p = nullptr) {
delete _p;

View File

@ -36,9 +36,9 @@ public:
vector_of_moveable(const vector_of_moveable &other) = delete;
vector_of_moveable &operator=(const vector_of_moveable &other) = delete;
vector_of_moveable(vector_of_moveable &&other)
: _size(createAndSwap(other._size))
, _capacity(createAndSwap(other._capacity))
, _plaindata(createAndSwap(other._plaindata)) {
: _size(base::take(other._size))
, _capacity(base::take(other._capacity))
, _plaindata(base::take(other._plaindata)) {
}
vector_of_moveable &operator=(vector_of_moveable &&other) {
std_::swap_moveable(_size, other._size);

View File

@ -22,9 +22,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/utils.h"
#define BETA_VERSION_MACRO (10008005ULL)
#define BETA_VERSION_MACRO (0ULL)
constexpr int AppVersion = 10008;
constexpr str_const AppVersionStr = "0.10.8";
constexpr bool AppAlphaVersion = false;
constexpr int AppVersion = 10013;
constexpr str_const AppVersionStr = "0.10.13";
constexpr bool AppAlphaVersion = true;
constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO;

View File

@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "dialogs/dialogs_layout.h"
#include "styles/style_dialogs.h"
#include "ui/buttons/round_button.h"
#include "ui/popupmenu.h"
#include "data/data_drafts.h"
#include "lang.h"
#include "application.h"
@ -122,8 +123,8 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
p.fillRect(0, 0, w, st::mentionHeight, (selected ? st::mentionBgOver : st::white)->b);
if (!paintingOther) {
if (selected) {
int skip = (st::mentionHeight - st::notifyClose.icon.pxHeight()) / 2;
p.drawSprite(QPoint(w - st::notifyClose.icon.pxWidth() - skip, skip), st::notifyClose.icon);
int skip = (st::mentionHeight - st::simpleClose.icon.pxHeight()) / 2;
p.drawSprite(QPoint(w - st::simpleClose.icon.pxWidth() - skip, skip), st::simpleClose.icon);
}
QString first = (_hashtagFilter.size() < 2) ? QString() : ('#' + _hashtagResults.at(from).mid(0, _hashtagFilter.size() - 1)), second = (_hashtagFilter.size() < 2) ? ('#' + _hashtagResults.at(from)) : _hashtagResults.at(from).mid(_hashtagFilter.size() - 1);
int32 firstwidth = st::mentionFont->width(first), secondwidth = st::mentionFont->width(second);
@ -478,7 +479,6 @@ void DialogsInner::removeDialog(History *history) {
if (importantDialogs) {
history->removeFromChatList(Dialogs::Mode::Important, importantDialogs.get());
}
history->clearNotifications();
if (App::wnd()) App::wnd()->notifyClear(history);
if (contacts->contains(history->peer->id)) {
if (!contactsNoDialogs->contains(history->peer->id)) {

View File

@ -22,7 +22,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "window/section_widget.h"
class MainWidget;
namespace Dialogs {
class Row;
class FakeRow;
@ -33,6 +32,9 @@ namespace Ui {
class RoundButton;
} // namespace Ui
class MainWidget;
class PopupMenu;
enum DialogsSearchRequestType {
DialogsSearchFromStart,
DialogsSearchFromOffset,

View File

@ -122,7 +122,7 @@ void Dropdown::resizeEvent(QResizeEvent *e) {
}
void Dropdown::paintEvent(QPaintEvent *e) {
QPainter p(this);
Painter p(this);
if (_a_appearance.animating()) {
p.setOpacity(a_opacity.current());
@ -358,7 +358,7 @@ void DragArea::setText(const QString &text, const QString &subtext) {
}
void DragArea::paintEvent(QPaintEvent *e) {
QPainter p(this);
Painter p(this);
if (_a_appearance.animating()) {
p.setOpacity(a_opacity.current());

View File

@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#include "ui/twidget.h"
#include "ui/boxshadow.h"
#include "ui/effects/rect_shadow.h"
class Dropdown : public TWidget {
Q_OBJECT
@ -91,7 +91,7 @@ private:
QTimer _hideTimer;
BoxShadow _shadow;
Ui::RectShadow _shadow;
};
@ -101,13 +101,6 @@ class DragArea : public TWidget {
public:
DragArea(QWidget *parent);
void paintEvent(QPaintEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void dragEnterEvent(QDragEnterEvent *e);
void dragLeaveEvent(QDragLeaveEvent *e);
void dropEvent(QDropEvent *e);
void dragMoveEvent(QDragMoveEvent *e);
void setText(const QString &text, const QString &subtext);
void otherEnter();
@ -127,6 +120,14 @@ public:
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
protected:
void paintEvent(QPaintEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void dragEnterEvent(QDragEnterEvent *e) override;
void dragLeaveEvent(QDragLeaveEvent *e) override;
void dropEvent(QDropEvent *e) override;
void dragMoveEvent(QDragMoveEvent *e) override;
signals:
void dropped(const QMimeData *data);
@ -143,7 +144,7 @@ private:
anim::cvalue a_color;
Animation _a_appearance;
BoxShadow _shadow;
Ui::RectShadow _shadow;
QString _text, _subtext;

View File

@ -634,8 +634,10 @@ struct Data {
bool RestoreSoundNotifyFromTray = false;
bool IncludeMuted = true;
DBINotifyView NotifyView = dbinvShowPreview;
bool WindowsNotifications = true;
bool CustomNotifies = (cPlatform() == dbipMac) ? false : true;
bool NativeNotifications = false;
int NotificationsCount = 3;
Notify::ScreenCorner NotificationsCorner = Notify::ScreenCorner::BottomRight;
bool NotificationsDemoIsShown = false;
base::Observable<Notify::ChangeType> NotifySettingsChanged;
DBIConnectionType ConnectionType = dbictAuto;
@ -742,8 +744,10 @@ DefineVar(Global, bool, DesktopNotify);
DefineVar(Global, bool, RestoreSoundNotifyFromTray);
DefineVar(Global, bool, IncludeMuted);
DefineVar(Global, DBINotifyView, NotifyView);
DefineVar(Global, bool, WindowsNotifications);
DefineVar(Global, bool, CustomNotifies);
DefineVar(Global, bool, NativeNotifications);
DefineVar(Global, int, NotificationsCount);
DefineVar(Global, Notify::ScreenCorner, NotificationsCorner);
DefineVar(Global, bool, NotificationsDemoIsShown);
DefineRefVar(Global, base::Observable<Notify::ChangeType>, NotifySettingsChanged);
DefineVar(Global, DBIConnectionType, ConnectionType);

View File

@ -148,9 +148,26 @@ enum class ChangeType {
IncludeMuted,
DesktopEnabled,
ViewParams,
UseNative,
MaxCount,
Corner,
DemoIsShown,
};
enum class ScreenCorner {
TopLeft = 0,
TopRight = 1,
BottomRight = 2,
BottomLeft = 3,
};
inline bool IsLeftCorner(ScreenCorner corner) {
return (corner == ScreenCorner::TopLeft) || (corner == ScreenCorner::BottomLeft);
}
inline bool IsTopCorner(ScreenCorner corner) {
return (corner == ScreenCorner::TopLeft) || (corner == ScreenCorner::TopRight);
}
} // namespace Notify
#define DeclareReadOnlyVar(Type, Name) const Type &Name();
@ -309,8 +326,10 @@ DeclareVar(bool, DesktopNotify);
DeclareVar(bool, RestoreSoundNotifyFromTray);
DeclareVar(bool, IncludeMuted);
DeclareVar(DBINotifyView, NotifyView);
DeclareVar(bool, WindowsNotifications);
DeclareVar(bool, CustomNotifies);
DeclareVar(bool, NativeNotifications);
DeclareVar(int, NotificationsCount);
DeclareVar(Notify::ScreenCorner, NotificationsCorner);
DeclareVar(bool, NotificationsDemoIsShown);
DeclareRefVar(base::Observable<Notify::ChangeType>, NotifySettingsChanged);
DeclareVar(DBIConnectionType, ConnectionType);

View File

@ -1427,7 +1427,6 @@ MsgId History::inboxRead(MsgId upTo) {
showFrom = nullptr;
App::wnd()->notifyClear(this);
clearNotifications();
return upTo;
}

View File

@ -28,13 +28,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
, _scroll(this, st::mentionScroll)
, _inner(this, &_mrows, &_hrows, &_brows, &_srows)
, _chat(0)
, _user(0)
, _channel(0)
, _hiding(false)
, a_opacity(0)
, _a_appearance(animation(this, &FieldAutocomplete::step_appearance))
, _shadow(st::dropdownDef.shadow) {
, _a_appearance(animation(this, &FieldAutocomplete::step_appearance)) {
_hideTimer.setSingleShot(true);
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
@ -605,9 +600,9 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
bool selected = (i == _sel);
if (selected) {
p.fillRect(0, i * st::mentionHeight, width(), st::mentionHeight, st::mentionBgOver->b);
int skip = (st::mentionHeight - st::notifyClose.icon.pxHeight()) / 2;
int skip = (st::mentionHeight - st::simpleClose.icon.pxHeight()) / 2;
if (!_hrows->isEmpty() || (!_mrows->isEmpty() && i < _recentInlineBotsInRows)) {
p.drawSprite(QPoint(width() - st::notifyClose.icon.pxWidth() - skip, i * st::mentionHeight + skip), st::notifyClose.icon);
p.drawSprite(QPoint(width() - st::simpleClose.icon.pxWidth() - skip, i * st::mentionHeight + skip), st::simpleClose.icon);
}
}
p.setPen(st::black->p);

View File

@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#include "ui/twidget.h"
#include "ui/boxshadow.h"
#include "ui/effects/rect_shadow.h"
namespace internal {
@ -91,9 +91,10 @@ public slots:
void showStart();
private:
protected:
void paintEvent(QPaintEvent *e) override;
private:
void updateFiltered(bool resetScroll = false);
void recount(bool resetScroll = false);
@ -108,9 +109,9 @@ private:
ChildWidget<ScrollArea> _scroll;
ChildWidget<internal::FieldAutocompleteInner> _inner;
ChatData *_chat;
UserData *_user;
ChannelData *_channel;
ChatData *_chat = nullptr;
UserData *_user = nullptr;
ChannelData *_channel = nullptr;
EmojiPtr _emoji;
enum class Type {
Mentions,
@ -124,14 +125,13 @@ private:
bool _addInlineBots;
int32 _width, _height;
bool _hiding;
bool _hiding = false;
anim::fvalue a_opacity;
Animation _a_appearance;
QTimer _hideTimer;
BoxShadow _shadow;
friend class internal::FieldAutocompleteInner;
};

View File

@ -28,6 +28,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_dialogs.h"
#include "fileuploader.h"
namespace {
// a new message from the same sender is attached to previous within 15 minutes
constexpr int kAttachMessageToPreviousSecondsDelta = 900;
} // namespace
ReplyMarkupClickHandler::ReplyMarkupClickHandler(const HistoryItem *item, int row, int col)
: _itemId(item->fullId())
, _row(row)
@ -352,7 +359,7 @@ void HistoryMessageReplyMarkup::createFromButtonRows(const QVector<MTPKeyboardBu
if (!b.isEmpty()) {
ButtonRow buttonRow;
buttonRow.reserve(b.size());
for_const (const auto &button, b) {
for_const (auto &button, b) {
switch (button.type()) {
case mtpc_keyboardButton: {
buttonRow.push_back({ Button::Type::Default, qs(button.c_keyboardButton().vtext), QByteArray(), 0 });
@ -401,31 +408,46 @@ void HistoryMessageReplyMarkup::create(const MTPReplyMarkup &markup) {
switch (markup.type()) {
case mtpc_replyKeyboardMarkup: {
const auto &d(markup.c_replyKeyboardMarkup());
auto &d = markup.c_replyKeyboardMarkup();
flags = d.vflags.v;
createFromButtonRows(d.vrows.c_vector().v);
} break;
case mtpc_replyInlineMarkup: {
const auto &d(markup.c_replyInlineMarkup());
auto &d = markup.c_replyInlineMarkup();
flags = MTPDreplyKeyboardMarkup::Flags(0) | MTPDreplyKeyboardMarkup_ClientFlag::f_inline;
createFromButtonRows(d.vrows.c_vector().v);
} break;
case mtpc_replyKeyboardHide: {
const auto &d(markup.c_replyKeyboardHide());
auto &d = markup.c_replyKeyboardHide();
flags = mtpCastFlags(d.vflags) | MTPDreplyKeyboardMarkup_ClientFlag::f_zero;
} break;
case mtpc_replyKeyboardForceReply: {
const auto &d(markup.c_replyKeyboardForceReply());
auto &d = markup.c_replyKeyboardForceReply();
flags = mtpCastFlags(d.vflags) | MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply;
} break;
}
}
void HistoryMessageReplyMarkup::create(const HistoryMessageReplyMarkup &markup) {
flags = markup.flags;
inlineKeyboard = nullptr;
rows.clear();
for_const (auto &row, markup.rows) {
ButtonRow buttonRow;
buttonRow.reserve(row.size());
for_const (auto &button, row) {
buttonRow.push_back({ button.type, button.text, button.data, 0 });
}
if (!buttonRow.isEmpty()) rows.push_back(buttonRow);
}
}
void HistoryMessageUnreadBar::init(int count) {
if (_freezed) return;
_text = lng_unread_bar(lt_count, count);
@ -482,19 +504,19 @@ void HistoryMediaPtr::reset(HistoryMedia *p) {
namespace internal {
TextSelection unshiftSelection(TextSelection selection, const Text &byText) {
if (selection == FullSelection) {
return selection;
}
return ::unshiftSelection(selection, byText);
TextSelection unshiftSelection(TextSelection selection, const Text &byText) {
if (selection == FullSelection) {
return selection;
}
return ::unshiftSelection(selection, byText);
}
TextSelection shiftSelection(TextSelection selection, const Text &byText) {
if (selection == FullSelection) {
return selection;
}
return ::shiftSelection(selection, byText);
TextSelection shiftSelection(TextSelection selection, const Text &byText) {
if (selection == FullSelection) {
return selection;
}
return ::shiftSelection(selection, byText);
}
} // namespace internal
@ -629,7 +651,7 @@ void HistoryItem::recountAttachToPrevious() {
&& !previos->serviceMsg()
&& !previos->isEmpty()
&& previos->from() == from()
&& (qAbs(previos->date.secsTo(date)) < AttachMessageToPreviousSecondsDelta);
&& (qAbs(previos->date.secsTo(date)) < kAttachMessageToPreviousSecondsDelta);
}
}
if (attach && !(_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) {

View File

@ -199,6 +199,7 @@ struct HistoryMessageReplyMarkup : public RuntimeComponent<HistoryMessageReplyMa
}
void create(const MTPReplyMarkup &markup);
void create(const HistoryMessageReplyMarkup &markup);
struct Button {
enum class Type {
@ -436,8 +437,8 @@ private:
namespace internal {
TextSelection unshiftSelection(TextSelection selection, const Text &byText);
TextSelection shiftSelection(TextSelection selection, const Text &byText);
TextSelection unshiftSelection(TextSelection selection, const Text &byText);
TextSelection shiftSelection(TextSelection selection, const Text &byText);
} // namespace internal
@ -758,13 +759,13 @@ public:
}
PeerData *fromOriginal() const {
if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) {
if (auto fwd = Get<HistoryMessageForwarded>()) {
return fwd->_fromOriginal;
}
return from();
}
PeerData *authorOriginal() const {
if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) {
if (auto fwd = Get<HistoryMessageForwarded>()) {
return fwd->_authorOriginal;
}
return author();
@ -837,7 +838,7 @@ public:
void clipCallback(Media::Clip::Notification notification);
virtual ~HistoryItem();
~HistoryItem();
protected:
HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from);
@ -898,6 +899,12 @@ protected:
void recountAttachToPrevious();
const HistoryMessageReplyMarkup *inlineReplyMarkup() const {
return const_cast<HistoryItem*>(this)->inlineReplyMarkup();
}
const ReplyKeyboard *inlineReplyKeyboard() const {
return const_cast<HistoryItem*>(this)->inlineReplyKeyboard();
}
HistoryMessageReplyMarkup *inlineReplyMarkup() {
if (auto markup = Get<HistoryMessageReplyMarkup>()) {
if (markup->flags & MTPDreplyKeyboardMarkup_ClientFlag::f_inline) {
return markup;
@ -905,18 +912,12 @@ protected:
}
return nullptr;
}
const ReplyKeyboard *inlineReplyKeyboard() const {
ReplyKeyboard *inlineReplyKeyboard() {
if (auto markup = inlineReplyMarkup()) {
return markup->inlineKeyboard.get();
}
return nullptr;
}
HistoryMessageReplyMarkup *inlineReplyMarkup() {
return const_cast<HistoryMessageReplyMarkup*>(static_cast<const HistoryItem*>(this)->inlineReplyMarkup());
}
ReplyKeyboard *inlineReplyKeyboard() {
return const_cast<ReplyKeyboard*>(static_cast<const HistoryItem*>(this)->inlineReplyKeyboard());
}
TextSelection toMediaSelection(TextSelection selection) const {
return internal::unshiftSelection(selection, _text);

View File

@ -232,7 +232,7 @@ void HistoryFileMedia::checkAnimationFinished() {
}
HistoryFileMedia::~HistoryFileMedia() {
deleteAndMark(_animation);
delete base::take(_animation);
}
HistoryPhoto::HistoryPhoto(HistoryItem *parent, PhotoData *photo, const QString &caption) : HistoryFileMedia(parent)
@ -2562,7 +2562,7 @@ int HistoryWebPage::resizeGetHeight(int width) {
return _height;
}
_width = width = qMin(width, _maxw);
_width = width/* = qMin(width, _maxw)*/;
width -= st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
int32 linesMax = 5;
@ -2686,9 +2686,9 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, u
} else {
pix = _data->photo->thumb->pixBlurredSingle(ImageRoundRadius::Small, pixw, pixh, pw, ph);
}
p.drawPixmapLeft(padding.left() + width - pw, 0, _width, pix);
p.drawPixmapLeft(padding.left() + width - pw, tshift, _width, pix);
if (selected) {
App::roundRect(p, rtlrect(padding.left() + width - pw, 0, pw, _pixh, _width), textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners);
App::roundRect(p, rtlrect(padding.left() + width - pw, tshift, pw, _pixh, _width), textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners);
}
width -= pw + st::webPagePhotoDelta;
}

View File

@ -309,7 +309,7 @@ struct HistoryDocumentVoice : public RuntimeComponent<HistoryDocumentVoice> {
return *this;
}
~HistoryDocumentVoice() {
deleteAndMark(_playback);
delete base::take(_playback);
}
void ensurePlayback(const HistoryDocument *interfaces) const;
void checkPlaybackFinished() const;

View File

@ -366,7 +366,7 @@ HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg)
CreateConfig config;
if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) {
const auto &f(msg.vfwd_from.c_messageFwdHeader());
auto &f = msg.vfwd_from.c_messageFwdHeader();
if (f.has_from_id() || f.has_channel_id()) {
config.authorIdOriginal = f.has_channel_id() ? peerFromChannel(f.vchannel_id) : peerFromUser(f.vfrom_id);
config.fromIdOriginal = f.has_from_id() ? peerFromUser(f.vfrom_id) : peerFromChannel(f.vchannel_id);
@ -376,7 +376,7 @@ HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg)
if (msg.has_reply_to_msg_id()) config.replyTo = msg.vreply_to_msg_id.v;
if (msg.has_via_bot_id()) config.viaBotId = msg.vvia_bot_id.v;
if (msg.has_views()) config.viewsCount = msg.vviews.v;
if (msg.has_reply_markup()) config.markup = &msg.vreply_markup;
if (msg.has_reply_markup()) config.mtpMarkup = &msg.vreply_markup;
if (msg.has_edit_date()) config.editDate = ::date(msg.vedit_date);
createComponents(config);
@ -435,9 +435,15 @@ HistoryMessage::HistoryMessage(History *history, MsgId id, MTPDmessage::Flags fl
config.viewsCount = 1;
}
// Copy inline keyboard when forwarding messages with a game.
auto mediaOriginal = fwd->getMedia();
if (mediaOriginal && mediaOriginal->type() == MediaTypeGame) {
config.inlineMarkup = fwd->inlineReplyMarkup();
}
createComponents(config);
if (HistoryMedia *mediaOriginal = fwd->getMedia()) {
if (mediaOriginal) {
_media.reset(mediaOriginal->clone(this));
}
setText(fwd->originalText());
@ -479,7 +485,7 @@ void HistoryMessage::createComponentsHelper(MTPDmessage::Flags flags, MsgId repl
if (flags & MTPDmessage::Flag::f_via_bot_id) config.viaBotId = viaBotId;
if (flags & MTPDmessage::Flag::f_reply_to_msg_id) config.replyTo = replyTo;
if (flags & MTPDmessage::Flag::f_reply_markup) config.markup = &markup;
if (flags & MTPDmessage::Flag::f_reply_markup) config.mtpMarkup = &markup;
if (isPost()) config.viewsCount = 1;
createComponents(config);
@ -518,8 +524,10 @@ void HistoryMessage::updateMediaInBubbleState() {
_media->setInBubbleState(computeState());
}
bool HistoryMessage::displayEditedBadge(bool hasViaBot) const {
if (!(_flags & MTPDmessage::Flag::f_edit_date)) {
bool HistoryMessage::displayEditedBadge(bool hasViaBotOrInlineMarkup) const {
if (hasViaBotOrInlineMarkup) {
return false;
} else if (!(_flags & MTPDmessage::Flag::f_edit_date)) {
return false;
}
if (auto fromUser = from()->asUser()) {
@ -527,9 +535,6 @@ bool HistoryMessage::displayEditedBadge(bool hasViaBot) const {
return false;
}
}
if (hasViaBot) {
return false;
}
return true;
}
@ -548,20 +553,31 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
if (isPost() && _from->isUser()) {
mask |= HistoryMessageSigned::Bit();
}
if (displayEditedBadge(config.viaBotId != 0)) {
auto hasViaBot = (config.viaBotId != 0);
auto hasInlineMarkup = [&config] {
if (config.mtpMarkup) {
return (config.mtpMarkup->type() == mtpc_replyInlineMarkup);
}
return (config.inlineMarkup != nullptr);
};
if (displayEditedBadge(hasViaBot || hasInlineMarkup())) {
mask |= HistoryMessageEdited::Bit();
}
if (config.authorIdOriginal && config.fromIdOriginal) {
mask |= HistoryMessageForwarded::Bit();
}
if (config.markup) {
if (config.mtpMarkup) {
// optimization: don't create markup component for the case
// MTPDreplyKeyboardHide with flags = 0, assume it has f_zero flag
if (config.markup->type() != mtpc_replyKeyboardHide || config.markup->c_replyKeyboardHide().vflags.v != 0) {
if (config.mtpMarkup->type() != mtpc_replyKeyboardHide || config.mtpMarkup->c_replyKeyboardHide().vflags.v != 0) {
mask |= HistoryMessageReplyMarkup::Bit();
}
} else if (config.inlineMarkup) {
mask |= HistoryMessageReplyMarkup::Bit();
}
UpdateComponents(mask);
if (auto reply = Get<HistoryMessageReply>()) {
reply->replyToMsgId = config.replyTo;
if (!reply->updateData(this) && App::api()) {
@ -586,7 +602,11 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
fwd->_originalId = config.originalId;
}
if (auto markup = Get<HistoryMessageReplyMarkup>()) {
markup->create(*config.markup);
if (config.mtpMarkup) {
markup->create(*config.mtpMarkup);
} else if (config.inlineMarkup) {
markup->create(*config.inlineMarkup);
}
if (markup->flags & MTPDreplyKeyboardMarkup_ClientFlag::f_has_switch_inline_button) {
_flags |= MTPDmessage_ClientFlag::f_has_switch_inline_button;
}
@ -829,7 +849,9 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) {
if (message.has_edit_date()) {
_flags |= MTPDmessage::Flag::f_edit_date;
if (displayEditedBadge(Has<HistoryMessageVia>())) {
auto hasViaBotId = Has<HistoryMessageVia>();
auto hasInlineMarkup = (inlineReplyMarkup() != nullptr);
if (displayEditedBadge(hasViaBotId || hasInlineMarkup)) {
if (!Has<HistoryMessageEdited>()) {
AddComponents(HistoryMessageEdited::Bit());
}
@ -1808,7 +1830,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
case mtpc_messageActionChannelCreate: {
auto &d = action.c_messageActionChannelCreate();
if (isPost()) {
text = lng_action_created_channel(lt_title, textClean(qs(d.vtitle)));
text = lang(lng_action_created_channel);
} else {
text = lng_action_created_chat(lt_from, from, lt_title, textClean(qs(d.vtitle)));
}
@ -2009,12 +2031,21 @@ bool HistoryService::prepareGameScoreText(const QString &from, QString *outText,
gameTitle = lang(lng_contacts_loading);
result = true;
} else {
gameTitle = lang(lng_deleted_message);
gameTitle = QString();
}
auto scoreNumber = gamescore ? gamescore->score : 0;
if (_from->isSelf()) {
*outText = lng_action_game_you_scored(lt_count, gamescore->score, lt_game, gameTitle);
if (gameTitle.isEmpty()) {
*outText = lng_action_game_you_scored_no_game(lt_count, scoreNumber);
} else {
*outText = lng_action_game_you_scored(lt_count, scoreNumber, lt_game, gameTitle);
}
} else {
*outText = lng_action_game_score(lt_from, from, lt_count, gamescore->score, lt_game, gameTitle);
if (gameTitle.isEmpty()) {
*outText = lng_action_game_score_no_game(lt_from, from, lt_count, scoreNumber);
} else {
*outText = lng_action_game_score(lt_from, from, lt_count, scoreNumber, lt_game, gameTitle);
}
}
if (second) {
outLinks->push_back(second);
@ -2212,12 +2243,13 @@ HistoryTextState HistoryService::getState(int x, int y, HistoryStateRequest requ
}
void HistoryService::createFromMtp(const MTPDmessageService &message) {
if (message.vaction.type() == mtpc_messageActionGameScore) {
UpdateComponents(HistoryServiceGameScore::Bit());
Get<HistoryServiceGameScore>()->score = message.vaction.c_messageActionGameScore().vscore.v;
}
if (message.has_reply_to_msg_id()) {
if (message.vaction.type() == mtpc_messageActionPinMessage) {
UpdateComponents(HistoryServicePinned::Bit());
} else if (message.vaction.type() == mtpc_messageActionGameScore) {
UpdateComponents(HistoryServiceGameScore::Bit());
Get<HistoryServiceGameScore>()->score = message.vaction.c_messageActionGameScore().vscore.v;
}
if (auto dependent = GetDependentData()) {
dependent->msgId = message.vreply_to_msg_id.v;

View File

@ -63,7 +63,7 @@ public:
return (!emptyText() || !_media || !_media->isDisplayed() || Has<HistoryMessageReply>() || Has<HistoryMessageForwarded>() || viaBot() || !_media->hideFromName());
}
bool displayEditedBadge(bool hasViaBot) const;
bool displayEditedBadge(bool hasViaBotOrInlineMarkup) const;
bool uploading() const {
return _media && _media->uploading();
}
@ -191,7 +191,12 @@ private:
PeerId fromIdOriginal = 0;
MsgId originalId = 0;
QDateTime editDate;
const MTPReplyMarkup *markup = nullptr;
// For messages created from MTP structs.
const MTPReplyMarkup *mtpMarkup = nullptr;
// For messages created from existing messages (forwarded).
const HistoryMessageReplyMarkup *inlineMarkup = nullptr;
};
void createComponentsHelper(MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, const MTPReplyMarkup &markup);
void createComponents(const CreateConfig &config);

View File

@ -2638,85 +2638,53 @@ void BotKeyboard::updateSelected() {
}
HistoryHider::HistoryHider(MainWidget *parent, bool forwardSelected) : TWidget(parent)
, _sharedContact(0)
, _forwardSelected(forwardSelected)
, _sendPath(false)
, _send(this, lang(lng_forward_send), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, offered(0)
, a_opacity(0, 1)
, _a_appearance(animation(this, &HistoryHider::step_appearance))
, hiding(false)
, _forwardRequest(0)
, toTextWidth(0)
, shadow(st::boxShadow) {
, _shadow(st::boxShadow) {
init();
}
HistoryHider::HistoryHider(MainWidget *parent, UserData *sharedContact) : TWidget(parent)
, _sharedContact(sharedContact)
, _forwardSelected(false)
, _sendPath(false)
, _send(this, lang(lng_forward_send), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, offered(0)
, a_opacity(0, 1)
, _a_appearance(animation(this, &HistoryHider::step_appearance))
, hiding(false)
, _forwardRequest(0)
, toTextWidth(0)
, shadow(st::boxShadow) {
, _shadow(st::boxShadow) {
init();
}
HistoryHider::HistoryHider(MainWidget *parent) : TWidget(parent)
, _sharedContact(0)
, _forwardSelected(false)
, _sendPath(true)
, _send(this, lang(lng_forward_send), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, offered(0)
, a_opacity(0, 1)
, _a_appearance(animation(this, &HistoryHider::step_appearance))
, hiding(false)
, _forwardRequest(0)
, toTextWidth(0)
, shadow(st::boxShadow) {
, _shadow(st::boxShadow) {
init();
}
HistoryHider::HistoryHider(MainWidget *parent, const QString &botAndQuery) : TWidget(parent)
, _sharedContact(0)
, _forwardSelected(false)
, _sendPath(false)
, _botAndQuery(botAndQuery)
, _send(this, lang(lng_forward_send), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, offered(0)
, a_opacity(0, 1)
, _a_appearance(animation(this, &HistoryHider::step_appearance))
, hiding(false)
, _forwardRequest(0)
, toTextWidth(0)
, shadow(st::boxShadow) {
, _shadow(st::boxShadow) {
init();
}
HistoryHider::HistoryHider(MainWidget *parent, const QString &url, const QString &text) : TWidget(parent)
, _sharedContact(0)
, _forwardSelected(false)
, _sendPath(false)
, _shareUrl(url)
, _shareText(text)
, _send(this, lang(lng_forward_send), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, offered(0)
, a_opacity(0, 1)
, _a_appearance(animation(this, &HistoryHider::step_appearance))
, hiding(false)
, _forwardRequest(0)
, toTextWidth(0)
, shadow(st::boxShadow) {
, _shadow(st::boxShadow) {
init();
}
@ -2736,7 +2704,7 @@ void HistoryHider::step_appearance(float64 ms, bool timer) {
if (dt >= 1) {
_a_appearance.stop();
a_opacity.finish();
if (hiding) {
if (_hiding) {
QTimer::singleShot(0, this, SLOT(deleteLater()));
}
} else {
@ -2752,45 +2720,45 @@ bool HistoryHider::withConfirm() const {
void HistoryHider::paintEvent(QPaintEvent *e) {
Painter p(this);
if (!hiding || !cacheForAnim.isNull() || !offered) {
if (!_hiding || !_cacheForAnim.isNull() || !_offered) {
p.setOpacity(a_opacity.current() * st::layerAlpha);
p.fillRect(rect(), st::layerBg->b);
p.setOpacity(a_opacity.current());
}
if (cacheForAnim.isNull() || !offered) {
p.setFont(st::forwardFont->f);
if (offered) {
shadow.paint(p, box, st::boxShadowShift);
if (_cacheForAnim.isNull() || !_offered) {
p.setFont(st::forwardFont);
if (_offered) {
_shadow.paint(p, _box, st::boxShadowShift);
// fill bg
p.fillRect(box, st::boxBg->b);
p.fillRect(_box, st::boxBg);
p.setPen(st::black->p);
toText.drawElided(p, box.left() + st::boxPadding.left(), box.top() + st::boxPadding.top(), toTextWidth + 2);
p.setPen(st::black);
_toText.drawElided(p, _box.left() + st::boxPadding.left(), _box.top() + st::boxPadding.top(), _toTextWidth + 2);
} else {
int32 w = st::forwardMargins.left() + _chooseWidth + st::forwardMargins.right(), h = st::forwardMargins.top() + st::forwardFont->height + st::forwardMargins.bottom();
App::roundRect(p, (width() - w) / 2, (height() - st::titleHeight - h) / 2, w, h, st::forwardBg, ForwardCorners);
p.setPen(st::white->p);
p.drawText(box, lang(_botAndQuery.isEmpty() ? lng_forward_choose : lng_inline_switch_choose), QTextOption(style::al_center));
p.setPen(st::white);
p.drawText(_box, lang(_botAndQuery.isEmpty() ? lng_forward_choose : lng_inline_switch_choose), QTextOption(style::al_center));
}
} else {
p.drawPixmap(box.left(), box.top(), cacheForAnim);
p.drawPixmap(_box.left(), _box.top(), _cacheForAnim);
}
}
void HistoryHider::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape) {
if (offered) {
offered = 0;
resizeEvent(0);
if (_offered) {
_offered = nullptr;
resizeEvent(nullptr);
update();
App::main()->dialogsActivate();
} else {
startHide();
}
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
if (offered) {
if (_offered) {
forward();
}
}
@ -2798,19 +2766,19 @@ void HistoryHider::keyPressEvent(QKeyEvent *e) {
void HistoryHider::mousePressEvent(QMouseEvent *e) {
if (e->button() == Qt::LeftButton) {
if (!box.contains(e->pos())) {
if (!_box.contains(e->pos())) {
startHide();
}
}
}
void HistoryHider::startHide() {
if (hiding) return;
hiding = true;
if (_hiding) return;
_hiding = true;
if (Adaptive::OneColumn()) {
QTimer::singleShot(0, this, SLOT(deleteLater()));
} else {
if (offered) cacheForAnim = myGrab(this, box);
if (_offered) _cacheForAnim = myGrab(this, _box);
if (_forwardRequest) MTP::cancel(_forwardRequest);
a_opacity.start(0);
_send.hide();
@ -2820,17 +2788,17 @@ void HistoryHider::startHide() {
}
void HistoryHider::forward() {
if (!hiding && offered) {
if (!_hiding && _offered) {
if (_sharedContact) {
parent()->onShareContact(offered->id, _sharedContact);
parent()->onShareContact(_offered->id, _sharedContact);
} else if (_sendPath) {
parent()->onSendPaths(offered->id);
parent()->onSendPaths(_offered->id);
} else if (!_shareUrl.isEmpty()) {
parent()->onShareUrl(offered->id, _shareUrl, _shareText);
parent()->onShareUrl(_offered->id, _shareUrl, _shareText);
} else if (!_botAndQuery.isEmpty()) {
parent()->onInlineSwitchChosen(offered->id, _botAndQuery);
parent()->onInlineSwitchChosen(_offered->id, _botAndQuery);
} else {
parent()->onForward(offered->id, _forwardSelected ? ForwardSelectedMessages : ForwardContextMessage);
parent()->onForward(_offered->id, _forwardSelected ? ForwardSelectedMessages : ForwardContextMessage);
}
}
emit forwarded();
@ -2847,8 +2815,8 @@ MainWidget *HistoryHider::parent() {
void HistoryHider::resizeEvent(QResizeEvent *e) {
int32 w = st::boxWidth, h = st::boxPadding.top() + st::boxPadding.bottom();
if (offered) {
if (!hiding) {
if (_offered) {
if (!_hiding) {
_send.show();
_cancel.show();
}
@ -2858,22 +2826,22 @@ void HistoryHider::resizeEvent(QResizeEvent *e) {
_send.hide();
_cancel.hide();
}
box = QRect((width() - w) / 2, (height() - st::titleHeight - h) / 2, w, h);
_send.moveToRight(width() - (box.x() + box.width()) + st::boxButtonPadding.right(), box.y() + h - st::boxButtonPadding.bottom() - _send.height());
_cancel.moveToRight(width() - (box.x() + box.width()) + st::boxButtonPadding.right() + _send.width() + st::boxButtonPadding.left(), _send.y());
_box = QRect((width() - w) / 2, (height() - st::titleHeight - h) / 2, w, h);
_send.moveToRight(width() - (_box.x() + _box.width()) + st::boxButtonPadding.right(), _box.y() + h - st::boxButtonPadding.bottom() - _send.height());
_cancel.moveToRight(width() - (_box.x() + _box.width()) + st::boxButtonPadding.right() + _send.width() + st::boxButtonPadding.left(), _send.y());
}
bool HistoryHider::offerPeer(PeerId peer) {
if (!peer) {
offered = 0;
toText.setText(st::boxTextFont, QString());
toTextWidth = 0;
resizeEvent(0);
_offered = nullptr;
_toText.setText(st::boxTextFont, QString());
_toTextWidth = 0;
resizeEvent(nullptr);
return false;
}
offered = App::peer(peer);
_offered = App::peer(peer);
LangString phrase;
QString recipient = offered->isUser() ? offered->name : '\xAB' + offered->name + '\xBB';
QString recipient = _offered->isUser() ? _offered->name : '\xAB' + _offered->name + '\xBB';
if (_sharedContact) {
phrase = lng_forward_share_contact(lt_recipient, recipient);
} else if (_sendPath) {
@ -2887,35 +2855,35 @@ bool HistoryHider::offerPeer(PeerId peer) {
phrase = lng_forward_send_file_confirm(lt_name, name, lt_recipient, recipient);
}
} else if (!_shareUrl.isEmpty()) {
PeerId to = offered->id;
offered = 0;
PeerId to = _offered->id;
_offered = nullptr;
if (parent()->onShareUrl(to, _shareUrl, _shareText)) {
startHide();
}
return false;
} else if (!_botAndQuery.isEmpty()) {
PeerId to = offered->id;
offered = 0;
PeerId to = _offered->id;
_offered = nullptr;
if (parent()->onInlineSwitchChosen(to, _botAndQuery)) {
startHide();
}
return false;
} else {
PeerId to = offered->id;
offered = 0;
PeerId to = _offered->id;
_offered = nullptr;
if (parent()->onForward(to, _forwardSelected ? ForwardSelectedMessages : ForwardContextMessage)) {
startHide();
}
return false;
}
toText.setText(st::boxTextFont, phrase, _textNameOptions);
toTextWidth = toText.maxWidth();
if (toTextWidth > box.width() - st::boxPadding.left() - st::boxButtonPadding.right()) {
toTextWidth = box.width() - st::boxPadding.left() - st::boxButtonPadding.right();
_toText.setText(st::boxTextFont, phrase, _textNameOptions);
_toTextWidth = _toText.maxWidth();
if (_toTextWidth > _box.width() - st::boxPadding.left() - st::boxButtonPadding.right()) {
_toTextWidth = _box.width() - st::boxPadding.left() - st::boxButtonPadding.right();
}
resizeEvent(0);
resizeEvent(nullptr);
update();
setFocus();
@ -2923,11 +2891,11 @@ bool HistoryHider::offerPeer(PeerId peer) {
}
QString HistoryHider::offeredText() const {
return toText.originalText();
return _toText.originalText();
}
bool HistoryHider::wasOffered() const {
return !!offered;
return _offered != nullptr;
}
HistoryHider::~HistoryHider() {
@ -3404,7 +3372,7 @@ void HistoryWidget::writeDrafts(Data::Draft **localDraft, Data::Draft **editDraf
}
}
if (!_editMsgId) {
if (!_editMsgId && !_inlineBot) {
_saveCloudDraftTimer.start(SaveCloudDraftIdleTimeout);
}
}
@ -6017,7 +5985,6 @@ bool HistoryWidget::hasSilentToggle() const {
void HistoryWidget::inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result) {
_inlineBotResolveRequestId = 0;
// Notify::inlineBotRequesting(false);
_inlineBotUsername = QString();
UserData *resolvedBot = nullptr;
if (result.type() == mtpc_contacts_resolvedPeer) {
const auto &d(result.c_contacts_resolvedPeer());
@ -8895,6 +8862,6 @@ bool HistoryWidget::touchScroll(const QPoint &delta) {
}
HistoryWidget::~HistoryWidget() {
deleteAndMark(_pinnedBar);
deleteAndMark(_list);
delete base::take(_pinnedBar);
delete base::take(_list);
}

View File

@ -21,10 +21,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#include "localimageloader.h"
#include "ui/boxshadow.h"
#include "ui/effects/rect_shadow.h"
#include "ui/popupmenu.h"
#include "history/history_common.h"
#include "history/field_autocomplete.h"
#include "window/section_widget.h"
#include "core/single_timer.h"
namespace InlineBots {
namespace Layout {
@ -479,30 +481,31 @@ private:
void init();
MainWidget *parent();
UserData *_sharedContact;
bool _forwardSelected, _sendPath;
UserData *_sharedContact = nullptr;
bool _forwardSelected = false;
bool _sendPath = false;
QString _shareUrl, _shareText;
QString _botAndQuery;
BoxButton _send, _cancel;
PeerData *offered;
PeerData *_offered = nullptr;
anim::fvalue a_opacity;
Animation _a_appearance;
QRect box;
bool hiding;
QRect _box;
bool _hiding = false;
mtpRequestId _forwardRequest;
mtpRequestId _forwardRequest = 0;
int32 _chooseWidth;
int _chooseWidth = 0;
Text toText;
int32 toTextWidth;
QPixmap cacheForAnim;
Text _toText;
int32 _toTextWidth = 0;
QPixmap _cacheForAnim;
BoxShadow shadow;
Ui::RectShadow _shadow;
};

View File

@ -29,7 +29,7 @@ constexpr const str_const LanguageCodes[] = {
"pt_BR",
"ko",
};
constexpr const int languageTest = -1, languageDefault = 0, languageCount = arraysize(LanguageCodes);
constexpr const int languageTest = -1, languageDefault = 0, languageCount = base::array_size(LanguageCodes);
class LangString : public QString {
public:

View File

@ -83,7 +83,7 @@ private:
QRect _box, _hiddenSpecialBox;
float64 _opacity = 0.;
BoxShadow _shadow;
Ui::RectShadow _shadow;
};

View File

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "ui/boxshadow.h"
#include "ui/effects/rect_shadow.h"
class LayerWidget : public TWidget {
Q_OBJECT

View File

@ -32,6 +32,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mainwindow.h"
#include "lang.h"
#include "media/media_audio.h"
#include "application.h"
#include "apiwrap.h"
namespace Local {
@ -534,7 +535,7 @@ enum {
dbiDcOption = 0x27,
dbiTryIPv6 = 0x28,
dbiSongVolume = 0x29,
dbiWindowsNotifications = 0x30,
dbiWindowsNotificationsOld = 0x30,
dbiIncludeMuted = 0x31,
dbiMegagroupSizeMax = 0x32,
dbiDownloadPath = 0x33,
@ -548,6 +549,9 @@ enum {
dbiModerateMode = 0x41,
dbiVideoVolume = 0x42,
dbiStickersRecentLimit = 0x43,
dbiNativeNotifications = 0x44,
dbiNotificationsCount = 0x45,
dbiNotificationsCorner = 0x46,
dbiEncryptedWithSalt = 333,
dbiEncrypted = 444,
@ -989,15 +993,34 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
if (App::wnd()) App::wnd()->updateTrayMenu();
} break;
case dbiWindowsNotifications: {
case dbiWindowsNotificationsOld: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
} break;
case dbiNativeNotifications: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
Global::SetWindowsNotifications(v == 1);
if (cPlatform() == dbipWindows) {
Global::SetCustomNotifies((App::wnd() ? !App::wnd()->psHasNativeNotifications() : true) || !Global::WindowsNotifications());
}
Global::SetNativeNotifications(v == 1);
} break;
case dbiNotificationsCount: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
Global::SetNotificationsCount((v > 0 ? v : 3));
} break;
case dbiNotificationsCorner: {
qint32 v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
Global::SetNotificationsCorner(static_cast<Notify::ScreenCorner>((v >= 0 && v < 4) ? v : 2));
} break;
case dbiWorkMode: {
@ -1056,6 +1079,9 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
if (!_checkStreamStatus(stream)) return false;
cSetAutoUpdate(v == 1);
if (!cAutoUpdate()) {
Sandbox::stopUpdate();
}
} break;
case dbiLastUpdateCheck: {
@ -1568,7 +1594,7 @@ void _writeUserSettings() {
_writeMap(WriteMapFast);
}
uint32 size = 18 * (sizeof(quint32) + sizeof(qint32));
uint32 size = 20 * (sizeof(quint32) + sizeof(qint32));
size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark());
size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
@ -1592,7 +1618,9 @@ void _writeUserSettings() {
data.stream << quint32(dbiShowingSavedGifs) << qint32(cShowingSavedGifs());
data.stream << quint32(dbiDesktopNotify) << qint32(Global::DesktopNotify());
data.stream << quint32(dbiNotifyView) << qint32(Global::NotifyView());
data.stream << quint32(dbiWindowsNotifications) << qint32(Global::WindowsNotifications());
data.stream << quint32(dbiNativeNotifications) << qint32(Global::NativeNotifications());
data.stream << quint32(dbiNotificationsCount) << qint32(Global::NotificationsCount());
data.stream << quint32(dbiNotificationsCorner) << qint32(Global::NotificationsCorner());
data.stream << quint32(dbiAskDownloadPath) << qint32(Global::AskDownloadPath());
data.stream << quint32(dbiDownloadPath) << (Global::AskDownloadPath() ? QString() : Global::DownloadPath()) << (Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark());
data.stream << quint32(dbiCompressPastedImage) << qint32(cCompressPastedImage());
@ -2627,7 +2655,7 @@ public:
virtual void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, quint32 &type, QByteArray &data) = 0;
virtual void clearInMap() = 0;
virtual ~AbstractCachedLoadTask() {
deleteAndMark(_result);
delete base::take(_result);
}
protected:
@ -2903,7 +2931,7 @@ public:
}
}
virtual ~WebFileLoadTask() {
deleteAndMark(_result);
delete base::take(_result);
}
protected:

View File

@ -1015,8 +1015,7 @@ namespace internal {
#if !defined Q_OS_MAC || defined MAC_USE_BREAKPAD
if (internal::BreakpadExceptionHandler) {
google_breakpad::ExceptionHandler *h = getPointerAndReset(internal::BreakpadExceptionHandler);
delete h;
delete base::take(internal::BreakpadExceptionHandler);
}
#endif // !Q_OS_MAC || MAC_USE_BREAKPAD

View File

@ -3324,10 +3324,7 @@ void MainWidget::start(const MTPUser &user) {
App::feedUsers(MTP_vector<MTPUser>(1, user));
MTP::send(MTPupdates_GetState(), rpcDone(&MainWidget::gotState));
update();
if (!cStartUrl().isEmpty()) {
openLocalUrl(cStartUrl());
cSetStartUrl(QString());
}
_started = true;
App::wnd()->sendServiceHistoryRequest();
Local::readInstalledStickers();
@ -3335,12 +3332,23 @@ void MainWidget::start(const MTPUser &user) {
Local::readRecentStickers();
Local::readSavedGifs();
_history->start();
checkStartUrl();
}
bool MainWidget::started() {
return _started;
}
void MainWidget::checkStartUrl() {
if (!cStartUrl().isEmpty() && App::self() && !App::passcoded()) {
auto url = cStartUrl();
cSetStartUrl(QString());
openLocalUrl(url);
}
}
void MainWidget::openLocalUrl(const QString &url) {
auto urlTrimmed = url.trimmed();
if (urlTrimmed.size() > 8192) urlTrimmed = urlTrimmed.mid(0, 8192);

View File

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "localimageloader.h"
#include "history/history_common.h"
#include "core/single_timer.h"
namespace Dialogs {
class Row;
@ -156,6 +157,7 @@ public:
void start(const MTPUser &user);
void checkStartUrl();
void openLocalUrl(const QString &str);
void openPeerByName(const QString &name, MsgId msgId = ShowAtUnreadMsgId, const QString &startToken = QString());
void joinGroupByHash(const QString &hash);

View File

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "dialogs/dialogs_layout.h"
#include "styles/style_dialogs.h"
#include "ui/popupmenu.h"
#include "zip.h"
#include "lang.h"
#include "shortcuts.h"
@ -42,8 +43,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "localstorage.h"
#include "apiwrap.h"
#include "settings/settings_widget.h"
#include "window/notifications_manager.h"
ConnectingWidget::ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect) : QWidget(parent), _shadow(st::boxShadow), _reconnect(this, QString()) {
ConnectingWidget::ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect) : QWidget(parent)
, _shadow(st::boxShadow)
, _reconnect(this, QString()) {
set(text, reconnect);
connect(&_reconnect, SIGNAL(clicked()), this, SLOT(onReconnect()));
}
@ -57,310 +61,27 @@ void ConnectingWidget::set(const QString &text, const QString &reconnect) {
} else {
_reconnect.setText(reconnect);
_reconnect.show();
_reconnect.move(st::connectingPadding.left() + _textWidth, st::boxShadow.pxHeight() + st::connectingPadding.top());
_reconnect.move(st::connectingPadding.left() + _textWidth, st::boxShadow.height() + st::connectingPadding.top());
_reconnectWidth = _reconnect.width();
}
resize(st::connectingPadding.left() + _textWidth + _reconnectWidth + st::connectingPadding.right() + st::boxShadow.pxWidth(), st::boxShadow.pxHeight() + st::connectingPadding.top() + st::linkFont->height + st::connectingPadding.bottom());
resize(st::connectingPadding.left() + _textWidth + _reconnectWidth + st::connectingPadding.right() + st::boxShadow.width(), st::boxShadow.height() + st::connectingPadding.top() + st::linkFont->height + st::connectingPadding.bottom());
update();
}
void ConnectingWidget::paintEvent(QPaintEvent *e) {
QPainter p(this);
Painter p(this);
_shadow.paint(p, QRect(0, st::boxShadow.pxHeight(), width() - st::boxShadow.pxWidth(), height() - st::boxShadow.pxHeight()), 0, BoxShadow::Top | BoxShadow::Right);
p.fillRect(0, st::boxShadow.pxHeight(), width() - st::boxShadow.pxWidth(), height() - st::boxShadow.pxHeight(), st::connectingBG->b);
_shadow.paint(p, QRect(0, st::boxShadow.height(), width() - st::boxShadow.width(), height() - st::boxShadow.height()), 0, Ui::RectShadow::Side::Top | Ui::RectShadow::Side::Right);
p.fillRect(0, st::boxShadow.height(), width() - st::boxShadow.width(), height() - st::boxShadow.height(), st::connectingBG->b);
p.setFont(st::linkFont->f);
p.setPen(st::connectingColor->p);
p.drawText(st::connectingPadding.left(), st::boxShadow.pxHeight() + st::connectingPadding.top() + st::linkFont->ascent, _text);
p.drawText(st::connectingPadding.left(), st::boxShadow.height() + st::connectingPadding.top() + st::linkFont->ascent, _text);
}
void ConnectingWidget::onReconnect() {
MTP::restart();
}
NotifyWindow::NotifyWindow(HistoryItem *msg, int32 x, int32 y, int32 fwdCount) : TWidget(0)
, history(msg->history())
, item(msg)
, fwdCount(fwdCount)
#if defined Q_OS_WIN && !defined Q_OS_WINRT
, started(GetTickCount())
#endif // Q_OS_WIN && !Q_OS_WINRT
, close(this, st::notifyClose)
, alphaDuration(st::notifyFastAnim)
, posDuration(st::notifyFastAnim)
, hiding(false)
, _index(0)
, a_opacity(0)
, a_func(anim::linear)
, a_y(y + st::notifyHeight + st::notifyDeltaY)
, _a_appearance(animation(this, &NotifyWindow::step_appearance)) {
updateNotifyDisplay();
hideTimer.setSingleShot(true);
connect(&hideTimer, SIGNAL(timeout()), this, SLOT(hideByTimer()));
inputTimer.setSingleShot(true);
connect(&inputTimer, SIGNAL(timeout()), this, SLOT(checkLastInput()));
connect(&close, SIGNAL(clicked()), this, SLOT(unlinkHistoryAndNotify()));
close.setAcceptBoth(true);
close.move(st::notifyWidth - st::notifyClose.width - st::notifyClosePos.x(), st::notifyClosePos.y());
close.show();
a_y.start(y);
setGeometry(x, a_y.current(), st::notifyWidth, st::notifyHeight);
a_opacity.start(1);
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
show();
setWindowOpacity(a_opacity.current());
alphaDuration = posDuration = st::notifyFastAnim;
_a_appearance.start();
checkLastInput();
}
void NotifyWindow::checkLastInput() {
#if defined Q_OS_WIN && !defined Q_OS_WINRT
LASTINPUTINFO lii;
lii.cbSize = sizeof(LASTINPUTINFO);
BOOL res = GetLastInputInfo(&lii);
if (!res || lii.dwTime >= started) {
hideTimer.start(st::notifyWaitLongHide);
} else {
inputTimer.start(300);
}
#else // Q_OS_WIN && !Q_OS_WINRT
// TODO
if (true) {
hideTimer.start(st::notifyWaitLongHide);
} else {
inputTimer.start(300);
}
#endif // else for Q_OS_WIN && !Q_OS_WINRT
}
void NotifyWindow::moveTo(int32 x, int32 y, int32 index) {
if (index >= 0) {
_index = index;
}
move(x, a_y.current());
a_y.start(y);
a_opacity.restart();
posDuration = st::notifyFastAnim;
_a_appearance.start();
}
void NotifyWindow::updateNotifyDisplay() {
if (!item) return;
int32 w = st::notifyWidth, h = st::notifyHeight;
QImage img(w * cIntRetinaFactor(), h * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
if (cRetina()) img.setDevicePixelRatio(cRetinaFactor());
img.fill(st::notifyBG->c);
{
Painter p(&img);
p.fillRect(0, 0, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(w - st::notifyBorderWidth, 0, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) {
history->peer->loadUserpic(true, true);
history->peer->paintUserpicLeft(p, st::notifyPhotoSize, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width());
} else {
static QPixmap icon = App::pixmapFromImageInPlace(App::wnd()->iconLarge().scaled(st::notifyPhotoSize, st::notifyPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), icon);
}
int32 itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width;
QRect rectForName(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) {
if (auto chatTypeIcon = Dialogs::Layout::ChatTypeIcon(history->peer, false)) {
chatTypeIcon->paint(p, rectForName.topLeft(), w);
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
}
}
QDateTime now(QDateTime::currentDateTime()), lastTime(item->date);
QDate nowDate(now.date()), lastDate(lastTime.date());
QString dt = lastTime.toString(cTimeFormat());
int32 dtWidth = st::dialogsTextFont->width(dt);
rectForName.setWidth(rectForName.width() - dtWidth - st::dialogsDateSkip);
p.setFont(st::dialogsDateFont);
p.setPen(st::dialogsDateFg);
p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::dialogsTextFont->ascent, dt);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowPreview) {
const HistoryItem *textCachedFor = 0;
Text itemTextCache(itemWidth);
QRect r(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dialogsTextFont->height);
if (fwdCount < 2) {
bool active = false;
item->drawInDialog(p, r, active, textCachedFor, itemTextCache);
} else {
p.setFont(st::dialogsTextFont);
if (item->hasFromName() && !item->isPost()) {
itemTextCache.setText(st::dialogsTextFont, item->author()->name);
p.setPen(st::dialogsTextFgService);
itemTextCache.drawElided(p, r.left(), r.top(), r.width(), st::dialogsTextFont->height);
r.setTop(r.top() + st::dialogsTextFont->height);
}
p.setPen(st::dialogsTextFg);
p.drawText(r.left(), r.top() + st::dialogsTextFont->ascent, lng_forward_messages(lt_count, fwdCount));
}
} else {
static QString notifyText = st::dialogsTextFont->elided(lang(lng_notification_preview), itemWidth);
p.setPen(st::dialogsTextFgService);
p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText);
}
p.setPen(st::dialogsNameFg);
if (!App::passcoded() && Global::NotifyView() <= dbinvShowName) {
history->peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
} else {
p.setFont(st::msgNameFont->f);
static QString notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width());
p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle);
}
}
pm = App::pixmapFromImageInPlace(std_::move(img));
update();
}
void NotifyWindow::updatePeerPhoto() {
if (!peerPhoto->isNull() && peerPhoto->loaded()) {
QImage img(pm.toImage());
{
QPainter p(&img);
p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), peerPhoto->pix(st::notifyPhotoSize));
}
peerPhoto = ImagePtr();
pm = App::pixmapFromImageInPlace(std_::move(img));
update();
}
}
void NotifyWindow::itemRemoved(HistoryItem *del) {
if (item == del) {
item = 0;
unlinkHistoryAndNotify();
}
}
void NotifyWindow::unlinkHistoryAndNotify() {
unlinkHistory();
App::wnd()->notifyShowNext();
}
void NotifyWindow::unlinkHistory(History *hist) {
if (!hist || hist == history) {
animHide(st::notifyFastAnim, anim::linear);
history = 0;
item = 0;
}
}
void NotifyWindow::enterEvent(QEvent *e) {
if (!history) return;
if (App::wnd()) App::wnd()->notifyStopHiding();
}
void NotifyWindow::leaveEvent(QEvent *e) {
if (!history) return;
App::wnd()->notifyStartHiding();
}
void NotifyWindow::startHiding() {
hideTimer.start(st::notifyWaitShortHide);
}
void NotifyWindow::mousePressEvent(QMouseEvent *e) {
if (!history) return;
PeerId peer = history->peer->id;
MsgId msgId = (!history->peer->isUser() && item && item->mentionsMe() && item->id > 0) ? item->id : ShowAtUnreadMsgId;
if (e->button() == Qt::RightButton) {
unlinkHistoryAndNotify();
} else {
App::wnd()->showFromTray();
if (App::passcoded()) {
App::wnd()->setInnerFocus();
App::wnd()->notifyClear();
} else {
Ui::showPeerHistory(peer, msgId);
}
e->ignore();
}
}
void NotifyWindow::paintEvent(QPaintEvent *e) {
QPainter p(this);
p.drawPixmap(0, 0, pm);
}
void NotifyWindow::animHide(float64 duration, anim::transition func) {
if (!history) return;
alphaDuration = duration;
a_func = func;
a_opacity.start(0);
a_y.restart();
hiding = true;
_a_appearance.start();
}
void NotifyWindow::stopHiding() {
if (!history) return;
alphaDuration = st::notifyFastAnim;
a_func = anim::linear;
a_opacity.start(1);
a_y.restart();
hiding = false;
hideTimer.stop();
_a_appearance.start();
}
void NotifyWindow::hideByTimer() {
if (!history) return;
animHide(st::notifySlowHide, st::notifySlowHideFunc);
}
void NotifyWindow::step_appearance(float64 ms, bool timer) {
float64 dtAlpha = ms / alphaDuration, dtPos = ms / posDuration;
if (dtAlpha >= 1) {
a_opacity.finish();
if (hiding) {
_a_appearance.stop();
deleteLater();
} else if (dtPos >= 1) {
_a_appearance.stop();
}
} else {
a_opacity.update(dtAlpha, a_func);
}
setWindowOpacity(a_opacity.current());
if (dtPos >= 1) {
a_y.finish();
} else {
a_y.update(dtPos, anim::linear);
}
move(x(), a_y.current());
update();
}
NotifyWindow::~NotifyWindow() {
if (App::wnd()) App::wnd()->notifyShowNext(this);
}
MainWindow::MainWindow() {
icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation);
icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation);
@ -375,8 +96,6 @@ MainWindow::MainWindow() {
notifyClear();
} else if (type == Notify::ChangeType::ViewParams) {
notifyUpdateAll();
} else if (type == Notify::ChangeType::UseNative) {
notifyClearFast();
} else if (type == Notify::ChangeType::IncludeMuted) {
Notify::unreadCounterUpdated();
}
@ -397,14 +116,13 @@ MainWindow::MainWindow() {
_inactiveTimer.setSingleShot(true);
connect(&_inactiveTimer, SIGNAL(timeout()), this, SLOT(onInactiveTimer()));
connect(&notifyWaitTimer, SIGNAL(timeout()), this, SLOT(notifyFire()));
connect(&_notifyWaitTimer, SIGNAL(timeout()), this, SLOT(notifyShowNext()));
_isActiveTimer.setSingleShot(true);
connect(&_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActive()));
connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock()));
subscribe(FileDownload::ImageLoaded(), [this] { notifyUpdateAllPhotos(); });
subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); });
setAttribute(Qt::WA_NoSystemBackground);
@ -547,6 +265,10 @@ void MainWindow::clearPasscode() {
notifyUpdateAll();
title->updateControlsVisibility();
updateGlobalMenu();
if (auto main = App::main()) {
main->checkStartUrl();
}
}
void MainWindow::setupPasscode(bool anim) {
@ -1030,9 +752,8 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *e) {
QString url = static_cast<QFileOpenEvent*>(e)->url().toEncoded().trimmed();
if (url.startsWith(qstr("tg://"), Qt::CaseInsensitive)) {
cSetStartUrl(url.mid(0, 8192));
if (!cStartUrl().isEmpty() && App::main() && App::self()) {
App::main()->openLocalUrl(cStartUrl());
cSetStartUrl(QString());
if (auto main = App::main()) {
main->checkStartUrl();
}
}
activate();
@ -1402,72 +1123,66 @@ void MainWindow::notifySchedule(History *history, HistoryItem *item) {
// LOG(("Is online: %1, otherOnline: %2, currentTime: %3, otherNotOld: %4, otherLaterThanMe: %5").arg(Logs::b(isOnline)).arg(cOtherOnline()).arg(t).arg(Logs::b(otherNotOld)).arg(Logs::b(otherLaterThanMe)));
uint64 when = ms + delay;
notifyWhenAlerts[history].insert(when, notifyByFrom);
_notifyWhenAlerts[history].insert(when, notifyByFrom);
if (Global::DesktopNotify() && !psSkipDesktopNotify()) {
NotifyWhenMaps::iterator i = notifyWhenMaps.find(history);
if (i == notifyWhenMaps.end()) {
i = notifyWhenMaps.insert(history, NotifyWhenMap());
NotifyWhenMaps::iterator i = _notifyWhenMaps.find(history);
if (i == _notifyWhenMaps.end()) {
i = _notifyWhenMaps.insert(history, NotifyWhenMap());
}
if (i.value().constFind(item->id) == i.value().cend()) {
i.value().insert(item->id, when);
}
NotifyWaiters *addTo = haveSetting ? &notifyWaiters : &notifySettingWaiters;
NotifyWaiters *addTo = haveSetting ? &_notifyWaiters : &_notifySettingWaiters;
NotifyWaiters::const_iterator it = addTo->constFind(history);
if (it == addTo->cend() || it->when > when) {
addTo->insert(history, NotifyWaiter(item->id, when, notifyByFrom));
}
}
if (haveSetting) {
if (!notifyWaitTimer.isActive() || notifyWaitTimer.remainingTime() > delay) {
notifyWaitTimer.start(delay);
if (!_notifyWaitTimer.isActive() || _notifyWaitTimer.remainingTime() > delay) {
_notifyWaitTimer.start(delay);
}
}
}
void MainWindow::notifyFire() {
notifyShowNext();
}
void MainWindow::notifyClear(History *history) {
if (!history) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->unlinkHistory();
}
psClearNotifies();
for (NotifyWhenMaps::const_iterator i = notifyWhenMaps.cbegin(), e = notifyWhenMaps.cend(); i != e; ++i) {
Window::Notifications::manager()->clearAll();
for (auto i = _notifyWhenMaps.cbegin(), e = _notifyWhenMaps.cend(); i != e; ++i) {
i.key()->clearNotifications();
}
notifyWaiters.clear();
notifySettingWaiters.clear();
notifyWhenMaps.clear();
_notifyWhenMaps.clear();
_notifyWhenAlerts.clear();
_notifyWaiters.clear();
_notifySettingWaiters.clear();
return;
}
notifyWaiters.remove(history);
notifySettingWaiters.remove(history);
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->unlinkHistory(history);
}
psClearNotifies(history->peer->id);
notifyWhenMaps.remove(history);
notifyWhenAlerts.remove(history);
Window::Notifications::manager()->clearFromHistory(history);
history->clearNotifications();
_notifyWhenMaps.remove(history);
_notifyWhenAlerts.remove(history);
_notifyWaiters.remove(history);
_notifySettingWaiters.remove(history);
_notifyWaitTimer.stop();
notifyShowNext();
}
void MainWindow::notifyClearFast() {
notifyWaiters.clear();
notifySettingWaiters.clear();
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->deleteLater();
}
psClearNotifies();
notifyWindows.clear();
notifyWhenMaps.clear();
notifyWhenAlerts.clear();
Window::Notifications::manager()->clearAllFast();
_notifyWhenMaps.clear();
_notifyWhenAlerts.clear();
_notifyWaiters.clear();
_notifySettingWaiters.clear();
}
void MainWindow::notifySettingGot() {
int32 t = unixtime();
for (NotifyWaiters::iterator i = notifySettingWaiters.begin(); i != notifySettingWaiters.end();) {
for (NotifyWaiters::iterator i = _notifySettingWaiters.begin(); i != _notifySettingWaiters.end();) {
History *history = i.key();
bool loaded = false, muted = false;
if (history->peer->notify != UnknownNotifySettings) {
@ -1496,34 +1211,24 @@ void MainWindow::notifySettingGot() {
}
if (loaded) {
if (!muted) {
notifyWaiters.insert(i.key(), i.value());
_notifyWaiters.insert(i.key(), i.value());
}
i = notifySettingWaiters.erase(i);
i = _notifySettingWaiters.erase(i);
} else {
++i;
}
}
notifyWaitTimer.stop();
_notifyWaitTimer.stop();
notifyShowNext();
}
void MainWindow::notifyShowNext(NotifyWindow *remove) {
void MainWindow::notifyShowNext() {
if (App::quitting()) return;
int32 count = NotifyWindowsCount;
if (remove) {
for (NotifyWindows::iterator i = notifyWindows.begin(), e = notifyWindows.end(); i != e; ++i) {
if ((*i) == remove) {
notifyWindows.erase(i);
break;
}
}
}
uint64 ms = getms(true), nextAlert = 0;
bool alert = false;
int32 now = unixtime();
for (NotifyWhenAlerts::iterator i = notifyWhenAlerts.begin(); i != notifyWhenAlerts.end();) {
for (NotifyWhenAlerts::iterator i = _notifyWhenAlerts.begin(); i != _notifyWhenAlerts.end();) {
while (!i.value().isEmpty() && i.value().begin().key() <= ms) {
NotifySettingsPtr n = i.key()->peer->notify, f = i.value().begin().value() ? i.value().begin().value()->notify : UnknownNotifySettings;
while (!i.value().isEmpty() && i.value().begin().key() <= ms + 500) { // not more than one sound in 500ms from one peer - grouping
@ -1536,7 +1241,7 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
}
}
if (i.value().isEmpty()) {
i = notifyWhenAlerts.erase(i);
i = _notifyWhenAlerts.erase(i);
} else {
if (!nextAlert || nextAlert > i.value().begin().key()) {
nextAlert = i.value().begin().key();
@ -1549,33 +1254,24 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
App::playSound();
}
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
int32 ind = (*i)->index();
if (ind < 0) continue;
--count;
}
}
if (count <= 0 || notifyWaiters.isEmpty() || !Global::DesktopNotify() || psSkipDesktopNotify()) {
if (_notifyWaiters.isEmpty() || !Global::DesktopNotify() || psSkipDesktopNotify()) {
if (nextAlert) {
notifyWaitTimer.start(nextAlert - ms);
_notifyWaitTimer.start(nextAlert - ms);
}
return;
}
QRect r = psDesktopRect();
int32 x = r.x() + r.width() - st::notifyWidth - st::notifyDeltaX, y = r.y() + r.height() - st::notifyHeight - st::notifyDeltaY;
while (count > 0) {
while (true) {
uint64 next = 0;
HistoryItem *notifyItem = 0;
History *notifyHistory = 0;
for (NotifyWaiters::iterator i = notifyWaiters.begin(); i != notifyWaiters.end();) {
for (NotifyWaiters::iterator i = _notifyWaiters.begin(); i != _notifyWaiters.end();) {
History *history = i.key();
if (history->currentNotification() && history->currentNotification()->id != i.value().msg) {
NotifyWhenMaps::iterator j = notifyWhenMaps.find(history);
if (j == notifyWhenMaps.end()) {
NotifyWhenMaps::iterator j = _notifyWhenMaps.find(history);
if (j == _notifyWhenMaps.end()) {
history->clearNotifications();
i = notifyWaiters.erase(i);
i = _notifyWaiters.erase(i);
continue;
}
do {
@ -1589,8 +1285,8 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
} while (history->currentNotification());
}
if (!history->currentNotification()) {
notifyWhenMaps.remove(history);
i = notifyWaiters.erase(i);
_notifyWhenMaps.remove(history);
i = _notifyWaiters.erase(i);
continue;
}
uint64 when = i.value().when;
@ -1607,7 +1303,7 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
next = nextAlert;
nextAlert = 0;
}
notifyWaitTimer.start(next - ms);
_notifyWaitTimer.start(next - ms);
break;
} else {
HistoryItem *fwd = notifyItem->Has<HistoryMessageForwarded>() ? notifyItem : nullptr; // forwarded notify grouping
@ -1615,8 +1311,8 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
uint64 ms = getms(true);
History *history = notifyItem->history();
NotifyWhenMaps::iterator j = notifyWhenMaps.find(history);
if (j == notifyWhenMaps.cend()) {
NotifyWhenMaps::iterator j = _notifyWhenMaps.find(history);
if (j == _notifyWhenMaps.cend()) {
history->clearNotifications();
} else {
HistoryItem *nextNotify = 0;
@ -1631,7 +1327,7 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id);
if (k != j.value().cend()) {
nextNotify = history->currentNotification();
notifyWaiters.insert(notifyHistory, NotifyWaiter(k.key(), k.value(), 0));
_notifyWaiters.insert(notifyHistory, NotifyWaiter(k.key(), k.value(), 0));
break;
}
history->skipNotification();
@ -1652,18 +1348,11 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
} while (nextNotify);
}
if (Global::CustomNotifies()) {
NotifyWindow *notify = new NotifyWindow(notifyItem, x, y, fwdCount);
notifyWindows.push_back(notify);
psNotifyShown(notify);
--count;
} else {
psPlatformNotify(notifyItem, fwdCount);
}
Window::Notifications::manager()->showNotification(notifyItem, fwdCount);
if (!history->hasNotification()) {
notifyWaiters.remove(history);
notifyWhenMaps.remove(history);
_notifyWaiters.remove(history);
_notifyWhenMaps.remove(history);
continue;
}
}
@ -1672,49 +1361,8 @@ void MainWindow::notifyShowNext(NotifyWindow *remove) {
}
}
if (nextAlert) {
notifyWaitTimer.start(nextAlert - ms);
_notifyWaitTimer.start(nextAlert - ms);
}
count = NotifyWindowsCount - count;
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
int32 ind = (*i)->index();
if (ind < 0) continue;
--count;
(*i)->moveTo(x, y - count * (st::notifyHeight + st::notifyDeltaY));
}
}
void MainWindow::notifyItemRemoved(HistoryItem *item) {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->itemRemoved(item);
}
}
}
void MainWindow::notifyStopHiding() {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->stopHiding();
}
}
}
void MainWindow::notifyStartHiding() {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->startHiding();
}
}
}
void MainWindow::notifyUpdateAllPhotos() {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->updatePeerPhoto();
}
}
if (_mediaView && !_mediaView->isHidden()) _mediaView->updateControls();
}
void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
@ -1722,20 +1370,7 @@ void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButt
}
void MainWindow::notifyUpdateAll() {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->updateNotifyDisplay();
}
}
psClearNotifies();
}
void MainWindow::notifyActivateAll() {
if (Global::CustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
psActivateNotify(*i);
}
}
Window::Notifications::manager()->updateAll();
}
QImage MainWindow::iconLarge() const {

View File

@ -22,8 +22,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "title.h"
#include "pspecific.h"
#include "ui/boxshadow.h"
#include "ui/effects/rect_shadow.h"
#include "platform/platform_main_window.h"
#include "core/single_timer.h"
class MediaView;
class TitleWidget;
@ -32,9 +33,11 @@ class IntroWidget;
class MainWidget;
class LayerStackWidget;
class LayerWidget;
namespace Local {
class ClearManager;
} // namespace Local
namespace Settings {
class Widget;
} // namespace Settings
@ -43,87 +46,21 @@ class ConnectingWidget : public QWidget {
Q_OBJECT
public:
ConnectingWidget(QWidget *parent, const QString &text, const QString &reconnect);
void set(const QString &text, const QString &reconnect);
void paintEvent(QPaintEvent *e);
public slots:
void onReconnect();
private:
BoxShadow _shadow;
Ui::RectShadow _shadow;
QString _text;
int32 _textWidth;
LinkButton _reconnect;
};
class NotifyWindow : public TWidget {
Q_OBJECT
public:
NotifyWindow(HistoryItem *item, int32 x, int32 y, int32 fwdCount);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void mousePressEvent(QMouseEvent *e);
void paintEvent(QPaintEvent *e);
void step_appearance(float64 ms, bool timer);
void animHide(float64 duration, anim::transition func);
void startHiding();
void stopHiding();
void moveTo(int32 x, int32 y, int32 index = -1);
void updateNotifyDisplay();
void updatePeerPhoto();
void itemRemoved(HistoryItem *del);
int32 index() const {
return history ? _index : -1;
}
void unlinkHistory(History *hist = 0);
~NotifyWindow();
public slots:
void hideByTimer();
void checkLastInput();
void unlinkHistoryAndNotify();
private:
#if defined Q_OS_WIN && !defined Q_OS_WINRT
DWORD started;
#endif // Q_OS_WIN && !Q_OS_WINRT
History *history;
HistoryItem *item;
int32 fwdCount;
IconedButton close;
QPixmap pm;
float64 alphaDuration, posDuration;
QTimer hideTimer, inputTimer;
bool hiding;
int32 _index;
anim::fvalue a_opacity;
anim::transition a_func;
anim::ivalue a_y;
Animation _a_appearance;
ImagePtr peerPhoto;
};
typedef QList<NotifyWindow*> NotifyWindows;
class MediaPreviewWidget;
class MainWindow : public Platform::MainWindow, private base::Subscriber {
@ -204,12 +141,7 @@ public:
void notifySchedule(History *history, HistoryItem *item);
void notifyClear(History *history = 0);
void notifyClearFast();
void notifyShowNext(NotifyWindow *remove = 0);
void notifyItemRemoved(HistoryItem *item);
void notifyStopHiding();
void notifyStartHiding();
void notifyUpdateAll();
void notifyActivateAll();
QImage iconLarge() const;
@ -266,7 +198,7 @@ public slots:
void onClearFinished(int task, void *manager);
void onClearFailed(int task, void *manager);
void notifyFire();
void notifyShowNext();
void updateTrayMenu(bool force = false);
void onShowAddContact();
@ -278,8 +210,6 @@ public slots:
void onReActivate();
void notifyUpdateAllPhotos();
void app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button);
signals:
@ -333,28 +263,30 @@ private:
SingleTimer _autoLockTimer;
uint64 _shouldLockAt = 0;
typedef QMap<MsgId, uint64> NotifyWhenMap;
typedef QMap<History*, NotifyWhenMap> NotifyWhenMaps;
NotifyWhenMaps notifyWhenMaps;
using NotifyWhenMap = QMap<MsgId, uint64>;
using NotifyWhenMaps = QMap<History*, NotifyWhenMap>;
NotifyWhenMaps _notifyWhenMaps;
struct NotifyWaiter {
NotifyWaiter(MsgId msg, uint64 when, PeerData *notifyByFrom) : msg(msg), when(when), notifyByFrom(notifyByFrom) {
NotifyWaiter(MsgId msg, uint64 when, PeerData *notifyByFrom)
: msg(msg)
, when(when)
, notifyByFrom(notifyByFrom) {
}
MsgId msg;
uint64 when;
PeerData *notifyByFrom;
};
typedef QMap<History*, NotifyWaiter> NotifyWaiters;
NotifyWaiters notifyWaiters;
NotifyWaiters notifySettingWaiters;
SingleTimer notifyWaitTimer;
using NotifyWaiters = QMap<History*, NotifyWaiter>;
NotifyWaiters _notifyWaiters;
NotifyWaiters _notifySettingWaiters;
SingleTimer _notifyWaitTimer;
typedef QMap<uint64, PeerData*> NotifyWhenAlert;
typedef QMap<History*, NotifyWhenAlert> NotifyWhenAlerts;
NotifyWhenAlerts notifyWhenAlerts;
NotifyWindows notifyWindows;
using NotifyWhenAlert = QMap<uint64, PeerData*>;
using NotifyWhenAlerts = QMap<History*, NotifyWhenAlert>;
NotifyWhenAlerts _notifyWhenAlerts;
MediaView *_mediaView = nullptr;
};
class PreLaunchWindow : public TWidget {

View File

@ -985,13 +985,13 @@ void AudioPlayerFader::onTimer() {
} else if (ms > _suppressAllStart + notifyLengthMs - AudioFadeDuration) {
if (_suppressAllGain.to() != 1.) _suppressAllGain.start(1.);
_suppressAllGain.update(1. - ((_suppressAllStart + notifyLengthMs - ms) / float64(AudioFadeDuration)), anim::linear);
} else if (ms >= _suppressAllStart + st::notifyFastAnim) {
} else if (ms >= _suppressAllStart + st::mediaPlayerSuppressDuration) {
if (_suppressAllAnim) {
_suppressAllGain.finish();
_suppressAllAnim = false;
}
} else if (ms > _suppressAllStart) {
_suppressAllGain.update((ms - _suppressAllStart) / st::notifyFastAnim, anim::linear);
_suppressAllGain.update((ms - _suppressAllStart) / st::mediaPlayerSuppressDuration, anim::linear);
}
suppressAllGain = _suppressAllGain.current();
suppressAudioChanged = (suppressAllGain != wasAudio);

View File

@ -75,7 +75,7 @@ AudioPlayerLoaders::~AudioPlayerLoaders() {
}
void AudioPlayerLoaders::clearFromVideoQueue() {
auto queue = createAndSwap(_fromVideoQueue);
auto queue = base::take(_fromVideoQueue);
for (auto &packetData : queue) {
AVPacket packet;
FFMpeg::packetFromDataWrap(packet, packetData);

View File

@ -197,7 +197,7 @@ void ChildFFMpegLoader::enqueuePackets(QQueue<FFMpeg::AVPacketDataWrap> &packets
}
ChildFFMpegLoader::~ChildFFMpegLoader() {
auto queue = createAndSwap(_queue);
auto queue = base::take(_queue);
for (auto &packetData : queue) {
AVPacket packet;
FFMpeg::packetFromDataWrap(packet, packetData);

View File

@ -525,7 +525,7 @@ void FFMpegReaderImplementation::finishPacket() {
void FFMpegReaderImplementation::clearPacketQueue() {
finishPacket();
auto packets = createAndSwap(_packetQueue);
auto packets = base::take(_packetQueue);
for (auto &packetData : packets) {
AVPacket packet;
FFMpeg::packetFromDataWrap(packet, packetData);

View File

@ -106,7 +106,7 @@ bool QtGifReaderImplementation::start(Mode mode, int64 &positionMs) {
}
QtGifReaderImplementation::~QtGifReaderImplementation() {
deleteAndMark(_reader);
delete base::take(_reader);
}
bool QtGifReaderImplementation::jumpToStart() {

View File

@ -44,8 +44,7 @@ bool exists() {
}
void finish() {
auto temp = createAndSwap(SingleInstance);
delete temp;
delete base::take(SingleInstance);
audioFinish();
}

View File

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "ui/boxshadow.h"
#include "ui/effects/rect_shadow.h"
class ScrollArea;

View File

@ -26,6 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mainwindow.h"
#include "application.h"
#include "ui/filedialog.h"
#include "ui/popupmenu.h"
#include "media/media_clip_reader.h"
#include "media/view/media_clip_controller.h"
#include "styles/style_mediaview.h"
@ -96,6 +97,12 @@ MediaView::MediaView() : TWidget(App::wnd())
connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(onScreenResized(int)));
subscribe(FileDownload::ImageLoaded(), [this] {
if (!isHidden()) {
updateControls();
}
});
_transparentBrush = QBrush(App::sprite().copy(st::mvTransparentBrush.rect()));
setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::Tool | Qt::NoDropShadowWindowHint);
@ -612,7 +619,7 @@ void MediaView::clearData() {
}
MediaView::~MediaView() {
deleteAndMark(_menu);
delete base::take(_menu);
}
void MediaView::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {

View File

@ -29,9 +29,11 @@ class Controller;
} // namespace Clip
} // namespace Media
class PopupMenu;
struct AudioPlaybackState;
class MediaView : public TWidget, public RPCSender, public ClickHandlerHost {
class MediaView : public TWidget, private base::Subscriber, public RPCSender, public ClickHandlerHost {
Q_OBJECT
public:

View File

@ -44,17 +44,17 @@ public:
}
uint32 getDC() const {
if (!_isset) throw mtpErrorKeyNotReady("getDC()");
t_assert(_isset);
return _dc;
}
uint64 keyId() const {
if (!_isset) throw mtpErrorKeyNotReady("keyId()");
t_assert(_isset);
return _keyId;
}
void prepareAES(const MTPint128 &msgKey, MTPint256 &aesKey, MTPint256 &aesIV, bool send = true) const {
if (!_isset) throw mtpErrorKeyNotReady(QString("prepareAES(..., %1)").arg(Logs::b(send)));
t_assert(_isset);
uint32 x = send ? 0 : 8;
@ -90,7 +90,7 @@ public:
}
void write(QDataStream &to) const {
if (!_isset) throw mtpErrorKeyNotReady("write(...)");
t_assert(_isset);
to.writeRawData(_key, 256);
}

View File

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mtproto/core_types.h"
#include "mtproto/auth_key.h"
#include "mtproto/connection_abstract.h"
#include "core/single_timer.h"
namespace MTP {
namespace internal {

View File

@ -298,7 +298,7 @@ void AbstractTCPConnection::tcpSend(mtpBuffer &buffer) {
// prepare decryption key/iv
char reversed[48];
memcpy(reversed, nonce + 8, sizeof(reversed));
std::reverse(reversed, reversed + arraysize(reversed));
std::reverse(reversed, reversed + base::array_size(reversed));
memcpy(_receiveKey, reversed, CTRState::KeySize);
memcpy(_receiveState.ivec, reversed + CTRState::KeySize, CTRState::IvecSize);

View File

@ -199,30 +199,12 @@ public:
}
};
class mtpErrorUninitialized : public Exception {
public:
mtpErrorUninitialized() : Exception("MTP Uninitialized variable write attempt") {
}
};
class mtpErrorBadTypeId : public Exception {
public:
mtpErrorBadTypeId(mtpTypeId typeId, const QString &type) : Exception(QString("MTP Bad type id %1 passed to constructor of %2").arg(typeId).arg(type)) {
}
};
class mtpErrorWrongTypeId : public Exception {
public:
mtpErrorWrongTypeId(mtpTypeId typeId, mtpTypeId required) : Exception(QString("MTP Wrong type id %1 for this data conversion, must be %2").arg(typeId).arg(required)) {
}
};
class mtpErrorKeyNotReady : public Exception {
public:
mtpErrorKeyNotReady(const QString &method) : Exception(QString("MTP Auth key is used in %1 without being created").arg(method)) {
}
};
class mtpData {
public:
mtpData() : cnt(1) {
@ -686,12 +668,12 @@ public:
}
MTPDstring &_string() {
if (!data) throw mtpErrorUninitialized();
t_assert(data != nullptr);
split();
return *(MTPDstring*)data;
}
const MTPDstring &c_string() const {
if (!data) throw mtpErrorUninitialized();
t_assert(data != nullptr);
return *(const MTPDstring*)data;
}
@ -823,12 +805,12 @@ public:
}
MTPDvector<T> &_vector() {
if (!data) throw mtpErrorUninitialized();
t_assert(data != nullptr);
split();
return *(MTPDvector<T>*)data;
}
const MTPDvector<T> &c_vector() const {
if (!data) throw mtpErrorUninitialized();
t_assert(data != nullptr);
return *(const MTPDvector<T>*)data;
}

View File

@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "core/single_timer.h"
namespace MTP {
namespace internal {
@ -27,7 +29,6 @@ class Dcenter : public QObject {
Q_OBJECT
public:
Dcenter(int32 id, const AuthKeyPtr &key);
QReadWriteLock *keyMutex() const;
@ -46,21 +47,19 @@ public:
}
signals:
void authKeyCreated();
void layerWasInited(bool was);
private slots:
void authKeyWrite();
private:
mutable QReadWriteLock keyLock;
mutable QMutex initLock;
int32 _id;
AuthKeyPtr _key;
bool _connectionInited;
};
typedef QSharedPointer<Dcenter> DcenterPtr;
@ -70,21 +69,17 @@ class ConfigLoader : public QObject {
Q_OBJECT
public:
ConfigLoader();
void load();
void done();
public slots:
void enumDC();
signals:
void loaded();
private:
SingleTimer _enumDCTimer;
int32 _enumCurrent;
mtpRequestId _enumRequest;

View File

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mtproto/core_types.h"
#include "mtproto/session.h"
#include "core/single_timer.h"
namespace MTP {
@ -57,17 +58,15 @@ class GlobalSlotCarrier : public QObject {
Q_OBJECT
public:
GlobalSlotCarrier();
public slots:
void checkDelayed();
void connectionFinished(Connection *connection);
private:
SingleTimer _timer;
};
GlobalSlotCarrier *globalSlotCarrier();

View File

@ -612,17 +612,19 @@ for restype in typesList:
withData = 1;
getters += '\n\tMTPD' + name + ' &_' + name + '() {\n'; # splitting getter
getters += '\t\tif (!data) throw mtpErrorUninitialized();\n';
if (withType):
getters += '\t\tif (_type != mtpc_' + name + ') throw mtpErrorWrongTypeId(_type, mtpc_' + name + ');\n';
getters += '\t\tt_assert(data != nullptr && _type == mtpc_' + name + ');\n';
else:
getters += '\t\tt_assert(data != nullptr);\n';
getters += '\t\tsplit();\n';
getters += '\t\treturn *(MTPD' + name + '*)data;\n';
getters += '\t}\n';
getters += '\tconst MTPD' + name + ' &c_' + name + '() const {\n'; # const getter
getters += '\t\tif (!data) throw mtpErrorUninitialized();\n';
if (withType):
getters += '\t\tif (_type != mtpc_' + name + ') throw mtpErrorWrongTypeId(_type, mtpc_' + name + ');\n';
getters += '\t\tt_assert(data != nullptr && _type == mtpc_' + name + ');\n';
else:
getters += '\t\tt_assert(data != nullptr);\n';
getters += '\t\treturn *(const MTPD' + name + '*)data;\n';
getters += '\t}\n';
@ -783,7 +785,7 @@ for restype in typesList:
typesText += '\tmtpTypeId type() const;\n'; # type id method
inlineMethods += 'inline mtpTypeId MTP' + restype + '::type() const {\n';
if (withType):
inlineMethods += '\tif (!_type) throw mtpErrorUninitialized();\n';
inlineMethods += '\tt_assert(_type != 0);\n';
inlineMethods += '\treturn _type;\n';
else:
inlineMethods += '\treturn mtpc_' + v[0][0] + ';\n';

View File

@ -20,9 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "core/lambda_wrap.h"
class RPCError {
public:
RPCError(const MTPrpcError &error) : _code(error.c_rpc_error().verror_code.v) {
QString text = qs(error.c_rpc_error().verror_message);
if (_code < 0 || _code >= 500) {
@ -827,3 +828,187 @@ protected:
typedef void (*MTPStateChangedHandler)(int32 dcId, int32 state);
typedef void(*MTPSessionResetHandler)(int32 dcId);
template <typename FunctionType>
struct LambdaUniqueHelper;
template <typename Lambda, typename R, typename ...Args>
struct LambdaUniqueHelper<R(Lambda::*)(Args...) const> {
using UniqueType = base::lambda_unique<R(Args...)>;
};
template <typename FunctionType>
using LambdaGetUnique = typename LambdaUniqueHelper<FunctionType>::UniqueType;
template <typename Base, typename FunctionType>
class RPCHandlerImplementation : public Base {
protected:
using Lambda = base::lambda_unique<FunctionType>;
using Parent = RPCHandlerImplementation<Base, FunctionType>;
public:
RPCHandlerImplementation(Lambda &&handler) : _handler(std_::move(handler)) {
}
protected:
Lambda _handler;
};
template <typename FunctionType>
using RPCDoneHandlerImplementation = RPCHandlerImplementation<RPCAbstractDoneHandler, FunctionType>;
template <typename R>
class RPCDoneHandlerImplementationBare : public RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*)> { // done(from, end)
public:
using RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(from, end) : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationBareReq : public RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*, mtpRequestId)> { // done(from, end, req_id)
public:
using RPCDoneHandlerImplementation<R(const mtpPrime*, const mtpPrime*, mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(from, end, requestId) : void(0);
}
};
template <typename R, typename T>
class RPCDoneHandlerImplementationPlain : public RPCDoneHandlerImplementation<R(const T&)> { // done(result)
public:
using RPCDoneHandlerImplementation<R(const T&)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(T(from, end)) : void(0);
}
};
template <typename R, typename T>
class RPCDoneHandlerImplementationReq : public RPCDoneHandlerImplementation<R(const T&, mtpRequestId)> { // done(result, req_id)
public:
using RPCDoneHandlerImplementation<R(const T&, mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(T(from, end), requestId) : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationNo : public RPCDoneHandlerImplementation<R()> { // done()
public:
using RPCDoneHandlerImplementation<R()>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler() : void(0);
}
};
template <typename R>
class RPCDoneHandlerImplementationNoReq : public RPCDoneHandlerImplementation<R(mtpRequestId)> { // done(req_id)
public:
using RPCDoneHandlerImplementation<R(mtpRequestId)>::Parent::Parent;
void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) const override {
return this->_handler ? this->_handler(requestId) : void(0);
}
};
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const mtpPrime*, const mtpPrime*)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBare<R>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const mtpPrime*, const mtpPrime*, mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBareReq<R>(std_::move(lambda)));
}
template <typename R, typename T>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const T&)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationPlain<R, T>(std_::move(lambda)));
}
template <typename R, typename T>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(const T&, mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationReq<R, T>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R()> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNo<R>(std_::move(lambda)));
}
template <typename R>
inline RPCDoneHandlerPtr rpcDone_lambda_wrap_helper(base::lambda_unique<R(mtpRequestId)> &&lambda) {
return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNoReq<R>(std_::move(lambda)));
}
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
RPCDoneHandlerPtr rpcDone(Lambda &&lambda) {
return rpcDone_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}
template <typename FunctionType>
using RPCFailHandlerImplementation = RPCHandlerImplementation<RPCAbstractFailHandler, FunctionType>;
class RPCFailHandlerImplementationPlain : public RPCFailHandlerImplementation<bool(const RPCError&)> { // fail(error)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return _handler ? _handler(error) : true;
}
};
class RPCFailHandlerImplementationReq : public RPCFailHandlerImplementation<bool(const RPCError&, mtpRequestId)> { // fail(error, req_id)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler(error, requestId) : true;
}
};
class RPCFailHandlerImplementationNo : public RPCFailHandlerImplementation<bool()> { // fail()
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler() : true;
}
};
class RPCFailHandlerImplementationNoReq : public RPCFailHandlerImplementation<bool(mtpRequestId)> { // fail(req_id)
public:
using Parent::Parent;
bool operator()(mtpRequestId requestId, const RPCError &error) const override {
return this->_handler ? this->_handler(requestId) : true;
}
};
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(const RPCError&)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationPlain(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(const RPCError&, mtpRequestId)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationReq(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool()> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationNo(std_::move(lambda)));
}
inline RPCFailHandlerPtr rpcFail_lambda_wrap_helper(base::lambda_unique<bool(mtpRequestId)> &&lambda) {
return RPCFailHandlerPtr(new RPCFailHandlerImplementationNoReq(std_::move(lambda)));
}
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
RPCFailHandlerPtr rpcFail(Lambda &&lambda) {
return rpcFail_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mtproto/connection.h"
#include "mtproto/dcenter.h"
#include "mtproto/rpc_sender.h"
#include "core/single_timer.h"
namespace MTP {
namespace internal {
@ -31,7 +32,6 @@ class Session;
class SessionData {
public:
SessionData(Session *creator)
: _session(0)
, _salt(0)
@ -227,7 +227,6 @@ class Session : public QObject {
Q_OBJECT
public:
Session(int32 dcenter);
void restart();
@ -237,7 +236,6 @@ public:
void unpaused();
int32 getDcWithShift() const;
~Session();
QReadWriteLock *keyMutex() const;
void notifyKeyCreated(const AuthKeyPtr &key);
@ -255,15 +253,15 @@ public:
void sendPrepared(const mtpRequest &request, uint64 msCanWait = 0, bool newRequest = true); // nulls msgId and seqNo in request, if newRequest = true
signals:
~Session();
signals:
void authKeyCreated();
void needToSend();
void needToPing();
void needToRestart();
public slots:
void needToResumeAndSend();
mtpRequestId resend(quint64 msgId, quint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
@ -283,7 +281,6 @@ public slots:
void sendMsgsStateInfo(quint64 msgId, QByteArray data);
private:
Connection *_connection;
bool _killed;

View File

@ -98,8 +98,8 @@ void peerUpdatedSendDelayed() {
if (!SmallUpdates || !AllUpdates || SmallUpdates->empty()) return;
auto smallList = createAndSwap(*SmallUpdates);
auto allList = createAndSwap(*AllUpdates);
auto smallList = base::take(*SmallUpdates);
auto allList = base::take(*AllUpdates);
for (auto &update : smallList) {
PeerUpdated().notify(std_::move(update), true);
}

View File

@ -106,7 +106,7 @@ void RadialProgressItem::checkRadialFinished() {
}
RadialProgressItem::~RadialProgressItem() {
deleteAndMark(_radial);
delete base::take(_radial);
}
void FileBase::setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const {

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#include "window/section_widget.h"
#include "ui/popupmenu.h"
namespace Overview {
namespace Layout {

View File

@ -0,0 +1,122 @@
/*
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
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "platform/linux/linux_libnotify.h"
#include "platform/linux/linux_libs.h"
namespace Platform {
namespace Libs {
namespace {
bool loadLibrary(QLibrary &lib, const char *name, int version) {
DEBUG_LOG(("Loading '%1' with version %2...").arg(QLatin1String(name)).arg(version));
lib.setFileNameAndVersion(QLatin1String(name), version);
if (lib.load()) {
DEBUG_LOG(("Loaded '%1' with version %2!").arg(QLatin1String(name)).arg(version));
return true;
}
lib.setFileNameAndVersion(QLatin1String(name), QString());
if (lib.load()) {
DEBUG_LOG(("Loaded '%1' without version!").arg(QLatin1String(name)));
return true;
}
LOG(("Could not load '%1' with version %2 :(").arg(QLatin1String(name)).arg(version));
return false;
}
} // namespace
f_notify_init notify_init = nullptr;
f_notify_uninit notify_uninit = nullptr;
f_notify_is_initted notify_is_initted = nullptr;
//f_notify_get_app_name notify_get_app_name = nullptr;
//f_notify_set_app_name notify_set_app_name = nullptr;
f_notify_get_server_caps notify_get_server_caps = nullptr;
f_notify_get_server_info notify_get_server_info = nullptr;
f_notify_notification_new notify_notification_new = nullptr;
//f_notify_notification_update notify_notification_update = nullptr;
f_notify_notification_show notify_notification_show = nullptr;
//f_notify_notification_set_app_name notify_notification_set_app_name = nullptr;
f_notify_notification_set_timeout notify_notification_set_timeout = nullptr;
//f_notify_notification_set_category notify_notification_set_category = nullptr;
//f_notify_notification_set_urgency notify_notification_set_urgency = nullptr;
//f_notify_notification_set_icon_from_pixbuf notify_notification_set_icon_from_pixbuf = nullptr;
f_notify_notification_set_image_from_pixbuf notify_notification_set_image_from_pixbuf = nullptr;
//f_notify_notification_set_hint notify_notification_set_hint = nullptr;
//f_notify_notification_set_hint_int32 notify_notification_set_hint_int32 = nullptr;
//f_notify_notification_set_hint_uint32 notify_notification_set_hint_uint32 = nullptr;
//f_notify_notification_set_hint_double notify_notification_set_hint_double = nullptr;
f_notify_notification_set_hint_string notify_notification_set_hint_string = nullptr;
//f_notify_notification_set_hint_byte notify_notification_set_hint_byte = nullptr;
//f_notify_notification_set_hint_byte_array notify_notification_set_hint_byte_array = nullptr;
//f_notify_notification_clear_hints notify_notification_clear_hints = nullptr;
f_notify_notification_add_action notify_notification_add_action = nullptr;
f_notify_notification_clear_actions notify_notification_clear_actions = nullptr;
f_notify_notification_close notify_notification_close = nullptr;
f_notify_notification_get_closed_reason notify_notification_get_closed_reason = nullptr;
void startLibNotify() {
DEBUG_LOG(("Loading libnotify"));
QLibrary lib_notify;
if (!loadLibrary(lib_notify, "notify", 4)) {
if (!loadLibrary(lib_notify, "notify", 5)) {
if (!loadLibrary(lib_notify, "notify", 1)) {
return;
}
}
}
load(lib_notify, "notify_init", notify_init);
load(lib_notify, "notify_uninit", notify_uninit);
load(lib_notify, "notify_is_initted", notify_is_initted);
// load(lib_notify, "notify_get_app_name", notify_get_app_name);
// load(lib_notify, "notify_set_app_name", notify_set_app_name);
load(lib_notify, "notify_get_server_caps", notify_get_server_caps);
load(lib_notify, "notify_get_server_info", notify_get_server_info);
load(lib_notify, "notify_notification_new", notify_notification_new);
// load(lib_notify, "notify_notification_update", notify_notification_update);
load(lib_notify, "notify_notification_show", notify_notification_show);
// load(lib_notify, "notify_notification_set_app_name", notify_notification_set_app_name);
load(lib_notify, "notify_notification_set_timeout", notify_notification_set_timeout);
// load(lib_notify, "notify_notification_set_category", notify_notification_set_category);
// load(lib_notify, "notify_notification_set_urgency", notify_notification_set_urgency);
// load(lib_notify, "notify_notification_set_icon_from_pixbuf", notify_notification_set_icon_from_pixbuf);
load(lib_notify, "notify_notification_set_image_from_pixbuf", notify_notification_set_image_from_pixbuf);
// load(lib_notify, "notify_notification_set_hint", notify_notification_set_hint);
// load(lib_notify, "notify_notification_set_hint_int32", notify_notification_set_hint_int32);
// load(lib_notify, "notify_notification_set_hint_uint32", notify_notification_set_hint_uint32);
// load(lib_notify, "notify_notification_set_hint_double", notify_notification_set_hint_double);
load(lib_notify, "notify_notification_set_hint_string", notify_notification_set_hint_string);
// load(lib_notify, "notify_notification_set_hint_byte", notify_notification_set_hint_byte);
// load(lib_notify, "notify_notification_set_hint_byte_array", notify_notification_set_hint_byte_array);
// load(lib_notify, "notify_notification_clear_hints", notify_notification_clear_hints);
load(lib_notify, "notify_notification_add_action", notify_notification_add_action);
load(lib_notify, "notify_notification_clear_actions", notify_notification_clear_actions);
load(lib_notify, "notify_notification_close", notify_notification_close);
load(lib_notify, "notify_notification_get_closed_reason", notify_notification_get_closed_reason);
}
} // namespace Libs
} // namespace Platform

View File

@ -0,0 +1,131 @@
/*
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
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
extern "C" {
#undef signals
#include <gtk/gtk.h>
#define signals public
} // extern "C"
namespace Platform {
namespace Libs {
void startLibNotify();
constexpr gint NOTIFY_EXPIRES_DEFAULT = -1;
constexpr gint NOTIFY_EXPIRES_NEVER = 0;
struct NotifyNotification;
typedef enum {
NOTIFY_URGENCY_LOW,
NOTIFY_URGENCY_NORMAL,
NOTIFY_URGENCY_CRITICAL,
} NotifyUrgency;
using NotifyActionCallback = void (*)(NotifyNotification *notification, char *action, gpointer user_data);
using f_notify_init = gboolean (*)(const char *app_name);
extern f_notify_init notify_init;
using f_notify_uninit = void (*)(void);
extern f_notify_uninit notify_uninit;
using f_notify_is_initted = gboolean (*)(void);
extern f_notify_is_initted notify_is_initted;
//using f_notify_get_app_name = const char* (*)(void);
//extern f_notify_get_app_name notify_get_app_name;
//using f_notify_set_app_name = void (*)(const char *app_name);
//extern f_notify_set_app_name notify_set_app_name;
using f_notify_get_server_caps = GList* (*)(void);
extern f_notify_get_server_caps notify_get_server_caps;
using f_notify_get_server_info = gboolean (*)(char **ret_name, char **ret_vendor, char **ret_version, char **ret_spec_version);
extern f_notify_get_server_info notify_get_server_info;
using f_notify_notification_new = NotifyNotification* (*)(const char *summary, const char *body, const char *icon);
extern f_notify_notification_new notify_notification_new;
//using f_notify_notification_update = gboolean (*)(NotifyNotification *notification, const char *summary, const char *body, const char *icon);
//extern f_notify_notification_update notify_notification_update;
using f_notify_notification_show = gboolean (*)(NotifyNotification *notification, GError **error);
extern f_notify_notification_show notify_notification_show;
//using f_notify_notification_set_app_name = void (*)(NotifyNotification *notification, const char *app_name);
//extern f_notify_notification_set_app_name notify_notification_set_app_name;
using f_notify_notification_set_timeout = void (*)(NotifyNotification *notification, gint timeout);
extern f_notify_notification_set_timeout notify_notification_set_timeout;
//using f_notify_notification_set_category = void (*)(NotifyNotification *notification, const char *category);
//extern f_notify_notification_set_category notify_notification_set_category;
//using f_notify_notification_set_urgency = void (*)(NotifyNotification *notification, NotifyUrgency urgency);
//extern f_notify_notification_set_urgency notify_notification_set_urgency;
//using f_notify_notification_set_icon_from_pixbuf = void (*)(NotifyNotification *notification, GdkPixbuf *icon);
//extern f_notify_notification_set_icon_from_pixbuf notify_notification_set_icon_from_pixbuf;
using f_notify_notification_set_image_from_pixbuf = void (*)(NotifyNotification *notification, GdkPixbuf *pixbuf);
extern f_notify_notification_set_image_from_pixbuf notify_notification_set_image_from_pixbuf;
//using f_notify_notification_set_hint = void (*)(NotifyNotification *notification, const char *key, GVariant *value);
//extern f_notify_notification_set_hint notify_notification_set_hint;
//using f_notify_notification_set_hint_int32 = void (*)(NotifyNotification *notification, const char *key, gint value);
//extern f_notify_notification_set_hint_int32 notify_notification_set_hint_int32;
//using f_notify_notification_set_hint_uint32 = void (*)(NotifyNotification *notification, const char *key, guint value);
//extern f_notify_notification_set_hint_uint32 notify_notification_set_hint_uint32;
//using f_notify_notification_set_hint_double = void (*)(NotifyNotification *notification, const char *key, gdouble value);
//extern f_notify_notification_set_hint_double notify_notification_set_hint_double;
using f_notify_notification_set_hint_string = void (*)(NotifyNotification *notification, const char *key, const char *value);
extern f_notify_notification_set_hint_string notify_notification_set_hint_string;
//using f_notify_notification_set_hint_byte = void (*)(NotifyNotification *notification, const char *key, guchar value);
//extern f_notify_notification_set_hint_byte notify_notification_set_hint_byte;
//using f_notify_notification_set_hint_byte_array = void (*)(NotifyNotification *notification, const char *key, const guchar *value, gsize len);
//extern f_notify_notification_set_hint_byte_array notify_notification_set_hint_byte_array;
//using f_notify_notification_clear_hints = void (*)(NotifyNotification *notification);
//extern f_notify_notification_clear_hints notify_notification_clear_hints;
using f_notify_notification_add_action = void (*)(NotifyNotification *notification, const char *action, const char *label, NotifyActionCallback callback, gpointer user_data, GFreeFunc free_func);
extern f_notify_notification_add_action notify_notification_add_action;
using f_notify_notification_clear_actions = void (*)(NotifyNotification *notification);
extern f_notify_notification_clear_actions notify_notification_clear_actions;
using f_notify_notification_close = gboolean (*)(NotifyNotification *notification, GError **error);
extern f_notify_notification_close notify_notification_close;
using f_notify_notification_get_closed_reason = gint (*)(const NotifyNotification *notification);
extern f_notify_notification_get_closed_reason notify_notification_get_closed_reason;
} // namespace Libs
} // namespace Platform

View File

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "platform/linux/linux_libs.h"
#include "platform/linux/linux_gdk_helper.h"
#include "platform/linux/linux_libnotify.h"
namespace Platform {
namespace Libs {
@ -92,10 +93,16 @@ bool setupGtkBase(QLibrary &lib_gtk) {
if (!load(lib_gtk, "g_type_check_instance_cast", g_type_check_instance_cast)) return false;
if (!load(lib_gtk, "g_type_check_instance_is_a", g_type_check_instance_is_a)) return false;
if (!load(lib_gtk, "g_signal_connect_data", g_signal_connect_data)) return false;
if (!load(lib_gtk, "g_signal_handler_disconnect", g_signal_handler_disconnect)) return false;
if (!load(lib_gtk, "g_object_ref_sink", g_object_ref_sink)) return false;
if (!load(lib_gtk, "g_object_unref", g_object_unref)) return false;
if (!load(lib_gtk, "g_free", g_free)) return false;
if (!load(lib_gtk, "g_list_foreach", g_list_foreach)) return false;
if (!load(lib_gtk, "g_list_free", g_list_free)) return false;
if (!load(lib_gtk, "g_list_free_full", g_list_free_full)) return false;
if (!load(lib_gtk, "g_error_free", g_error_free)) return false;
if (!load(lib_gtk, "g_slist_free", g_slist_free)) return false;
DEBUG_LOG(("Library gtk functions loaded!"));
@ -169,12 +176,14 @@ f_gtk_dialog_run gtk_dialog_run = nullptr;
f_g_type_check_instance_cast g_type_check_instance_cast = nullptr;
f_g_type_check_instance_is_a g_type_check_instance_is_a = nullptr;
f_g_signal_connect_data g_signal_connect_data = nullptr;
f_g_signal_handler_disconnect g_signal_handler_disconnect = nullptr;
f_app_indicator_new app_indicator_new = nullptr;
f_app_indicator_set_status app_indicator_set_status = nullptr;
f_app_indicator_set_menu app_indicator_set_menu = nullptr;
f_app_indicator_set_icon_full app_indicator_set_icon_full = nullptr;
f_gdk_init_check gdk_init_check = nullptr;
f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data = nullptr;
f_gdk_pixbuf_new_from_file gdk_pixbuf_new_from_file = nullptr;
f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf = nullptr;
f_gtk_status_icon_set_from_pixbuf gtk_status_icon_set_from_pixbuf = nullptr;
f_gtk_status_icon_new_from_file gtk_status_icon_new_from_file = nullptr;
@ -191,6 +200,10 @@ f_g_object_ref_sink g_object_ref_sink = nullptr;
f_g_object_unref g_object_unref = nullptr;
f_g_idle_add g_idle_add = nullptr;
f_g_free g_free = nullptr;
f_g_list_foreach g_list_foreach = nullptr;
f_g_list_free g_list_free = nullptr;
f_g_list_free_full g_list_free_full = nullptr;
f_g_error_free g_error_free = nullptr;
f_g_slist_free g_slist_free = nullptr;
#ifndef TDESKTOP_DISABLE_UNITY_INTEGRATION
f_unity_launcher_entry_set_count unity_launcher_entry_set_count = nullptr;
@ -233,6 +246,7 @@ void start() {
if (gtkLoaded) {
load(lib_gtk, "gdk_init_check", gdk_init_check);
load(lib_gtk, "gdk_pixbuf_new_from_data", gdk_pixbuf_new_from_data);
load(lib_gtk, "gdk_pixbuf_new_from_file", gdk_pixbuf_new_from_file);
load(lib_gtk, "gtk_status_icon_new_from_pixbuf", gtk_status_icon_new_from_pixbuf);
load(lib_gtk, "gtk_status_icon_set_from_pixbuf", gtk_status_icon_set_from_pixbuf);
load(lib_gtk, "gtk_status_icon_new_from_file", gtk_status_icon_new_from_file);
@ -266,6 +280,10 @@ void start() {
load(lib_unity, "unity_launcher_entry_set_count_visible", unity_launcher_entry_set_count_visible);
}
#endif // TDESKTOP_DISABLE_UNITY_INTEGRATION
if (gtkLoaded) {
startLibNotify();
}
}
} // namespace Libs

View File

@ -247,14 +247,17 @@ extern f_gtk_dialog_run gtk_dialog_run;
typedef gulong (*f_g_signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags);
extern f_g_signal_connect_data g_signal_connect_data;
inline gulong g_signal_connect_helper(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data) {
return g_signal_connect_data(instance, detailed_signal, c_handler, data, NULL, (GConnectFlags)0);
inline gulong g_signal_connect_helper(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data = nullptr) {
return g_signal_connect_data(instance, detailed_signal, c_handler, data, destroy_data, (GConnectFlags)0);
}
inline gulong g_signal_connect_swapped_helper(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data) {
return g_signal_connect_data(instance, detailed_signal, c_handler, data, NULL, G_CONNECT_SWAPPED);
inline gulong g_signal_connect_swapped_helper(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data = nullptr) {
return g_signal_connect_data(instance, detailed_signal, c_handler, data, destroy_data, G_CONNECT_SWAPPED);
}
typedef void (*f_g_signal_handler_disconnect)(gpointer instance, gulong handler_id);
extern f_g_signal_handler_disconnect g_signal_handler_disconnect;
typedef AppIndicator* (*f_app_indicator_new)(const gchar *id, const gchar *icon_name, AppIndicatorCategory category);
extern f_app_indicator_new app_indicator_new;
@ -273,6 +276,9 @@ extern f_gdk_init_check gdk_init_check;
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_data)(const guchar *data, GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height, int rowstride, GdkPixbufDestroyNotify destroy_fn, gpointer destroy_fn_data);
extern f_gdk_pixbuf_new_from_data gdk_pixbuf_new_from_data;
typedef GdkPixbuf* (*f_gdk_pixbuf_new_from_file)(const gchar *filename, GError **error);
extern f_gdk_pixbuf_new_from_file gdk_pixbuf_new_from_file;
typedef GtkStatusIcon* (*f_gtk_status_icon_new_from_pixbuf)(GdkPixbuf *pixbuf);
extern f_gtk_status_icon_new_from_pixbuf gtk_status_icon_new_from_pixbuf;
@ -321,6 +327,18 @@ extern f_g_idle_add g_idle_add;
typedef void (*f_g_free)(gpointer mem);
extern f_g_free g_free;
typedef void (*f_g_list_foreach)(GList *list, GFunc func, gpointer user_data);
extern f_g_list_foreach g_list_foreach;
typedef void (*f_g_list_free)(GList *list);
extern f_g_list_free g_list_free;
typedef void (*f_g_list_free_full)(GList *list, GDestroyNotify free_func);
extern f_g_list_free_full g_list_free_full;
typedef void (*f_g_error_free)(GError *error);
extern f_g_error_free g_error_free;
typedef void (*f_g_slist_free)(GSList *list);
extern f_g_slist_free g_slist_free;

View File

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "platform/linux/main_window_linux.h"
#include "platform/linux/linux_libs.h"
#include "platform/platform_notifications_manager.h"
#include "mainwindow.h"
#include "application.h"
#include "lang.h"
@ -63,22 +64,11 @@ gboolean _trayIconResized(GtkStatusIcon *status_icon, gint size, gpointer popup_
return FALSE;
}
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
#define QT_RED 3
#define QT_GREEN 2
#define QT_BLUE 1
#define QT_ALPHA 0
#else
#define QT_RED 0
#define QT_GREEN 1
#define QT_BLUE 2
#define QT_ALPHA 3
#endif
#define GTK_RED 2
#define GTK_GREEN 1
#define GTK_BLUE 0
@ -262,13 +252,19 @@ void MainWindow::psSetupTrayIcon() {
trayIcon->setToolTip(str_const_toString(AppName));
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(toggleTray(QSystemTrayIcon::ActivationReason)), Qt::UniqueConnection);
// This is very important for native notifications via libnotify!
// Some notification servers compose several notifications with a "Reply"
// action into one and after that a click on "Reply" button does not call
// the specified callback from any of the sent notification - libnotify
// just ignores ibus messages, but Qt tray icon at least emits this signal.
connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showFromTray()));
App::wnd()->updateTrayMenu();
}
psUpdateCounter();
trayIcon->show();
psUpdateDelegate();
}
}
@ -367,6 +363,10 @@ void MainWindow::psUpdateCounter() {
}
}
bool MainWindow::psHasNativeNotifications() {
return Notifications::supported();
}
void MainWindow::LibsLoaded() {
QString cdesktop = QString(getenv("XDG_CURRENT_DESKTOP")).toLower();
noQtTrayIcon = (cdesktop == qstr("pantheon")) || (cdesktop == qstr("gnome"));
@ -430,9 +430,6 @@ void MainWindow::LibsLoaded() {
#endif // TDESKTOP_DISABLE_UNITY_INTEGRATION
}
void MainWindow::psUpdateDelegate() {
}
void MainWindow::psInitSize() {
setMinimumWidth(st::wndMinWidth);
setMinimumHeight(st::wndMinHeight);
@ -663,18 +660,6 @@ void MainWindow::psUpdateMargins() {
void MainWindow::psFlash() {
}
void MainWindow::psActivateNotify(NotifyWindow *w) {
}
void MainWindow::psClearNotifies(PeerId peerId) {
}
void MainWindow::psNotifyShown(NotifyWindow *w) {
}
void MainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
}
MainWindow::~MainWindow() {
if (_trayIcon) {
Libs::g_object_unref(_trayIcon);

View File

@ -22,8 +22,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "window/main_window.h"
class NotifyWindow;
namespace Platform {
class MainWindow : public Window::MainWindow {
@ -58,16 +56,9 @@ public:
return posInited;
}
void psActivateNotify(NotifyWindow *w);
void psClearNotifies(PeerId peerId = 0);
void psNotifyShown(NotifyWindow *w);
void psPlatformNotify(HistoryItem *item, int32 fwdCount);
void psUpdateCounter();
bool psHasNativeNotifications() {
return false;
}
bool psHasNativeNotifications();
virtual QImage iconWithCounter(int size, int count, style::color bg, bool smallIcon) = 0;
@ -76,8 +67,6 @@ public:
~MainWindow();
public slots:
void psUpdateDelegate();
void psSavePosition(Qt::WindowState state = Qt::WindowActive);
void psShowTrayMenu();

Some files were not shown because too many files have changed in this diff Show More