diff --git a/Telegram/Resources/qrc/telegram/telegram.qrc b/Telegram/Resources/qrc/telegram/telegram.qrc
index 13e96d5ea..37013d170 100644
--- a/Telegram/Resources/qrc/telegram/telegram.qrc
+++ b/Telegram/Resources/qrc/telegram/telegram.qrc
@@ -74,6 +74,7 @@
../../icons/settings/devices/device_desktop_mac.lottie
../../icons/settings/devices/device_desktop_win.lottie
../../icons/settings/devices/device_linux.lottie
+ ../../icons/settings/devices/device_linux_ubuntu.lottie
../../icons/settings/devices/device_phone_android.lottie
../../icons/settings/devices/device_phone_ios.lottie
../../icons/settings/devices/device_tablet_ios.lottie
diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style
index 5dd5c1894..55c010523 100644
--- a/Telegram/SourceFiles/boxes/boxes.style
+++ b/Telegram/SourceFiles/boxes/boxes.style
@@ -279,71 +279,6 @@ membersAbout: FlatLabel(defaultFlatLabel) {
style: boxLabelStyle;
}
-sessionsScroll: boxScroll;
-sessionsHeight: 350px;
-sessionsTerminateAll: SettingsButton(defaultSettingsButton) {
- textFg: attentionButtonFg;
- textFgOver: attentionButtonFgOver;
- font: font(boxFontSize semibold);
- height: 20px;
- padding: margins(77px, 12px, 22px, 10px);
-}
-sessionsTerminateAllIcon: icon {{ "settings/devices/terminate_all", attentionButtonFg }};
-sessionsTerminateAllIconLeft: 30px;
-sessionHeight: 84px;
-sessionInfoTop: 21px;
-sessionLocationTop: 43px;
-sessionCurrentSkip: 8px;
-sessionSubtitleSkip: 14px;
-sessionPadding: margins(77px, 11px, 22px, 0px);
-sessionNameFont: msgNameFont;
-sessionNameFg: boxTextFg;
-sessionWhenFont: msgDateFont;
-sessionWhenFg: windowSubTextFg;
-sessionInfoFont: msgFont;
-sessionInfoFg: windowSubTextFg;
-sessionTerminateTop: 9px;
-sessionTerminateSkip: 22px;
-sessionUserpicSize: 42px;
-sessionUserpicPosition: point(21px, 10px);
-sessionNamePadding: margins(0px, 0px, 5px, 0px);
-sessionTerminate: IconButton {
- width: 20px;
- height: 20px;
-
- icon: smallCloseIcon;
- iconOver: smallCloseIconOver;
- iconPosition: point(5px, 5px);
-
- rippleAreaPosition: point(0px, 0px);
- rippleAreaSize: 20px;
- ripple: RippleAnimation(defaultRippleAnimation) {
- color: windowBgOver;
- }
-}
-sessionNameStyle: TextStyle(defaultTextStyle) {
- font: sessionNameFont;
-}
-sessionWhenStyle: TextStyle(defaultTextStyle) {
- font: sessionWhenFont;
-}
-sessionInfoStyle: TextStyle(defaultTextStyle) {
- font: sessionInfoFont;
-}
-sessionIconWindows: icon{{ "settings/devices/device_desktop_win", historyPeerUserpicFg }};
-sessionIconMac: icon{{ "settings/devices/device_desktop_mac", historyPeerUserpicFg }};
-sessionIconUbuntu: icon{{ "settings/devices/device_linux_ubuntu", historyPeerUserpicFg }};
-sessionIconLinux: icon{{ "settings/devices/device_linux", historyPeerUserpicFg }};
-sessionIconiPhone: icon{{ "settings/devices/device_phone_ios", historyPeerUserpicFg }};
-sessionIconiPad: icon{{ "settings/devices/device_tablet_ios", historyPeerUserpicFg }};
-sessionIconAndroid: icon{{ "settings/devices/device_phone_android", historyPeerUserpicFg }};
-sessionIconWeb: icon{{ "settings/devices/device_web_other", historyPeerUserpicFg }};
-sessionIconChrome: icon{{ "settings/devices/device_web_chrome", historyPeerUserpicFg }};
-sessionIconEdge: icon{{ "settings/devices/device_web_edge", historyPeerUserpicFg }};
-sessionIconFirefox: icon{{ "settings/devices/device_web_firefox", historyPeerUserpicFg }};
-sessionIconSafari: icon{{ "settings/devices/device_web_safari", historyPeerUserpicFg }};
-sessionIconOther: icon{{ "settings/devices/device_other", historyPeerUserpicFg }};
-
passcodeHeaderFont: font(19px);
passcodeHeaderHeight: 80px;
passcodeInput: InputField(introPhone) {
diff --git a/Telegram/SourceFiles/boxes/sessions_box.cpp b/Telegram/SourceFiles/boxes/sessions_box.cpp
index bab50931f..501fdd428 100644
--- a/Telegram/SourceFiles/boxes/sessions_box.cpp
+++ b/Telegram/SourceFiles/boxes/sessions_box.cpp
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/labels.h"
#include "ui/widgets/scroll_area.h"
#include "ui/wrap/slide_wrap.h"
+#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/layers/generic_box.h"
#include "lottie/lottie_icon.h"
@@ -93,56 +94,6 @@ void RenameBox(not_null box) {
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
}
-void SessionInfoBox(
- not_null box,
- const EntryData &data,
- Fn terminate) {
- box->setTitle(rpl::single(data.name));
- box->setWidth(st::boxWidth);
-
- const auto skips = style::margins(0, 0, 0, st::settingsSectionSkip);
- const auto date = base::unixtime::parse(data.activeTime);
- box->addRow(
- object_ptr(
- box,
- rpl::single(langDateTimeFull(date)),
- st::boxDividerLabel),
- st::boxRowPadding + skips);
-
- const auto add = [&](rpl::producer label, QString value) {
- if (value.isEmpty()) {
- return;
- }
- Settings::AddSubsectionTitle(
- box->verticalLayout(),
- std::move(label));
- box->addRow(
- object_ptr(
- box,
- rpl::single(value),
- st::boxDividerLabel),
- st::boxRowPadding + skips);
- };
- add(tr::lng_sessions_application(), data.info);
- add(tr::lng_sessions_system(), data.system);
- add(tr::lng_sessions_ip(), data.ip);
- add(tr::lng_sessions_location(), data.location);
- if (!data.location.isEmpty()) {
- Settings::AddDividerText(
- box->verticalLayout(),
- tr::lng_sessions_location_about());
- }
-
- box->addButton(tr::lng_about_done(), [=] { box->closeBox(); });
- box->addLeftButton(tr::lng_sessions_terminate(), [=, hash = data.hash] {
- const auto weak = Ui::MakeWeak(box.get());
- terminate(hash);
- if (weak) {
- box->closeBox();
- }
- }, st::attentionBoxButton);
-}
-
[[nodiscard]] QString LocationAndDate(const EntryData &entry) {
return (entry.location.isEmpty() ? entry.ip : entry.location)
+ (entry.hash
@@ -265,6 +216,44 @@ void SessionInfoBox(
Unexpected("Type in IconForType.");
}
+[[nodiscard]] const style::icon *IconBigForType(Type type) {
+ switch (type) {
+ case Type::Web: return &st::sessionBigIconWeb;
+ case Type::Other: return &st::sessionBigIconOther;
+ }
+ return nullptr;
+}
+
+[[nodiscard]] std::unique_ptr LottieForType(Type type) {
+ if (IconBigForType(type)) {
+ return nullptr;
+ }
+ const auto path = [&] {
+ switch (type) {
+ case Type::Windows: return "device_desktop_win";
+ case Type::Mac: return "device_desktop_mac";
+ case Type::Ubuntu: return "device_linux_ubuntu";
+ case Type::Linux: return "device_linux";
+ case Type::iPhone: return "device_phone_ios";
+ case Type::iPad: return "device_tablet_ios";
+ case Type::Android: return "device_phone_android";
+ case Type::Chrome: return "device_web_chrome";
+ case Type::Edge: return "device_web_edge";
+ case Type::Firefox: return "device_web_firefox";
+ case Type::Safari: return "device_web_safari";
+ }
+ Unexpected("Type in LottieForType.");
+ }();
+ const auto size = st::sessionBigLottieSize;
+ static const auto kWhite = style::owned_color(Qt::white);
+ return std::make_unique(Lottie::IconDescriptor{
+ .path = u":/icons/settings/devices/"_q + path + u".lottie"_q,
+ .color = kWhite.color(),
+ .sizeOverride = QSize(size, size),
+ .frame = 1,
+ });
+}
+
[[nodiscard]] QImage GenerateUserpic(Type type) {
const auto size = st::sessionUserpicSize;
const auto full = size * style::DevicePixelRatio();
@@ -285,6 +274,172 @@ void SessionInfoBox(
return result;
}
+[[nodiscard]] not_null GenerateUserpicBig(
+ not_null parent,
+ rpl::producer<> shown,
+ Type type) {
+ const auto size = st::sessionBigUserpicSize;
+ const auto full = size * style::DevicePixelRatio();
+ const auto rect = QRect(0, 0, size, size);
+
+ const auto result = Ui::CreateChild(parent.get());
+ result->resize(rect.size());
+ struct State {
+ QImage background;
+ std::unique_ptr lottie;
+ QImage lottieFrame;
+ QImage colorizedFrame;
+ };
+ const auto state = result->lifetime().make_state();
+ state->background = QImage(
+ full,
+ full,
+ QImage::Format_ARGB32_Premultiplied);
+ state->background.fill(Qt::transparent);
+ state->background.setDevicePixelRatio(style::DevicePixelRatio());
+ state->colorizedFrame = state->lottieFrame = state->background;
+
+ auto p = QPainter(&state->background);
+ auto hq = PainterHighQualityEnabler(p);
+ p.setBrush(ColorForType(type));
+ p.setPen(Qt::NoPen);
+ p.drawEllipse(rect);
+ if (const auto icon = IconBigForType(type)) {
+ icon->paintInCenter(p, rect);
+ }
+ p.end();
+
+ if ((state->lottie = LottieForType(type))) {
+ std::move(
+ shown
+ ) | rpl::start_with_next([=] {
+ state->lottie->animate(
+ [=] { result->update(); },
+ 0,
+ state->lottie->framesCount());
+ }, result->lifetime());
+ }
+
+ result->paintRequest(
+ ) | rpl::start_with_next([=] {
+ auto p = QPainter(result);
+ p.drawImage(QPoint(0, 0), state->background);
+ if (state->lottie) {
+ state->lottieFrame.fill(Qt::black);
+ auto q = QPainter(&state->lottieFrame);
+ state->lottie->paintInCenter(q, result->rect());
+ q.end();
+ style::colorizeImage(
+ state->lottieFrame,
+ st::historyPeerUserpicFg->c,
+ &state->colorizedFrame);
+ p.drawImage(QPoint(0, 0), state->colorizedFrame);
+
+ }
+ }, result->lifetime());
+
+ return result;
+}
+
+void SessionInfoBox(
+ not_null box,
+ const EntryData &data,
+ Fn terminate) {
+ box->setWidth(st::boxWideWidth);
+
+ const auto shown = box->lifetime().make_state>();
+ box->setShowFinishedCallback([=] {
+ shown->fire({});
+ });
+
+ const auto userpicWrap = box->addRow(
+ object_ptr(box, st::sessionBigUserpicSize),
+ st::sessionBigCoverPadding);
+ const auto big = GenerateUserpicBig(
+ userpicWrap,
+ shown->events(),
+ TypeFromEntry(data));
+ userpicWrap->sizeValue(
+ ) | rpl::start_with_next([=](QSize size) {
+ big->move((size.width() - big->width()) / 2, 0);
+ }, userpicWrap->lifetime());
+
+ const auto nameWrap = box->addRow(
+ object_ptr(
+ box,
+ st::sessionBigName.maxHeight));
+ const auto name = Ui::CreateChild(
+ nameWrap,
+ rpl::single(data.name),
+ st::sessionBigName);
+ nameWrap->widthValue(
+ ) | rpl::start_with_next([=](int width) {
+ name->resizeToWidth(width);
+ name->move((width - name->width()) / 2, 0);
+ }, name->lifetime());
+
+ const auto dateWrap = box->addRow(
+ object_ptr(
+ box,
+ st::sessionDateLabel.style.font->height),
+ style::margins(0, 0, 0, st::sessionDateSkip));
+ const auto date = Ui::CreateChild(
+ dateWrap,
+ rpl::single(
+ langDateTimeFull(base::unixtime::parse(data.activeTime))),
+ st::sessionDateLabel);
+ rpl::combine(
+ dateWrap->widthValue(),
+ date->widthValue()
+ ) | rpl::start_with_next([=](int outer, int inner) {
+ date->move((outer - inner) / 2, 0);
+ }, date->lifetime());
+
+ using namespace Settings;
+ const auto container = box->verticalLayout();
+ AddDivider(container);
+ AddSkip(container, st::sessionSubtitleSkip);
+ AddSubsectionTitle(container, tr::lng_sessions_info());
+
+ const auto add = [&](rpl::producer label, QString value) {
+ if (value.isEmpty()) {
+ return;
+ }
+ container->add(
+ object_ptr(
+ container,
+ rpl::single(value),
+ st::boxLabel),
+ st::boxRowPadding + st::sessionValuePadding);
+ container->add(
+ object_ptr(
+ container,
+ std::move(label),
+ st::sessionValueLabel),
+ (st::boxRowPadding
+ + style::margins{ 0, 0, 0, st::sessionValueSkip }));
+ };
+ add(tr::lng_sessions_application(), data.info);
+ add(tr::lng_sessions_system(), data.system);
+ add(tr::lng_sessions_ip(), data.ip);
+ add(tr::lng_sessions_location(), data.location);
+ AddSkip(container, st::sessionValueSkip);
+ if (!data.location.isEmpty()) {
+ AddDividerText(container, tr::lng_sessions_location_about());
+ }
+
+ box->addButton(tr::lng_about_done(), [=] { box->closeBox(); });
+ if (const auto hash = data.hash) {
+ box->addLeftButton(tr::lng_sessions_terminate(), [=] {
+ const auto weak = Ui::MakeWeak(box.get());
+ terminate(hash);
+ if (weak) {
+ box->closeBox();
+ }
+ }, st::attentionBoxButton);
+ }
+}
+
} // namespace
class SessionsContent : public Ui::RpWidget {
@@ -737,6 +892,7 @@ rpl::producer SessionsContent::Inner::terminateOne() const {
rpl::producer SessionsContent::Inner::showRequests() const {
return rpl::merge(
+ _current->showRequests(),
_incomplete->showRequests(),
_list->showRequests());
}
diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style
index e06edc15c..d56433435 100644
--- a/Telegram/SourceFiles/settings/settings.style
+++ b/Telegram/SourceFiles/settings/settings.style
@@ -237,3 +237,93 @@ settingsDeviceName: InputField(defaultInputField) {
dictionariesSectionButton: SettingsButton(settingsUpdateToggle) {
font: font(14px semibold);
}
+
+sessionsScroll: boxScroll;
+sessionsHeight: 350px;
+sessionsTerminateAll: SettingsButton(defaultSettingsButton) {
+ textFg: attentionButtonFg;
+ textFgOver: attentionButtonFgOver;
+ font: font(boxFontSize semibold);
+ height: 20px;
+ padding: margins(77px, 12px, 22px, 10px);
+}
+sessionsTerminateAllIcon: icon {{ "settings/devices/terminate_all", attentionButtonFg }};
+sessionsTerminateAllIconLeft: 30px;
+sessionHeight: 84px;
+sessionInfoTop: 21px;
+sessionLocationTop: 43px;
+sessionCurrentSkip: 8px;
+sessionSubtitleSkip: 14px;
+sessionPadding: margins(77px, 11px, 22px, 0px);
+sessionNameFont: msgNameFont;
+sessionNameFg: boxTextFg;
+sessionWhenFont: msgDateFont;
+sessionWhenFg: windowSubTextFg;
+sessionInfoFont: msgFont;
+sessionInfoFg: windowSubTextFg;
+sessionTerminateTop: 9px;
+sessionTerminateSkip: 22px;
+sessionUserpicSize: 42px;
+sessionUserpicPosition: point(21px, 10px);
+sessionNamePadding: margins(0px, 0px, 5px, 0px);
+sessionTerminate: IconButton {
+ width: 20px;
+ height: 20px;
+
+ icon: smallCloseIcon;
+ iconOver: smallCloseIconOver;
+ iconPosition: point(5px, 5px);
+
+ rippleAreaPosition: point(0px, 0px);
+ rippleAreaSize: 20px;
+ ripple: RippleAnimation(defaultRippleAnimation) {
+ color: windowBgOver;
+ }
+}
+sessionNameStyle: TextStyle(defaultTextStyle) {
+ font: sessionNameFont;
+}
+sessionWhenStyle: TextStyle(defaultTextStyle) {
+ font: sessionWhenFont;
+}
+sessionInfoStyle: TextStyle(defaultTextStyle) {
+ font: sessionInfoFont;
+}
+sessionIconWindows: icon{{ "settings/devices/device_desktop_win", historyPeerUserpicFg }};
+sessionIconMac: icon{{ "settings/devices/device_desktop_mac", historyPeerUserpicFg }};
+sessionIconUbuntu: icon{{ "settings/devices/device_linux_ubuntu", historyPeerUserpicFg }};
+sessionIconLinux: icon{{ "settings/devices/device_linux", historyPeerUserpicFg }};
+sessionIconiPhone: icon{{ "settings/devices/device_phone_ios", historyPeerUserpicFg }};
+sessionIconiPad: icon{{ "settings/devices/device_tablet_ios", historyPeerUserpicFg }};
+sessionIconAndroid: icon{{ "settings/devices/device_phone_android", historyPeerUserpicFg }};
+sessionIconWeb: icon{{ "settings/devices/device_web_other", historyPeerUserpicFg }};
+sessionIconChrome: icon{{ "settings/devices/device_web_chrome", historyPeerUserpicFg }};
+sessionIconEdge: icon{{ "settings/devices/device_web_edge", historyPeerUserpicFg }};
+sessionIconFirefox: icon{{ "settings/devices/device_web_firefox", historyPeerUserpicFg }};
+sessionIconSafari: icon{{ "settings/devices/device_web_safari", historyPeerUserpicFg }};
+sessionIconOther: icon{{ "settings/devices/device_other", historyPeerUserpicFg }};
+sessionBigUserpicSize: 70px;
+sessionBigLottieSize: 52px;
+sessionBigIconOther: icon{{ "settings/devices/device_other_large", historyPeerUserpicFg }};
+sessionBigIconWeb: icon{{ "settings/devices/device_web_other_large", historyPeerUserpicFg }};
+sessionBigCoverPadding: margins(0px, 18px, 0px, 7px);
+sessionBigName: FlatLabel(defaultFlatLabel) {
+ textFg: boxTitleFg;
+ maxHeight: 29px;
+ style: TextStyle(defaultTextStyle) {
+ font: font(20px semibold);
+ linkFont: font(20px semibold);
+ linkFontOver: font(20px semibold underline);
+ }
+ align: align(top);
+}
+sessionDateLabel: FlatLabel(defaultFlatLabel) {
+ textFg: windowSubTextFg;
+ align: align(top);
+}
+sessionDateSkip: 19px;
+sessionValuePadding: margins(0px, 5px, 0px, 2px);
+sessionValueLabel: FlatLabel(defaultFlatLabel) {
+ textFg: windowSubTextFg;
+}
+sessionValueSkip: 8px;
diff --git a/Telegram/lib_lottie b/Telegram/lib_lottie
index fd4d8576a..ad7fce76f 160000
--- a/Telegram/lib_lottie
+++ b/Telegram/lib_lottie
@@ -1 +1 @@
-Subproject commit fd4d8576adb611780d1dc7dcce4fe0115eabc9c0
+Subproject commit ad7fce76f3b403471a296c928bae67cd36b8b2cf