mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Move advanced notifications settings from box.
This commit is contained in:
parent
f493d69bd2
commit
7ee1af5348
6 changed files with 488 additions and 507 deletions
|
@ -278,7 +278,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_settings_show_preview" = "Show message preview";
|
"lng_settings_show_preview" = "Show message preview";
|
||||||
"lng_settings_use_windows" = "Use Windows notifications";
|
"lng_settings_use_windows" = "Use Windows notifications";
|
||||||
"lng_settings_use_native_notifications" = "Use native 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_position" = "Location on the screen";
|
||||||
"lng_settings_notifications_count" = "Notifications count";
|
"lng_settings_notifications_count" = "Notifications count";
|
||||||
"lng_settings_sound_notify" = "Play sound";
|
"lng_settings_sound_notify" = "Play sound";
|
||||||
|
|
|
@ -403,13 +403,9 @@ shareColumnSkip: 6px;
|
||||||
shareActivateDuration: 150;
|
shareActivateDuration: 150;
|
||||||
shareScrollDuration: 300;
|
shareScrollDuration: 300;
|
||||||
|
|
||||||
notificationsBoxHeight: 420px;
|
|
||||||
notificationsBoxMonitorTop: 63px;
|
|
||||||
notificationsBoxMonitor: icon {{ "monitor", notificationsBoxMonitorFg }};
|
notificationsBoxMonitor: icon {{ "monitor", notificationsBoxMonitorFg }};
|
||||||
notificationsBoxScreenTop: 10px;
|
notificationsBoxScreenTop: 10px;
|
||||||
notificationsBoxScreenSize: size(280px, 160px);
|
notificationsBoxScreenSize: size(280px, 160px);
|
||||||
notificationsBoxCountLabelTop: 80px;
|
|
||||||
notificationsBoxCountTop: 30px;
|
|
||||||
|
|
||||||
notificationsSampleSkip: 5px;
|
notificationsSampleSkip: 5px;
|
||||||
notificationsSampleTopSkip: 5px;
|
notificationsSampleTopSkip: 5px;
|
||||||
|
|
|
@ -1,420 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#include "boxes/notifications_box.h"
|
|
||||||
|
|
||||||
#include "lang/lang_keys.h"
|
|
||||||
#include "ui/widgets/buttons.h"
|
|
||||||
#include "ui/widgets/discrete_sliders.h"
|
|
||||||
#include "styles/style_boxes.h"
|
|
||||||
#include "styles/style_dialogs.h"
|
|
||||||
#include "styles/style_window.h"
|
|
||||||
#include "messenger.h"
|
|
||||||
#include "storage/localstorage.h"
|
|
||||||
#include "auth_session.h"
|
|
||||||
#include "window/notifications_manager.h"
|
|
||||||
#include "platform/platform_specific.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr int kMaxNotificationsCount = 5;
|
|
||||||
|
|
||||||
using ChangeType = Window::Notifications::ChangeType;
|
|
||||||
|
|
||||||
} // 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());
|
|
||||||
|
|
||||||
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::Tool);
|
|
||||||
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
|
|
||||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
|
||||||
|
|
||||||
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;
|
|
||||||
Animation _opacity;
|
|
||||||
bool _hiding = false;
|
|
||||||
bool _deleted = false;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
NotificationsBox::NotificationsBox(QWidget *parent)
|
|
||||||
: _chosenCorner(Global::NotificationsCorner())
|
|
||||||
, _oldCount(snap(Global::NotificationsCount(), 1, kMaxNotificationsCount))
|
|
||||||
, _countSlider(this) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotificationsBox::prepare() {
|
|
||||||
addButton(langFactory(lng_close), [this] { closeBox(); });
|
|
||||||
|
|
||||||
_sampleOpacities.reserve(kMaxNotificationsCount);
|
|
||||||
for (int i = 0; i != kMaxNotificationsCount; ++i) {
|
|
||||||
_countSlider->addSection(QString::number(i + 1));
|
|
||||||
_sampleOpacities.push_back(Animation());
|
|
||||||
}
|
|
||||||
_countSlider->setActiveSectionFast(_oldCount - 1);
|
|
||||||
_countSlider->sectionActivated(
|
|
||||||
) | rpl::start_with_next(
|
|
||||||
[this] { countChanged(); },
|
|
||||||
lifetime());
|
|
||||||
|
|
||||||
setMouseTracking(true);
|
|
||||||
|
|
||||||
prepareNotificationSampleSmall();
|
|
||||||
prepareNotificationSampleLarge();
|
|
||||||
|
|
||||||
setDimensions(st::boxWideWidth, st::notificationsBoxHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotificationsBox::paintEvent(QPaintEvent *e) {
|
|
||||||
BoxContent::paintEvent(e);
|
|
||||||
|
|
||||||
Painter p(this);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
p.setOpacity(1.);
|
|
||||||
} else {
|
|
||||||
p.setOpacity(st::notificationSampleOpacity);
|
|
||||||
p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall);
|
|
||||||
p.setOpacity(1.);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto labelTop = screenRect.y() + screenRect.height() + st::notificationsBoxCountLabelTop;
|
|
||||||
p.setFont(st::boxTitleFont);
|
|
||||||
p.setPen(st::boxTitleFg);
|
|
||||||
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());
|
|
||||||
Auth().notifications().settingsChanged().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) {
|
|
||||||
BoxContent::resizeEvent(e);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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::notificationBg->c);
|
|
||||||
{
|
|
||||||
Painter p(&sampleImage);
|
|
||||||
PainterHighQualityEnabler hq(p);
|
|
||||||
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
|
|
||||||
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(Messenger::Instance().logoNoMargin().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::notificationBg->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);
|
|
||||||
|
|
||||||
st::notifyClose.icon.paint(p, w - st::notifyClosePos.x() - st::notifyClose.width + st::notifyClose.iconPosition.x(), st::notifyClosePos.y() + st::notifyClose.iconPosition.y(), w);
|
|
||||||
}
|
|
||||||
|
|
||||||
_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::leaveEventHook(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);
|
|
||||||
Auth().notifications().settingsChanged().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);
|
|
||||||
Auth().notifications().settingsChanged().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);
|
|
||||||
Auth().notifications().settingsChanged().notify(ChangeType::Corner);
|
|
||||||
Local::writeUserSettings();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationsBox::~NotificationsBox() {
|
|
||||||
for_const (auto &samples, _cornerSamples) {
|
|
||||||
for_const (auto widget, samples) {
|
|
||||||
widget->detach();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clearOverCorner();
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
/*
|
|
||||||
This file is part of Telegram Desktop,
|
|
||||||
the official desktop application for the Telegram messaging service.
|
|
||||||
|
|
||||||
For license and copyright information please follow this link:
|
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "boxes/abstract_box.h"
|
|
||||||
|
|
||||||
namespace Ui {
|
|
||||||
class LinkButton;
|
|
||||||
class SettingsSlider;
|
|
||||||
} // namespace Ui
|
|
||||||
|
|
||||||
class NotificationsBox : public BoxContent {
|
|
||||||
public:
|
|
||||||
NotificationsBox(QWidget*);
|
|
||||||
~NotificationsBox();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void prepare() override;
|
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
|
||||||
void leaveEventHook(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<Animation> _sampleOpacities;
|
|
||||||
|
|
||||||
bool _isOverCorner = false;
|
|
||||||
ScreenCorner _overCorner = ScreenCorner::TopLeft;
|
|
||||||
bool _isDownCorner = false;
|
|
||||||
ScreenCorner _downCorner = ScreenCorner::TopLeft;
|
|
||||||
|
|
||||||
int _oldCount;
|
|
||||||
object_ptr<Ui::SettingsSlider> _countSlider;
|
|
||||||
|
|
||||||
QVector<SampleWidget*> _cornerSamples[4];
|
|
||||||
|
|
||||||
};
|
|
|
@ -12,19 +12,505 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/widgets/discrete_sliders.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "info/profile/info_profile_button.h"
|
#include "info/profile/info_profile_button.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
#include "boxes/notifications_box.h"
|
|
||||||
#include "platform/platform_notifications_manager.h"
|
#include "platform/platform_notifications_manager.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include "messenger.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
#include "styles/style_settings.h"
|
#include "styles/style_settings.h"
|
||||||
|
#include "styles/style_boxes.h"
|
||||||
|
#include "styles/style_window.h"
|
||||||
|
#include "styles/style_dialogs.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kMaxNotificationsCount = 5;
|
||||||
|
|
||||||
|
int CurrentCount() {
|
||||||
|
return snap(Global::NotificationsCount(), 1, kMaxNotificationsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
using ChangeType = Window::Notifications::ChangeType;
|
||||||
|
|
||||||
|
class NotificationsCount : public Ui::RpWidget {
|
||||||
|
public:
|
||||||
|
NotificationsCount(QWidget *parent);
|
||||||
|
|
||||||
|
void setCount(int count);
|
||||||
|
|
||||||
|
~NotificationsCount();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
void leaveEventHook(QEvent *e) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
|
|
||||||
|
int resizeGetHeight(int newWidth) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using ScreenCorner = Notify::ScreenCorner;
|
||||||
|
void setOverCorner(ScreenCorner corner);
|
||||||
|
void clearOverCorner();
|
||||||
|
|
||||||
|
class SampleWidget;
|
||||||
|
void removeSample(SampleWidget *widget);
|
||||||
|
|
||||||
|
QRect getScreenRect() const;
|
||||||
|
QRect getScreenRect(int width) const;
|
||||||
|
int getContentLeft() const;
|
||||||
|
void prepareNotificationSampleSmall();
|
||||||
|
void prepareNotificationSampleLarge();
|
||||||
|
void prepareNotificationSampleUserpic();
|
||||||
|
|
||||||
|
QPixmap _notificationSampleUserpic;
|
||||||
|
QPixmap _notificationSampleSmall;
|
||||||
|
QPixmap _notificationSampleLarge;
|
||||||
|
ScreenCorner _chosenCorner;
|
||||||
|
std::vector<Animation> _sampleOpacities;
|
||||||
|
|
||||||
|
bool _isOverCorner = false;
|
||||||
|
ScreenCorner _overCorner = ScreenCorner::TopLeft;
|
||||||
|
bool _isDownCorner = false;
|
||||||
|
ScreenCorner _downCorner = ScreenCorner::TopLeft;
|
||||||
|
|
||||||
|
int _oldCount;
|
||||||
|
|
||||||
|
QVector<SampleWidget*> _cornerSamples[4];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class NotificationsCount::SampleWidget : public QWidget {
|
||||||
|
public:
|
||||||
|
SampleWidget(NotificationsCount *owner, const QPixmap &cache);
|
||||||
|
|
||||||
|
void detach();
|
||||||
|
void showFast();
|
||||||
|
void hideFast();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void startAnimation();
|
||||||
|
void animationCallback();
|
||||||
|
|
||||||
|
void destroyDelayed();
|
||||||
|
|
||||||
|
NotificationsCount *_owner;
|
||||||
|
QPixmap _cache;
|
||||||
|
Animation _opacity;
|
||||||
|
bool _hiding = false;
|
||||||
|
bool _deleted = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
NotificationsCount::NotificationsCount(QWidget *parent)
|
||||||
|
: _chosenCorner(Global::NotificationsCorner())
|
||||||
|
, _oldCount(CurrentCount()) {
|
||||||
|
setMouseTracking(true);
|
||||||
|
|
||||||
|
_sampleOpacities.resize(kMaxNotificationsCount);
|
||||||
|
|
||||||
|
prepareNotificationSampleSmall();
|
||||||
|
prepareNotificationSampleLarge();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
|
||||||
|
auto contentLeft = getContentLeft();
|
||||||
|
|
||||||
|
auto screenRect = getScreenRect();
|
||||||
|
p.fillRect(
|
||||||
|
screenRect.x(),
|
||||||
|
screenRect.y(),
|
||||||
|
st::notificationsBoxScreenSize.width(),
|
||||||
|
st::notificationsBoxScreenSize.height(),
|
||||||
|
st::notificationsBoxScreenBg);
|
||||||
|
|
||||||
|
auto monitorTop = 0;
|
||||||
|
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 = _oldCount;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
p.setOpacity(1.);
|
||||||
|
} else {
|
||||||
|
p.setOpacity(st::notificationSampleOpacity);
|
||||||
|
p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall);
|
||||||
|
p.setOpacity(1.);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::setCount(int count) {
|
||||||
|
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 (count != Global::NotificationsCount()) {
|
||||||
|
Global::SetNotificationsCount(count);
|
||||||
|
Auth().notifications().settingsChanged().notify(ChangeType::MaxCount);
|
||||||
|
Local::writeUserSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int NotificationsCount::getContentLeft() const {
|
||||||
|
return (width() - st::notificationsBoxMonitor.width()) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect NotificationsCount::getScreenRect() const {
|
||||||
|
return getScreenRect(width());
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect NotificationsCount::getScreenRect(int width) const {
|
||||||
|
auto screenLeft = (width - st::notificationsBoxScreenSize.width()) / 2;
|
||||||
|
auto screenTop = st::notificationsBoxScreenTop;
|
||||||
|
return QRect(screenLeft, screenTop, st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
int NotificationsCount::resizeGetHeight(int newWidth) {
|
||||||
|
update();
|
||||||
|
return st::notificationsBoxMonitor.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::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::notificationBg->c);
|
||||||
|
{
|
||||||
|
Painter p(&sampleImage);
|
||||||
|
PainterHighQualityEnabler hq(p);
|
||||||
|
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
|
||||||
|
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 NotificationsCount::prepareNotificationSampleUserpic() {
|
||||||
|
if (_notificationSampleUserpic.isNull()) {
|
||||||
|
_notificationSampleUserpic = App::pixmapFromImageInPlace(
|
||||||
|
Messenger::Instance().logoNoMargin().scaled(
|
||||||
|
st::notifyPhotoSize * cIntRetinaFactor(),
|
||||||
|
st::notifyPhotoSize * cIntRetinaFactor(),
|
||||||
|
Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation));
|
||||||
|
_notificationSampleUserpic.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::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::notificationBg->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);
|
||||||
|
|
||||||
|
st::notifyClose.icon.paint(p, w - st::notifyClosePos.x() - st::notifyClose.width + st::notifyClose.iconPosition.x(), st::notifyClosePos.y() + st::notifyClose.iconPosition.y(), w);
|
||||||
|
}
|
||||||
|
|
||||||
|
_notificationSampleLarge = App::pixmapFromImageInPlace(std::move(sampleImage));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::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 NotificationsCount::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 NotificationsCount::leaveEventHook(QEvent *e) {
|
||||||
|
clearOverCorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::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);
|
||||||
|
Auth().notifications().settingsChanged().notify(ChangeType::DemoIsShown);
|
||||||
|
}
|
||||||
|
_overCorner = corner;
|
||||||
|
|
||||||
|
auto &samples = _cornerSamples[static_cast<int>(_overCorner)];
|
||||||
|
auto samplesAlready = samples.size();
|
||||||
|
auto samplesNeeded = _oldCount;
|
||||||
|
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 NotificationsCount::clearOverCorner() {
|
||||||
|
if (_isOverCorner) {
|
||||||
|
_isOverCorner = false;
|
||||||
|
setCursor(style::cur_default);
|
||||||
|
Global::SetNotificationsDemoIsShown(false);
|
||||||
|
Auth().notifications().settingsChanged().notify(ChangeType::DemoIsShown);
|
||||||
|
|
||||||
|
for_const (auto &samples, _cornerSamples) {
|
||||||
|
for_const (auto widget, samples) {
|
||||||
|
widget->hideFast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::mousePressEvent(QMouseEvent *e) {
|
||||||
|
_isDownCorner = _isOverCorner;
|
||||||
|
_downCorner = _overCorner;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::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);
|
||||||
|
Auth().notifications().settingsChanged().notify(ChangeType::Corner);
|
||||||
|
Local::writeUserSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationsCount::~NotificationsCount() {
|
||||||
|
for_const (auto &samples, _cornerSamples) {
|
||||||
|
for_const (auto widget, samples) {
|
||||||
|
widget->detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearOverCorner();
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationsCount::SampleWidget::SampleWidget(
|
||||||
|
NotificationsCount *owner,
|
||||||
|
const QPixmap &cache)
|
||||||
|
: QWidget(nullptr)
|
||||||
|
, _owner(owner)
|
||||||
|
, _cache(cache) {
|
||||||
|
resize(
|
||||||
|
cache.width() / cache.devicePixelRatio(),
|
||||||
|
cache.height() / cache.devicePixelRatio());
|
||||||
|
|
||||||
|
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint)
|
||||||
|
| Qt::WindowStaysOnTopHint
|
||||||
|
| Qt::BypassWindowManagerHint
|
||||||
|
| Qt::NoDropShadowWindowHint
|
||||||
|
| Qt::Tool);
|
||||||
|
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
|
||||||
|
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
|
setWindowOpacity(0.);
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::SampleWidget::detach() {
|
||||||
|
_owner = nullptr;
|
||||||
|
hideFast();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::SampleWidget::showFast() {
|
||||||
|
_hiding = false;
|
||||||
|
startAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::SampleWidget::hideFast() {
|
||||||
|
_hiding = true;
|
||||||
|
startAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::SampleWidget::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
p.drawPixmap(0, 0, _cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::SampleWidget::startAnimation() {
|
||||||
|
_opacity.start(
|
||||||
|
[=] { animationCallback(); },
|
||||||
|
_hiding ? 1. : 0.,
|
||||||
|
_hiding ? 0. : 1.,
|
||||||
|
st::notifyFastAnim);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::SampleWidget::animationCallback() {
|
||||||
|
setWindowOpacity(_opacity.current(_hiding ? 0. : 1.));
|
||||||
|
if (!_opacity.animating() && _hiding) {
|
||||||
|
if (_owner) {
|
||||||
|
_owner->removeSample(this);
|
||||||
|
}
|
||||||
|
hide();
|
||||||
|
destroyDelayed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotificationsCount::SampleWidget::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
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupAdvancedNotifications(not_null<Ui::VerticalLayout*> container) {
|
||||||
|
AddSkip(container, st::settingsCheckboxesSkip);
|
||||||
|
AddDivider(container);
|
||||||
|
AddSkip(container, st::settingsCheckboxesSkip);
|
||||||
|
AddSubsectionTitle(container, lng_settings_notifications_position);
|
||||||
|
AddSkip(container, st::settingsCheckboxesSkip);
|
||||||
|
|
||||||
|
const auto position = container->add(
|
||||||
|
object_ptr<NotificationsCount>(container));
|
||||||
|
|
||||||
|
AddSkip(container, st::settingsCheckboxesSkip);
|
||||||
|
AddSubsectionTitle(container, lng_settings_notifications_count);
|
||||||
|
|
||||||
|
const auto count = container->add(
|
||||||
|
object_ptr<Ui::SettingsSlider>(container, st::settingsSlider),
|
||||||
|
st::settingsBigScalePadding);
|
||||||
|
for (int i = 0; i != kMaxNotificationsCount; ++i) {
|
||||||
|
count->addSection(QString::number(i + 1));
|
||||||
|
}
|
||||||
|
count->setActiveSectionFast(CurrentCount() - 1);
|
||||||
|
count->sectionActivated(
|
||||||
|
) | rpl::start_with_next([=](int section) {
|
||||||
|
position->setCount(section + 1);
|
||||||
|
}, count->lifetime());
|
||||||
|
AddSkip(container, st::settingsCheckboxesSkip);
|
||||||
|
}
|
||||||
|
|
||||||
void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) {
|
void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) {
|
||||||
const auto checkbox = [&](LangKey label, bool checked) {
|
const auto checkbox = [&](LangKey label, bool checked) {
|
||||||
return object_ptr<Ui::Checkbox>(
|
return object_ptr<Ui::Checkbox>(
|
||||||
|
@ -86,16 +572,8 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) {
|
||||||
? advancedSlide->entity()
|
? advancedSlide->entity()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
if (advancedWrap) {
|
if (advancedWrap) {
|
||||||
AddSkip(advancedWrap, st::settingsCheckboxesSkip);
|
SetupAdvancedNotifications(advancedWrap);
|
||||||
AddDivider(advancedWrap);
|
|
||||||
AddSkip(advancedWrap, st::settingsCheckboxesSkip);
|
|
||||||
}
|
}
|
||||||
const auto advanced = advancedWrap
|
|
||||||
? AddButton(
|
|
||||||
advancedWrap,
|
|
||||||
lng_settings_advanced_notifications,
|
|
||||||
st::settingsButton).get()
|
|
||||||
: nullptr;
|
|
||||||
|
|
||||||
if (!name->entity()->checked()) {
|
if (!name->entity()->checked()) {
|
||||||
preview->hide(anim::type::instant);
|
preview->hide(anim::type::instant);
|
||||||
|
@ -206,11 +684,6 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) {
|
||||||
}
|
}
|
||||||
}, native->lifetime());
|
}, native->lifetime());
|
||||||
}
|
}
|
||||||
if (advanced) {
|
|
||||||
advanced->addClickHandler([=] {
|
|
||||||
Ui::show(Box<NotificationsBox>());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupNotifications(not_null<Ui::VerticalLayout*> container) {
|
void SetupNotifications(not_null<Ui::VerticalLayout*> container) {
|
||||||
|
|
|
@ -38,8 +38,6 @@
|
||||||
<(src_loc)/boxes/local_storage_box.h
|
<(src_loc)/boxes/local_storage_box.h
|
||||||
<(src_loc)/boxes/mute_settings_box.cpp
|
<(src_loc)/boxes/mute_settings_box.cpp
|
||||||
<(src_loc)/boxes/mute_settings_box.h
|
<(src_loc)/boxes/mute_settings_box.h
|
||||||
<(src_loc)/boxes/notifications_box.cpp
|
|
||||||
<(src_loc)/boxes/notifications_box.h
|
|
||||||
<(src_loc)/boxes/peer_list_box.cpp
|
<(src_loc)/boxes/peer_list_box.cpp
|
||||||
<(src_loc)/boxes/peer_list_box.h
|
<(src_loc)/boxes/peer_list_box.h
|
||||||
<(src_loc)/boxes/peer_list_controllers.cpp
|
<(src_loc)/boxes/peer_list_controllers.cpp
|
||||||
|
|
Loading…
Add table
Reference in a new issue