Advanced notifications settings box layout done.

This commit is contained in:
John Preston 2016-10-05 21:37:48 +03:00
parent 41dc0f4e98
commit e7b6d7b498
15 changed files with 443 additions and 192 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -245,6 +245,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"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";

View File

@ -89,3 +89,12 @@ 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;

View File

@ -0,0 +1,108 @@
/*
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"
namespace {
constexpr int kMaxNotificationsCount = 5;
} // namespace
NotificationsBox::NotificationsBox() : AbstractBox()
, _countSlider(this)
, _save(this, lang(lng_settings_save), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
for (int i = 0; i != kMaxNotificationsCount; ++i) {
_countSlider->addSection(QString::number(i + 1));
}
_countSlider->setActiveSectionFast(2);
setMouseTracking(true);
_save->setClickedCallback([this] {
});
connect(_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
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 screenLeft = (width() - st::notificationsBoxScreenSize.width()) / 2;
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());
auto labelTop = screenRect.y() + screenRect.height() + st::notificationsBoxCountLabelTop;
p.drawTextLeft(contentLeft, labelTop, width(), lang(lng_settings_notifications_count));
}
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) {
_save->moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save->height());
_cancel->moveToRight(st::boxButtonPadding.right() + _save->width() + st::boxButtonPadding.left(), _save->y());
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::mousePressEvent(QMouseEvent *e) {
}
void NotificationsBox::mouseMoveEvent(QMouseEvent *e) {
}
void NotificationsBox::mouseReleaseEvent(QMouseEvent *e) {
}

View File

@ -0,0 +1,52 @@
/*
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 {
Q_OBJECT
public:
NotificationsBox();
protected:
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
private:
QRect getScreenRect() const;
int getContentLeft() const;
ChildWidget<Ui::DiscreteSlider> _countSlider;
ChildWidget<BoxButton> _save, _cancel;
};

View File

@ -125,17 +125,6 @@ settingsLargeSkip: 23px;
settingsActionPadding: margins(0px, 4px, 0px, 5px);
settingsSliderHeight: 39px;
settingsSliderTop: 5px;
settingsSliderSkip: 3px;
settingsSliderThickness: 3px;
settingsSliderActiveFg: #4bb5e7;
settingsSliderInactiveFg: #e1eaef;
settingsSliderLabelTop: 17px;
settingsSliderLabelFont: normalFont;
settingsSliderLabelFg: #1485c2;
settingsSliderDuration: 200;
settingsBackgroundSize: 120px;
settingsUpdateFg: #999999;

View File

@ -28,6 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/flatcheckbox.h"
#include "mainwindow.h"
#include "window/notifications_manager.h"
#include "boxes/notifications_box.h"
namespace Settings {
@ -74,6 +75,10 @@ void NotificationsWidget::createControls() {
if (!nativeNotificationsLabel.isEmpty()) {
addChildRow(_nativeNotifications, margin, nativeNotificationsLabel, SLOT(onNativeNotifications()), Global::NativeNotifications());
}
addChildRow(_advanced, margin, slidedPadding, lang(lng_settings_advanced_notifications), SLOT(onAdvanced()));
if (!nativeNotificationsLabel.isEmpty() && Global::NativeNotifications()) {
_advanced->hideFast();
}
}
void NotificationsWidget::onDesktopNotifications() {
@ -149,6 +154,16 @@ void NotificationsWidget::onNativeNotifications() {
Window::Notifications::manager()->clearAllFast();
Global::SetNativeNotifications(_nativeNotifications->checked());
Local::writeUserSettings();
if (Global::NativeNotifications()) {
_advanced->slideUp();
} else {
_advanced->slideDown();
}
}
void NotificationsWidget::onAdvanced() {
Ui::showLayer(new NotificationsBox());
}
void NotificationsWidget::onPlaySound() {

View File

@ -37,6 +37,7 @@ private slots:
void onNativeNotifications();
void onPlaySound();
void onIncludeMuted();
void onAdvanced();
private:
void createControls();
@ -49,6 +50,7 @@ private:
ChildWidget<Checkbox> _nativeNotifications = { nullptr };
ChildWidget<Checkbox> _playSound = { nullptr };
ChildWidget<Checkbox> _includeMuted = { nullptr };
ChildWidget<Ui::WidgetSlideWrap<LinkButton>> _advanced = { nullptr };
};

View File

@ -27,6 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mainwindow.h"
#include "boxes/confirmbox.h"
#include "application.h"
#include "ui/widgets/discrete_slider.h"
namespace Settings {
namespace {
@ -43,139 +44,6 @@ QString scaleLabel(DBIScale scale) {
} // namespace
Slider::Slider(QWidget *parent) : TWidget(parent)
, _a_left(animation(this, &Slider::step_left)) {
setCursor(style::cur_pointer);
}
void Slider::setActiveSection(int index) {
setSelectedSection(index);
if (_activeIndex != index) {
_activeIndex = index;
emit sectionActivated();
}
}
void Slider::setActiveSectionFast(int index) {
setActiveSection(index);
a_left.finish();
_a_left.stop();
update();
}
void Slider::addSection(const QString &label) {
auto section = Section(label);
_sections.push_back(section);
}
void Slider::resizeSections(int newWidth) {
auto count = _sections.size();
if (!count) return;
auto skips = count - 1;
auto sectionsWidth = newWidth - skips * st::settingsSliderSkip;
auto sectionWidth = sectionsWidth / float64(count);
auto x = 0.;
for (int i = 0; i != count; ++i) {
auto &section = _sections[i];
auto skip = i * st::settingsSliderThickness;
section.left = qFloor(x) + skip;
x += sectionWidth;
section.width = qRound(x) - (section.left - skip);
}
a_left = anim::ivalue(_sections[_activeIndex].left, _sections[_activeIndex].left);
_a_left.stop();
}
void Slider::mousePressEvent(QMouseEvent *e) {
setSelectedSection(getIndexFromPosition(e->pos()));
_pressed = true;
}
void Slider::mouseMoveEvent(QMouseEvent *e) {
if (!_pressed) return;
setSelectedSection(getIndexFromPosition(e->pos()));
}
void Slider::mouseReleaseEvent(QMouseEvent *e) {
if (!_pressed) return;
_pressed = false;
setActiveSection(getIndexFromPosition(e->pos()));
}
void Slider::setSelectedSection(int index) {
if (index < 0) return;
if (_selected != index) {
_selected = index;
a_left.start(_sections[_selected].left);
_a_left.start();
}
}
void Slider::paintEvent(QPaintEvent *e) {
Painter p(this);
int activeLeft = a_left.current();
p.setFont(st::settingsSliderLabelFont);
p.setPen(st::settingsSliderLabelFg);
for (int i = 0, count = _sections.size(); i != count; ++i) {
auto &section = _sections.at(i);
auto from = section.left, tofill = section.width;
if (activeLeft > from) {
auto fill = qMin(tofill, activeLeft - from);
p.fillRect(myrtlrect(from, st::settingsSliderTop, fill, st::settingsSliderThickness), st::settingsSliderInactiveFg);
from += fill;
tofill -= fill;
}
if (activeLeft + section.width > from) {
if (auto fill = qMin(tofill, activeLeft + section.width - from)) {
p.fillRect(myrtlrect(from, st::settingsSliderTop, fill, st::settingsSliderThickness), st::settingsSliderActiveFg);
from += fill;
tofill -= fill;
}
}
if (tofill) {
p.fillRect(myrtlrect(from, st::settingsSliderTop, tofill, st::settingsSliderThickness), st::settingsSliderInactiveFg);
}
p.drawTextLeft(section.left + (section.width - section.labelWidth) / 2, st::settingsSliderLabelTop, width(), section.label, section.labelWidth);
}
}
int Slider::resizeGetHeight(int newWidth) {
resizeSections(newWidth);
return st::settingsSliderHeight;
}
int Slider::getIndexFromPosition(QPoint pos) {
int count = _sections.size();
for (int i = 0; i != count; ++i) {
if (_sections[i].left + _sections[i].width > pos.x()) {
return i;
}
}
return count - 1;
}
void Slider::step_left(float64 ms, bool timer) {
auto dt = ms / st::settingsSliderDuration;
if (dt >= 1) {
a_left.finish();
_a_left.stop();
} else {
a_left.update(dt, anim::linear);
}
if (timer) {
update();
}
}
Slider::Section::Section(const QString &label)
: label(label)
, labelWidth(st::settingsSliderLabelFont->width(label)) {
}
ScaleWidget::ScaleWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_scale)) {
createControls();
}

View File

@ -24,55 +24,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
class Checkbox;
namespace Ui {
class DiscreteSlider;
} // namespace Ui
namespace Settings {
class Slider : public TWidget {
Q_OBJECT
public:
Slider(QWidget *parent);
int activeSection() const {
return _activeIndex;
}
void setActiveSection(int index);
void setActiveSectionFast(int index);
void addSection(const QString &label);
protected:
void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
int resizeGetHeight(int newWidth) override;
signals:
void sectionActivated();
private:
void resizeSections(int newWidth);
int getIndexFromPosition(QPoint pos);
void setSelectedSection(int index);
void step_left(float64 ms, bool timer);
struct Section {
Section(const QString &label);
int left, width;
QString label;
int labelWidth;
};
QList<Section> _sections;
int _activeIndex = 0;
bool _pressed = false;
int _selected = 0;
anim::ivalue a_left = { 0 };
Animation _a_left;
};
class ScaleWidget : public BlockWidget {
Q_OBJECT
@ -89,7 +46,7 @@ private:
void setScale(DBIScale newScale);
ChildWidget<Checkbox> _auto = { nullptr };
ChildWidget<Slider> _scale = { nullptr };
ChildWidget<Ui::DiscreteSlider> _scale = { nullptr };
};

View File

@ -0,0 +1,161 @@
/*
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 "ui/widgets/discrete_slider.h"
#include "styles/style_widgets.h"
namespace Ui {
DiscreteSlider::DiscreteSlider(QWidget *parent) : TWidget(parent)
, _a_left(animation(this, &DiscreteSlider::step_left)) {
setCursor(style::cur_pointer);
}
void DiscreteSlider::setActiveSection(int index) {
setSelectedSection(index);
if (_activeIndex != index) {
_activeIndex = index;
emit sectionActivated();
}
}
void DiscreteSlider::setActiveSectionFast(int index) {
setActiveSection(index);
a_left.finish();
_a_left.stop();
update();
}
void DiscreteSlider::addSection(const QString &label) {
auto section = Section(label);
_sections.push_back(section);
}
void DiscreteSlider::resizeSections(int newWidth) {
auto count = _sections.size();
if (!count) return;
auto skips = count - 1;
auto sectionsWidth = newWidth - skips * st::discreteSliderSkip;
auto sectionWidth = sectionsWidth / float64(count);
auto x = 0.;
for (int i = 0; i != count; ++i) {
auto &section = _sections[i];
auto skip = i * st::discreteSliderThickness;
section.left = qFloor(x) + skip;
x += sectionWidth;
section.width = qRound(x) - (section.left - skip);
}
a_left = anim::ivalue(_sections[_activeIndex].left, _sections[_activeIndex].left);
_a_left.stop();
}
void DiscreteSlider::mousePressEvent(QMouseEvent *e) {
setSelectedSection(getIndexFromPosition(e->pos()));
_pressed = true;
}
void DiscreteSlider::mouseMoveEvent(QMouseEvent *e) {
if (!_pressed) return;
setSelectedSection(getIndexFromPosition(e->pos()));
}
void DiscreteSlider::mouseReleaseEvent(QMouseEvent *e) {
if (!_pressed) return;
_pressed = false;
setActiveSection(getIndexFromPosition(e->pos()));
}
void DiscreteSlider::setSelectedSection(int index) {
if (index < 0) return;
if (_selected != index) {
_selected = index;
a_left.start(_sections[_selected].left);
_a_left.start();
}
}
void DiscreteSlider::paintEvent(QPaintEvent *e) {
Painter p(this);
int activeLeft = a_left.current();
p.setFont(st::discreteSliderLabelFont);
p.setPen(st::discreteSliderLabelFg);
for (int i = 0, count = _sections.size(); i != count; ++i) {
auto &section = _sections.at(i);
auto from = section.left, tofill = section.width;
if (activeLeft > from) {
auto fill = qMin(tofill, activeLeft - from);
p.fillRect(myrtlrect(from, st::discreteSliderTop, fill, st::discreteSliderThickness), st::discreteSliderInactiveFg);
from += fill;
tofill -= fill;
}
if (activeLeft + section.width > from) {
if (auto fill = qMin(tofill, activeLeft + section.width - from)) {
p.fillRect(myrtlrect(from, st::discreteSliderTop, fill, st::discreteSliderThickness), st::discreteSliderActiveFg);
from += fill;
tofill -= fill;
}
}
if (tofill) {
p.fillRect(myrtlrect(from, st::discreteSliderTop, tofill, st::discreteSliderThickness), st::discreteSliderInactiveFg);
}
p.drawTextLeft(section.left + (section.width - section.labelWidth) / 2, st::discreteSliderLabelTop, width(), section.label, section.labelWidth);
}
}
int DiscreteSlider::resizeGetHeight(int newWidth) {
resizeSections(newWidth);
return st::discreteSliderHeight;
}
int DiscreteSlider::getIndexFromPosition(QPoint pos) {
int count = _sections.size();
for (int i = 0; i != count; ++i) {
if (_sections[i].left + _sections[i].width > pos.x()) {
return i;
}
}
return count - 1;
}
void DiscreteSlider::step_left(float64 ms, bool timer) {
auto dt = ms / st::discreteSliderDuration;
if (dt >= 1) {
a_left.finish();
_a_left.stop();
} else {
a_left.update(dt, anim::linear);
}
if (timer) {
update();
}
}
DiscreteSlider::Section::Section(const QString &label)
: label(label)
, labelWidth(st::discreteSliderLabelFont->width(label)) {
}
} // namespace Ui

View File

@ -0,0 +1,72 @@
/*
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
namespace Ui {
class DiscreteSlider : public TWidget {
Q_OBJECT
public:
DiscreteSlider(QWidget *parent);
int activeSection() const {
return _activeIndex;
}
void setActiveSection(int index);
void setActiveSectionFast(int index);
void addSection(const QString &label);
protected:
void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
int resizeGetHeight(int newWidth) override;
signals:
void sectionActivated();
private:
void resizeSections(int newWidth);
int getIndexFromPosition(QPoint pos);
void setSelectedSection(int index);
void step_left(float64 ms, bool timer);
struct Section {
Section(const QString &label);
int left, width;
QString label;
int labelWidth;
};
QList<Section> _sections;
int _activeIndex = 0;
bool _pressed = false;
int _selected = 0;
anim::ivalue a_left = { 0 };
Animation _a_left;
};
} // namespace Ui

View File

@ -34,3 +34,14 @@ defaultLabelSimple: LabelSimple {
}
widgetSlideDuration: 200;
discreteSliderHeight: 39px;
discreteSliderTop: 5px;
discreteSliderSkip: 3px;
discreteSliderThickness: 3px;
discreteSliderActiveFg: #4bb5e7;
discreteSliderInactiveFg: #e1eaef;
discreteSliderLabelTop: 17px;
discreteSliderLabelFont: normalFont;
discreteSliderLabelFg: #1485c2;
discreteSliderDuration: 200;

View File

@ -176,6 +176,8 @@
'<(src_loc)/boxes/languagebox.h',
'<(src_loc)/boxes/localstoragebox.cpp',
'<(src_loc)/boxes/localstoragebox.h',
'<(src_loc)/boxes/notifications_box.cpp',
'<(src_loc)/boxes/notifications_box.h',
'<(src_loc)/boxes/passcodebox.cpp',
'<(src_loc)/boxes/passcodebox.h',
'<(src_loc)/boxes/photocropbox.cpp',
@ -453,6 +455,8 @@
'<(src_loc)/ui/widgets/label_simple.cpp',
'<(src_loc)/ui/widgets/label_simple.h',
'<(src_loc)/ui/widgets/widget_slide_wrap.h',
'<(src_loc)/ui/widgets/discrete_slider.cpp',
'<(src_loc)/ui/widgets/discrete_slider.h',
'<(src_loc)/ui/animation.cpp',
'<(src_loc)/ui/animation.h',
'<(src_loc)/ui/button.cpp',