Compare commits

...

11 Commits

Author SHA1 Message Date
overinvest 096b985e9e
Merge ab56d522b0 into 2c4d8418c1 2024-04-26 10:57:42 +03:00
23rd 2c4d8418c1 Removed unused code for sponsored messages. 2024-04-26 11:21:41 +04:00
23rd 9fcb5d6f31 Added emoji button to input field for peer title edit. 2024-04-26 11:21:41 +04:00
23rd 38fc6bfbb9 Added special mode to emoji list widget to exclude non-unicode emoji. 2024-04-26 11:21:41 +04:00
23rd 804991a69c Added universal duration to styles. 2024-04-26 11:21:41 +04:00
23rd 7388f46adf Fixed display of subscribers count in dialogs suggestions. 2024-04-26 11:21:41 +04:00
John Preston 10c427127e Fix accidental search focusing. 2024-04-26 11:10:12 +04:00
John Preston c6d034174b Support separate webview storages. 2024-04-26 08:58:42 +04:00
overinvest ab56d522b0
Merge pull request #1 from overinvest/patch-2
This code improves readability and structure by using functional transformations and filtering, as well as explicitly updating userpics
2024-04-17 23:33:57 +03:00
overinvest aaa9332111
Some changes 2024-04-17 23:32:23 +03:00
overinvest 866a2a2a65
Update api_who_reacted.cpp
I split the original RegenerateParticipants function into two separate functions: UpdateExistingParticipants and AddNewParticipants
2024-04-17 23:06:36 +03:00
45 changed files with 400 additions and 216 deletions

View File

@ -416,64 +416,56 @@ struct State {
} }
bool UpdateUserpics( bool UpdateUserpics(
not_null<State*> state, not_null<State*> state,
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const std::vector<PeerWithReaction> &ids) { const std::vector<PeerWithReaction> &ids) {
auto &owner = item->history()->owner(); auto &owner = item->history()->owner();
struct ResolvedPeer { auto resolvePeer = [&](const PeerWithReaction& id) -> std::optional<ResolvedPeer> {
PeerData *peer = nullptr; auto peerData = owner.peerLoaded(id.peerWithDate.peer);
TimeId date = 0; if (peerData) {
bool dateReacted = false; return ResolvedPeer {
ReactionId reaction; .peer = peerData,
}; .date = id.peerWithDate.date,
const auto peers = ranges::views::all( .dateReacted = id.peerWithDate.dateReacted,
ids .reaction = id.reaction
) | ranges::views::transform([&](PeerWithReaction id) { };
return ResolvedPeer{ }
.peer = owner.peerLoaded(id.peerWithDate.peer), return std::nullopt;
.date = id.peerWithDate.date, };
.dateReacted = id.peerWithDate.dateReacted,
.reaction = id.reaction,
};
}) | ranges::views::filter([](ResolvedPeer resolved) {
return resolved.peer != nullptr;
}) | ranges::to_vector;
const auto same = ranges::equal( auto resolvedPeers = ids | ranges::views::transform(resolvePeer)
state->userpics, | ranges::views::filter([](const auto& resolved){ return resolved.has_value(); })
peers, | ranges::views::transform([](const auto& resolved){ return resolved.value(); })
ranges::equal_to(), | ranges::to_vector;
[](const Userpic &u) { return std::pair(u.peer.get(), u.date); },
[](const ResolvedPeer &r) { return std::pair(r.peer, r.date); }); if (ranges::equal(state->userpics, resolvedPeers, {},
if (same) { [](const auto& userpic){ return std::tie(userpic.peer, userpic.date); },
return false; [](const auto& resolved){ return std::tie(resolved.peer, resolved.date); })) {
} return false;
auto &was = state->userpics; }
auto now = std::vector<Userpic>();
for (const auto &resolved : peers) { state->userpics = resolvedPeers | ranges::views::transform([&](const auto& resolved) {
const auto peer = not_null{ resolved.peer }; auto i = ranges::find(state->userpics, resolved.peer, &Userpic::peer);
const auto &data = ReactionEntityData(resolved.reaction); if (i != end(state->userpics) && i->view.cloud) {
const auto i = ranges::find(was, peer, &Userpic::peer); i->date = resolved.date;
if (i != end(was) && i->view.cloud) { i->dateReacted = resolved.dateReacted;
i->date = resolved.date; i->customEntityData = ReactionEntityData(resolved.reaction);
i->dateReacted = resolved.dateReacted; return *i;
now.push_back(std::move(*i)); } else {
now.back().customEntityData = data; auto userpic = Userpic {
continue; .peer = resolved.peer,
} .date = resolved.date,
now.push_back(Userpic{ .dateReacted = resolved.dateReacted,
.peer = peer, .customEntityData = ReactionEntityData(resolved.reaction)
.date = resolved.date, };
.dateReacted = resolved.dateReacted, userpic.uniqueKey = resolved.peer->userpicUniqueKey(userpic.view);
.customEntityData = data, resolved.peer->loadUserpic();
}); return userpic;
auto &userpic = now.back(); }
userpic.uniqueKey = peer->userpicUniqueKey(userpic.view); }) | ranges::to_vector;
peer->loadUserpic();
} return true;
was = std::move(now);
return true;
} }
void RegenerateUserpics(not_null<State*> state, int small, int large) { void RegenerateUserpics(not_null<State*> state, int small, int large) {
@ -500,37 +492,52 @@ void RegenerateUserpics(not_null<State*> state, int small, int large) {
} }
} }
void UpdateExistingParticipants(State& state, const QDateTime& currentDate) {
auto& participants = state.current.participants;
for (auto& userpic : state.userpics) {
const auto peer = userpic.peer;
const auto id = peer->id.value;
const auto wasParticipant = ranges::find(participants, id, &Ui::WhoReadParticipant::id);
if (wasParticipant != end(participants)) {
wasParticipant->name = peer->name();
wasParticipant->date = FormatReadDate(userpic.date, currentDate);
wasParticipant->dateReacted = userpic.dateReacted;
participants.push_back(std::move(*wasParticipant));
}
}
}
void AddNewParticipants(State& state, const QDateTime& currentDate, int small, int large) {
auto& participants = state.current.participants;
for (auto& userpic : state.userpics) {
const auto peer = userpic.peer;
const auto id = peer->id.value;
const auto wasParticipant = ranges::find(participants, id, &Ui::WhoReadParticipant::id);
if (wasParticipant == end(participants)) {
Ui::WhoReadParticipant newParticipant {
.name = peer->name(),
.date = FormatReadDate(userpic.date, currentDate),
.dateReacted = userpic.dateReacted,
.customEntityData = userpic.customEntityData,
.userpicLarge = GenerateUserpic(userpic, large),
.userpicKey = userpic.uniqueKey,
.id = id,
};
participants.push_back(newParticipant);
if (participants.size() <= Ui::WhoReadParticipant::kMaxSmallUserpics) {
participants.back().userpicSmall = GenerateUserpic(userpic, small);
}
}
}
}
void RegenerateParticipants(not_null<State*> state, int small, int large) { void RegenerateParticipants(not_null<State*> state, int small, int large) {
const auto currentDate = QDateTime::currentDateTime(); const QDateTime currentDate = QDateTime::currentDateTime();
auto old = base::take(state->current.participants);
auto &now = state->current.participants; UpdateExistingParticipants(*state, currentDate);
now.reserve(state->userpics.size()); AddNewParticipants(*state, currentDate, small, large);
for (auto &userpic : state->userpics) {
const auto peer = userpic.peer; RegenerateUserpics(state, small, large);
const auto date = userpic.date;
const auto id = peer->id.value;
const auto was = ranges::find(old, id, &Ui::WhoReadParticipant::id);
if (was != end(old)) {
was->name = peer->name();
was->date = FormatReadDate(date, currentDate);
was->dateReacted = userpic.dateReacted;
now.push_back(std::move(*was));
continue;
}
now.push_back({
.name = peer->name(),
.date = FormatReadDate(date, currentDate),
.dateReacted = userpic.dateReacted,
.customEntityData = userpic.customEntityData,
.userpicLarge = GenerateUserpic(userpic, large),
.userpicKey = userpic.uniqueKey,
.id = id,
});
if (now.size() <= Ui::WhoReadParticipant::kMaxSmallUserpics) {
now.back().userpicSmall = GenerateUserpic(userpic, small);
}
}
RegenerateUserpics(state, small, large);
} }
rpl::producer<Ui::WhoReadContent> WhoReacted( rpl::producer<Ui::WhoReadContent> WhoReacted(

View File

@ -546,7 +546,7 @@ rightsToggle: Toggle(defaultToggle) {
vsize: 5px; vsize: 5px;
vshift: 1px; vshift: 1px;
stroke: 2px; stroke: 2px;
duration: 120; duration: universalDuration;
} }
rightsButton: SettingsButton(defaultSettingsButton) { rightsButton: SettingsButton(defaultSettingsButton) {

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_user_names.h" #include "api/api_user_names.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "base/event_filter.h"
#include "boxes/peers/edit_participants_box.h" #include "boxes/peers/edit_participants_box.h"
#include "boxes/peers/edit_peer_color_box.h" #include "boxes/peers/edit_peer_color_box.h"
#include "boxes/peers/edit_peer_common.h" #include "boxes/peers/edit_peer_common.h"
@ -27,6 +28,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/stickers_box.h" #include "boxes/stickers_box.h"
#include "boxes/username_box.h" #include "boxes/username_box.h"
#include "chat_helpers/emoji_suggestions_widget.h" #include "chat_helpers/emoji_suggestions_widget.h"
#include "chat_helpers/tabbed_panel.h"
#include "chat_helpers/tabbed_selector.h"
#include "core/application.h" #include "core/application.h"
#include "core/core_settings.h" #include "core/core_settings.h"
#include "data/data_channel.h" #include "data/data_channel.h"
@ -47,6 +50,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_app_config.h" #include "main/main_app_config.h"
#include "settings/settings_common.h" #include "settings/settings_common.h"
#include "ui/boxes/boost_box.h" #include "ui/boxes/boost_box.h"
#include "ui/controls/emoji_button.h"
#include "ui/controls/userpic_button.h" #include "ui/controls/userpic_button.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "ui/vertical_list.h" #include "ui/vertical_list.h"
@ -61,6 +65,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "api/api_invite_links.h" #include "api/api_invite_links.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_layers.h" #include "styles/style_layers.h"
#include "styles/style_menu_icons.h" #include "styles/style_menu_icons.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
@ -533,7 +538,7 @@ object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
_wrap, _wrap,
object_ptr<Ui::InputField>( object_ptr<Ui::InputField>(
_wrap, _wrap,
st::defaultInputField, st::editPeerTitleField,
(_isBot (_isBot
? tr::lng_dlg_new_bot_name ? tr::lng_dlg_new_bot_name
: _isGroup : _isGroup
@ -555,6 +560,76 @@ object_ptr<Ui::RpWidget> Controller::createTitleEdit() {
submitTitle(); submitTitle();
}, result->entity()->lifetime()); }, result->entity()->lifetime());
{
const auto field = result->entity();
const auto container = _box->getDelegate()->outerContainer();
using Selector = ChatHelpers::TabbedSelector;
using PanelPtr = base::unique_qptr<ChatHelpers::TabbedPanel>;
const auto emojiPanelPtr = field->lifetime().make_state<PanelPtr>(
base::make_unique_q<ChatHelpers::TabbedPanel>(
container,
ChatHelpers::TabbedPanelDescriptor{
.ownedSelector = object_ptr<Selector>(
nullptr,
ChatHelpers::TabbedSelectorDescriptor{
.show = _navigation->uiShow(),
.st = st::defaultComposeControls.tabbed,
.level = Window::GifPauseReason::Layer,
.mode = Selector::Mode::PeerTitle,
}),
}));
const auto emojiPanel = emojiPanelPtr->get();
emojiPanel->setDesiredHeightValues(
1.,
st::emojiPanMinHeight / 2,
st::emojiPanMinHeight);
emojiPanel->hide();
emojiPanel->selector()->setCurrentPeer(_peer);
emojiPanel->selector()->emojiChosen(
) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
Ui::InsertEmojiAtCursor(field->textCursor(), data.emoji);
field->setFocus();
}, field->lifetime());
emojiPanel->setDropDown(true);
const auto emojiToggle = Ui::CreateChild<Ui::EmojiButton>(
field,
st::defaultComposeControls.files.emoji);
emojiToggle->show();
emojiToggle->installEventFilter(emojiPanel);
emojiToggle->addClickHandler([=] { emojiPanel->toggleAnimated(); });
const auto updateEmojiPanelGeometry = [=] {
const auto parent = emojiPanel->parentWidget();
const auto global = emojiToggle->mapToGlobal({ 0, 0 });
const auto local = parent->mapFromGlobal(global);
emojiPanel->moveTopRight(
local.y() + emojiToggle->height(),
local.x() + emojiToggle->width() * 3);
};
base::install_event_filter(container, [=](not_null<QEvent*> event) {
const auto type = event->type();
if (type == QEvent::Move || type == QEvent::Resize) {
crl::on_main(field, [=] { updateEmojiPanelGeometry(); });
}
return base::EventFilterResult::Continue;
});
field->widthValue() | rpl::start_with_next([=](int width) {
const auto &p = st::editPeerTitleEmojiPosition;
emojiToggle->moveToRight(p.x(), p.y(), width);
updateEmojiPanelGeometry();
}, emojiToggle->lifetime());
base::install_event_filter(emojiToggle, [=](not_null<QEvent*> event) {
if (event->type() == QEvent::Enter) {
updateEmojiPanelGeometry();
}
return base::EventFilterResult::Continue;
});
}
_controls.title = result->entity(); _controls.title = result->entity();
return result; return result;
} }

View File

@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h" #include "main/main_session.h"
#include "boxes/abstract_box.h" #include "boxes/abstract_box.h"
#include "base/timer.h" #include "base/timer.h"
#include "styles/style_basic.h"
#include "styles/style_calls.h" #include "styles/style_calls.h"
#include "styles/style_chat_helpers.h" // style::GroupCallUserpics #include "styles/style_chat_helpers.h" // style::GroupCallUserpics
#include "styles/style_layers.h" #include "styles/style_layers.h"
@ -49,7 +50,6 @@ enum class BarState {
namespace { namespace {
constexpr auto kUpdateDebugTimeoutMs = crl::time(500); constexpr auto kUpdateDebugTimeoutMs = crl::time(500);
constexpr auto kSwitchStateDuration = 120;
constexpr auto kMinorBlobAlpha = 76. / 255.; constexpr auto kMinorBlobAlpha = 76. / 255.;
@ -374,7 +374,7 @@ void TopBar::initControls() {
}; };
_switchStateAnimation.stop(); _switchStateAnimation.stop();
const auto duration = (to - from) * kSwitchStateDuration; const auto duration = (to - from) * st::universalDuration;
_switchStateAnimation.start( _switchStateAnimation.start(
_switchStateCallback, _switchStateCallback,
from, from,

View File

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/checkbox.h" #include "ui/widgets/checkbox.h"
#include "ui/widgets/fields/input_field.h" #include "ui/widgets/fields/input_field.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "styles/style_basic.h"
#include "styles/style_calls.h" #include "styles/style_calls.h"
#include "styles/style_layers.h" #include "styles/style_layers.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
@ -26,7 +27,6 @@ namespace {
constexpr auto kRoundRadius = 9; constexpr auto kRoundRadius = 9;
constexpr auto kMaxGroupCallLength = 40; constexpr auto kMaxGroupCallLength = 40;
constexpr auto kSwitchDuration = 200; constexpr auto kSwitchDuration = 200;
constexpr auto kSelectDuration = 120;
class GraphicButton final : public Ui::AbstractButton { class GraphicButton final : public Ui::AbstractButton {
public: public:
@ -103,7 +103,7 @@ void GraphicButton::setToggled(bool value) {
[=] { update(); }, [=] { update(); },
_toggled ? 0. : 1., _toggled ? 0. : 1.,
_toggled ? 1. : 0., _toggled ? 1. : 0.,
kSelectDuration); st::universalDuration);
} }
void GraphicButton::paintEvent(QPaintEvent *e) { void GraphicButton::paintEvent(QPaintEvent *e) {

View File

@ -1108,8 +1108,6 @@ historyRecordVoiceFgOver: historyComposeIconFgOver;
historyRecordVoiceFgInactive: attentionButtonFg; historyRecordVoiceFgInactive: attentionButtonFg;
historyRecordVoiceFgActive: windowBgActive; historyRecordVoiceFgActive: windowBgActive;
historyRecordVoiceFgActiveIcon: windowFgActive; historyRecordVoiceFgActiveIcon: windowFgActive;
historyRecordVoiceShowDuration: 120;
historyRecordVoiceDuration: 120;
historyRecordVoice: icon {{ "chat/input_record", historyRecordVoiceFg }}; historyRecordVoice: icon {{ "chat/input_record", historyRecordVoiceFg }};
historyRecordVoiceOver: icon {{ "chat/input_record", historyRecordVoiceFgOver }}; historyRecordVoiceOver: icon {{ "chat/input_record", historyRecordVoiceFgOver }};
historyRecordVoiceOnceBg: icon {{ "voice_lock/audio_once_bg", historySendIconFg }}; historyRecordVoiceOnceBg: icon {{ "voice_lock/audio_once_bg", historySendIconFg }};

View File

@ -468,7 +468,8 @@ EmojiListWidget::EmojiListWidget(
std::move(descriptor.paused)) std::move(descriptor.paused))
, _show(std::move(descriptor.show)) , _show(std::move(descriptor.show))
, _features(descriptor.features) , _features(descriptor.features)
, _mode(descriptor.mode) , _onlyUnicodeEmoji(descriptor.mode == Mode::PeerTitle)
, _mode(_onlyUnicodeEmoji ? Mode::Full : descriptor.mode)
, _api(&session().mtp()) , _api(&session().mtp())
, _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1) , _staticCount(_mode == Mode::Full ? kEmojiSectionCount : 1)
, _premiumIcon(_mode == Mode::EmojiStatus , _premiumIcon(_mode == Mode::EmojiStatus
@ -490,7 +491,8 @@ EmojiListWidget::EmojiListWidget(
if (_mode != Mode::RecentReactions if (_mode != Mode::RecentReactions
&& _mode != Mode::BackgroundEmoji && _mode != Mode::BackgroundEmoji
&& _mode != Mode::ChannelStatus) { && _mode != Mode::ChannelStatus
&& !_onlyUnicodeEmoji) {
setupSearch(); setupSearch();
} }
@ -1052,7 +1054,7 @@ void EmojiListWidget::fillRecent() {
const auto test = session().isTestMode(); const auto test = session().isTestMode();
for (const auto &one : list) { for (const auto &one : list) {
const auto document = std::get_if<RecentEmojiDocument>(&one.id.data); const auto document = std::get_if<RecentEmojiDocument>(&one.id.data);
if (document && document->test != test) { if (document && ((document->test != test) || _onlyUnicodeEmoji)) {
continue; continue;
} }
_recent.push_back({ _recent.push_back({
@ -2129,7 +2131,9 @@ void EmojiListWidget::refreshCustom() {
auto old = base::take(_custom); auto old = base::take(_custom);
const auto session = &this->session(); const auto session = &this->session();
const auto premiumPossible = session->premiumPossible(); const auto premiumPossible = session->premiumPossible();
const auto premiumMayBeBought = premiumPossible const auto onlyUnicodeEmoji = _onlyUnicodeEmoji || !premiumPossible;
const auto premiumMayBeBought = (!onlyUnicodeEmoji)
&& premiumPossible
&& !session->premium() && !session->premium()
&& !_allowWithoutPremium; && !_allowWithoutPremium;
const auto owner = &session->data(); const auto owner = &session->data();
@ -2189,7 +2193,7 @@ void EmojiListWidget::refreshCustom() {
} }
return true; return true;
}(); }();
if (premium && !premiumPossible) { if (premium && onlyUnicodeEmoji) {
return; return;
} else if (valid) { } else if (valid) {
i->thumbnailDocument = it->second->lookupThumbnailDocument(); i->thumbnailDocument = it->second->lookupThumbnailDocument();
@ -2223,7 +2227,7 @@ void EmojiListWidget::refreshCustom() {
} }
} }
} }
if (premium && !premiumPossible) { if (premium && onlyUnicodeEmoji) {
return; return;
} }
_custom.push_back({ _custom.push_back({

View File

@ -76,6 +76,7 @@ enum class EmojiListMode {
RecentReactions, RecentReactions,
UserpicBuilder, UserpicBuilder,
BackgroundEmoji, BackgroundEmoji,
PeerTitle,
}; };
struct EmojiListDescriptor { struct EmojiListDescriptor {
@ -379,6 +380,7 @@ private:
const std::shared_ptr<Show> _show; const std::shared_ptr<Show> _show;
const ComposeFeatures _features; const ComposeFeatures _features;
const bool _onlyUnicodeEmoji;
Mode _mode = Mode::Full; Mode _mode = Mode::Full;
std::unique_ptr<Ui::TabbedSearch> _search; std::unique_ptr<Ui::TabbedSearch> _search;
MTP::Sender _api; MTP::Sender _api;

View File

@ -38,7 +38,6 @@ namespace {
constexpr auto kShowExactDelay = crl::time(300); constexpr auto kShowExactDelay = crl::time(300);
constexpr auto kMaxNonScrolledEmoji = 7; constexpr auto kMaxNonScrolledEmoji = 7;
constexpr auto kAnimationDuration = crl::time(120);
} // namespace } // namespace
@ -528,7 +527,7 @@ void SuggestionsWidget::setSelected(int selected, anim::type animated) {
[=] { update(); }, [=] { update(); },
_selected, _selected,
selected, selected,
kAnimationDuration, st::universalDuration,
anim::sineInOut); anim::sineInOut);
if (_scrollMax > 0) { if (_scrollMax > 0) {
const auto selectedMax = int(_rows.size()) - 3; const auto selectedMax = int(_rows.size()) - 3;
@ -560,7 +559,7 @@ void SuggestionsWidget::scrollTo(int value, anim::type animated) {
[=] { update(); }, [=] { update(); },
_scrollValue, _scrollValue,
value, value,
kAnimationDuration, st::universalDuration,
anim::sineInOut); anim::sineInOut);
} }
_scrollValue = value; _scrollValue = value;

View File

@ -540,6 +540,8 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) {
? EmojiMode::FullReactions ? EmojiMode::FullReactions
: _mode == Mode::RecentReactions : _mode == Mode::RecentReactions
? EmojiMode::RecentReactions ? EmojiMode::RecentReactions
: _mode == Mode::PeerTitle
? EmojiMode::PeerTitle
: EmojiMode::Full), : EmojiMode::Full),
.customTextColor = _customTextColor, .customTextColor = _customTextColor,
.paused = paused, .paused = paused,
@ -958,6 +960,9 @@ void TabbedSelector::beforeHiding() {
_beforeHidingCallback(_currentTabType); _beforeHidingCallback(_currentTabType);
} }
} }
if (Ui::InFocusChain(this)) {
window()->setFocus();
}
} }
void TabbedSelector::afterShown() { void TabbedSelector::afterShown() {

View File

@ -86,6 +86,7 @@ enum class TabbedSelectorMode {
BackgroundEmoji, BackgroundEmoji,
FullReactions, FullReactions,
RecentReactions, RecentReactions,
PeerTitle,
}; };
struct TabbedSelectorDescriptor { struct TabbedSelectorDescriptor {

View File

@ -116,7 +116,7 @@ dialogsSpeakingDenominator: 8.;
dialogsImportantBarHeight: 37px; dialogsImportantBarHeight: 37px;
dialogsWidthDuration: 120; dialogsWidthDuration: universalDuration;
dialogsTextWidthMin: 150px; dialogsTextWidthMin: 150px;
dialogsTextPalette: TextPalette(defaultTextPalette) { dialogsTextPalette: TextPalette(defaultTextPalette) {

View File

@ -290,7 +290,10 @@ RecentRow::RecentRow(not_null<PeerData*> peer)
} else if (const auto chat = peer->asChat()) { } else if (const auto chat = peer->asChat()) {
if (chat->count > 0) { if (chat->count > 0) {
setCustomStatus( setCustomStatus(
tr::lng_chat_status_members(tr::now, lt_count, chat->count)); tr::lng_chat_status_members(
tr::now,
lt_count_decimal,
chat->count));
} }
} else if (const auto channel = peer->asChannel()) { } else if (const auto channel = peer->asChannel()) {
if (channel->membersCountKnown()) { if (channel->membersCountKnown()) {
@ -298,7 +301,7 @@ RecentRow::RecentRow(not_null<PeerData*> peer)
? tr::lng_chat_status_subscribers ? tr::lng_chat_status_subscribers
: tr::lng_chat_status_members)( : tr::lng_chat_status_members)(
tr::now, tr::now,
lt_count, lt_count_decimal,
channel->membersCount())); channel->membersCount()));
} }
} }
@ -655,7 +658,7 @@ void MyChannelsController::appendRow(not_null<ChannelData*> channel) {
? tr::lng_chat_status_subscribers ? tr::lng_chat_status_subscribers
: tr::lng_chat_status_members)( : tr::lng_chat_status_members)(
tr::now, tr::now,
lt_count, lt_count_decimal,
channel->membersCount())); channel->membersCount()));
} }
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
@ -819,7 +822,7 @@ void RecommendationsController::appendRow(not_null<ChannelData*> channel) {
? tr::lng_chat_status_subscribers ? tr::lng_chat_status_subscribers
: tr::lng_chat_status_members)( : tr::lng_chat_status_members)(
tr::now, tr::now,
lt_count, lt_count_decimal,
channel->membersCount())); channel->membersCount()));
} }
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));

View File

@ -302,7 +302,7 @@ TTLButton::TTLButton(
[=] { update(); }, [=] { update(); },
isActive ? 0. : 1., isActive ? 0. : 1.,
isActive ? 1. : 0., isActive ? 1. : 0.,
st::historyRecordVoiceShowDuration); st::universalDuration);
}); });
Ui::RpWidget::shownValue() | rpl::start_with_next([=](bool shown) { Ui::RpWidget::shownValue() | rpl::start_with_next([=](bool shown) {
@ -1058,9 +1058,11 @@ void RecordLock::drawProgress(QPainter &p) {
} }
void RecordLock::startLockingAnimation(float64 to) { void RecordLock::startLockingAnimation(float64 to) {
auto callback = [=](float64 value) { setProgress(value); }; _lockEnderAnimation.start(
const auto &duration = st::historyRecordVoiceShowDuration; [=](float64 value) { setProgress(value); },
_lockEnderAnimation.start(std::move(callback), 0., to, duration); 0.,
to,
st::universalDuration);
} }
void RecordLock::requestPaintProgress(float64 progress) { void RecordLock::requestPaintProgress(float64 progress) {
@ -1453,7 +1455,7 @@ void VoiceRecordBar::init() {
if (!value) { if (!value) {
_listen = nullptr; _listen = nullptr;
} }
}, 1., 0., st::historyRecordVoiceShowDuration * 2); }, 1., 0., st::universalDuration * 2);
setLevelAsSend(); setLevelAsSend();
return; return;
@ -1473,7 +1475,6 @@ void VoiceRecordBar::init() {
// _lockShowing = false; // _lockShowing = false;
const auto to = 1.; const auto to = 1.;
const auto &duration = st::historyRecordVoiceShowDuration;
auto callback = [=](float64 value) { auto callback = [=](float64 value) {
paintShowListenCallback(value); paintShowListenCallback(value);
if (to == value) { if (to == value) {
@ -1481,7 +1482,11 @@ void VoiceRecordBar::init() {
} }
}; };
_showListenAnimation.stop(); _showListenAnimation.stop();
_showListenAnimation.start(std::move(callback), 0., to, duration); _showListenAnimation.start(
std::move(callback),
0.,
to,
st::universalDuration);
}, lifetime()); }, lifetime());
_lock->locks( _lock->locks(
@ -1498,15 +1503,16 @@ void VoiceRecordBar::init() {
setLevelAsSend(); setLevelAsSend();
const auto &duration = st::historyRecordVoiceShowDuration;
const auto from = 0.;
const auto to = 1.;
auto callback = [=](float64 value) { auto callback = [=](float64 value) {
_lock->requestPaintLockToStopProgress(value); _lock->requestPaintLockToStopProgress(value);
update(); update();
updateTTLGeometry(TTLAnimationType::RightLeft, value); updateTTLGeometry(TTLAnimationType::RightLeft, value);
}; };
_lockToStopAnimation.start(std::move(callback), from, to, duration); _lockToStopAnimation.start(
std::move(callback),
0.,
1.,
st::universalDuration);
}, lifetime()); }, lifetime());
_send->events( _send->events(
@ -1523,7 +1529,7 @@ void VoiceRecordBar::init() {
return; return;
} }
_recordingTipRequired = true; _recordingTipRequired = true;
_startTimer.callOnce(st::historyRecordVoiceShowDuration); _startTimer.callOnce(st::universalDuration);
} else if (e->type() == QEvent::MouseButtonRelease) { } else if (e->type() == QEvent::MouseButtonRelease) {
if (base::take(_recordingTipRequired)) { if (base::take(_recordingTipRequired)) {
_recordingTipRequests.fire({}); _recordingTipRequests.fire({});
@ -1556,23 +1562,24 @@ void VoiceRecordBar::init() {
void VoiceRecordBar::activeAnimate(bool active) { void VoiceRecordBar::activeAnimate(bool active) {
const auto to = active ? 1. : 0.; const auto to = active ? 1. : 0.;
const auto &duration = st::historyRecordVoiceDuration;
if (_activeAnimation.animating()) { if (_activeAnimation.animating()) {
_activeAnimation.change(to, duration); _activeAnimation.change(to, st::universalDuration);
} else { } else {
auto callback = [=] { auto callback = [=] {
update(_messageRect); update(_messageRect);
_level->requestPaintColor(activeAnimationRatio()); _level->requestPaintColor(activeAnimationRatio());
}; };
const auto from = active ? 0. : 1.; _activeAnimation.start(
_activeAnimation.start(std::move(callback), from, to, duration); std::move(callback),
active ? 0. : 1.,
to,
st::universalDuration);
} }
} }
void VoiceRecordBar::visibilityAnimate(bool show, Fn<void()> &&callback) { void VoiceRecordBar::visibilityAnimate(bool show, Fn<void()> &&callback) {
const auto to = show ? 1. : 0.; const auto to = show ? 1. : 0.;
const auto from = show ? 0. : 1.; const auto from = show ? 0. : 1.;
const auto &duration = st::historyRecordVoiceShowDuration;
auto animationCallback = [=, callback = std::move(callback)](auto value) { auto animationCallback = [=, callback = std::move(callback)](auto value) {
if (!_listen) { if (!_listen) {
_level->requestPaintProgress(value); _level->requestPaintProgress(value);
@ -1589,7 +1596,11 @@ void VoiceRecordBar::visibilityAnimate(bool show, Fn<void()> &&callback) {
} }
} }
}; };
_showAnimation.start(std::move(animationCallback), from, to, duration); _showAnimation.start(
std::move(animationCallback),
from,
to,
st::universalDuration);
} }
void VoiceRecordBar::setStartRecordingFilter(FilterCallback &&callback) { void VoiceRecordBar::setStartRecordingFilter(FilterCallback &&callback) {

View File

@ -196,8 +196,8 @@ void VoiceRecordButton::init() {
} }
update(); update();
}; };
const auto duration = st::historyRecordVoiceDuration * 2; constexpr auto kDuration = st::universalDuration * 2;
_stateChangedAnimation.start(std::move(callback), 0., to, duration); _stateChangedAnimation.start(std::move(callback), 0., to, kDuration);
}, lifetime()); }, lifetime());
} }

View File

@ -548,8 +548,6 @@ QSize WebPage::countCurrentSize(int newWidth) {
const auto twoTitleLines = 2 * st::webPageTitleFont->height; const auto twoTitleLines = 2 * st::webPageTitleFont->height;
const auto descriptionLineHeight = st::webPageDescriptionFont->height; const auto descriptionLineHeight = st::webPageDescriptionFont->height;
if (asArticle() || specialRightPix) { if (asArticle() || specialRightPix) {
const auto sponsoredUserpic = (_sponsoredData
&& _sponsoredData->peer);
constexpr auto kSponsoredUserpicLines = 2; constexpr auto kSponsoredUserpicLines = 2;
_pixh = lineHeight _pixh = lineHeight
* (_stickerSet * (_stickerSet
@ -576,8 +574,7 @@ QSize WebPage::countCurrentSize(int newWidth) {
newHeight += _titleLines * lineHeight; newHeight += _titleLines * lineHeight;
} }
const auto descriptionHeight = _description.countHeight( const auto descriptionHeight = _description.countHeight(wleft);
sponsoredUserpic ? innerWidth : wleft);
const auto restLines = (linesMax - _siteNameLines - _titleLines); const auto restLines = (linesMax - _siteNameLines - _titleLines);
if (descriptionHeight < restLines * descriptionLineHeight) { if (descriptionHeight < restLines * descriptionLineHeight) {
// We have height for all the lines. // We have height for all the lines.
@ -677,7 +674,6 @@ void WebPage::ensurePhotoMediaCreated() const {
bool WebPage::hasHeavyPart() const { bool WebPage::hasHeavyPart() const {
return _photoMedia return _photoMedia
|| (_sponsoredData && !_sponsoredData->userpicView.null())
|| (_stickerSet) || (_stickerSet)
|| (_attach ? _attach->hasHeavyPart() : false); || (_attach ? _attach->hasHeavyPart() : false);
} }
@ -688,9 +684,6 @@ void WebPage::unloadHeavyPart() {
} }
_description.unloadPersistentAnimation(); _description.unloadPersistentAnimation();
_photoMedia = nullptr; _photoMedia = nullptr;
if (_sponsoredData) {
_sponsoredData->userpicView = Ui::PeerUserpicView();
}
} }
void WebPage::draw(Painter &p, const PaintContext &context) const { void WebPage::draw(Painter &p, const PaintContext &context) const {
@ -834,21 +827,6 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
// as its width only affects the title. // as its width only affects the title.
paintw -= pw + st::webPagePhotoDelta; paintw -= pw + st::webPagePhotoDelta;
} }
} else if (asSponsored && _sponsoredData->peer) {
const auto size = _pixh;
const auto sizeHq = size * style::DevicePixelRatio();
const auto userpicPos = QPoint(inner.left() + paintw - size, tshift);
const auto &peer = _sponsoredData->peer;
auto &view = _sponsoredData->userpicView;
if (const auto cloud = peer->userpicCloudImage(view)) {
Ui::ValidateUserpicCache(view, cloud, nullptr, sizeHq, true);
p.drawImage(QRect(userpicPos, QSize(size, size)), view.cached);
} else {
const auto r = sizeHq * Ui::ForumUserpicRadiusMultiplier();
const auto empty = peer->generateUserpicImage(view, sizeHq, r);
p.drawImage(QRect(userpicPos, QSize(size, size)), empty);
}
// paintw -= size + st::webPagePhotoDelta;
} }
if (_siteNameLines) { if (_siteNameLines) {
p.setPen(cache->icon); p.setPen(cache->icon);

View File

@ -139,8 +139,6 @@ private:
std::unique_ptr<StickerSet> _stickerSet; std::unique_ptr<StickerSet> _stickerSet;
struct SponsoredData final { struct SponsoredData final {
PeerData *peer = nullptr;
Ui::PeerUserpicView userpicView;
QString buttonText; QString buttonText;
bool isLinkInternal = false; bool isLinkInternal = false;

View File

@ -722,6 +722,10 @@ editPeerHistoryVisibilityTopSkip: 8px;
editPeerPhotoMargins: margins(22px, 8px, 22px, 8px); editPeerPhotoMargins: margins(22px, 8px, 22px, 8px);
editPeerTitle: defaultInputField; editPeerTitle: defaultInputField;
editPeerTitleMargins: margins(27px, 13px, 22px, 8px); editPeerTitleMargins: margins(27px, 13px, 22px, 8px);
editPeerTitleEmojiPosition: point(0px, 23px);
editPeerTitleField: InputField(defaultInputField) {
textMargins: margins(0px, 28px, 30px, 4px);
}
editPeerDescription: InputField(defaultInputField) { editPeerDescription: InputField(defaultInputField) {
textBg: transparent; textBg: transparent;
textMargins: margins(0px, 7px, 0px, 7px); textMargins: margins(0px, 7px, 0px, 7px);

View File

@ -58,7 +58,16 @@ void PickUntilBox(not_null<Ui::GenericBox*> box, Fn<void(TimeId)> callback) {
EmojiStatusPanel::EmojiStatusPanel() = default; EmojiStatusPanel::EmojiStatusPanel() = default;
EmojiStatusPanel::~EmojiStatusPanel() = default; EmojiStatusPanel::~EmojiStatusPanel() {
if (hasFocus()) {
// Panel will try to return focus to the layer widget, the problem is
// we are destroying the layer widget probably right now and focusing
// it will lead to a crash, because it destroys its children (how we
// got here) after it clears focus out of itself. So if you return
// the focus inside a child destructor, it won't be cleared at all.
_panel->window()->setFocus();
}
}
void EmojiStatusPanel::setChooseFilter(Fn<bool(DocumentId)> filter) { void EmojiStatusPanel::setChooseFilter(Fn<bool(DocumentId)> filter) {
_chooseFilter = std::move(filter); _chooseFilter = std::move(filter);

View File

@ -66,5 +66,3 @@ userpicBuilderEmojiColorPlus: IconButton(userpicBuilderEmojiColorMinus) {
} }
userpicBuilderEmojiToggleStickersIcon: icon {{ "menu/stickers", emojiIconFg }}; userpicBuilderEmojiToggleStickersIcon: icon {{ "menu/stickers", emojiIconFg }};
userpicBuilderEmojiSlideDuration: 120;

View File

@ -137,7 +137,7 @@ void ColorsLine::fillButtons() {
wasChosen->setSelectedProgress(1. - progress); wasChosen->setSelectedProgress(1. - progress);
} }
nowChosen->setSelectedProgress(progress); nowChosen->setSelectedProgress(progress);
}, 0., 1., st::userpicBuilderEmojiSlideDuration); }, 0., 1., st::universalDuration);
}); });
if (i < _colors->size()) { if (i < _colors->size()) {
button->setBrush((*_colors)[i]); button->setBrush((*_colors)[i]);
@ -164,7 +164,7 @@ void ColorsLine::fillButtons() {
setLastChosen(); setLastChosen();
}); });
for (const auto &wrap : _wraps) { for (const auto &wrap : _wraps) {
wrap->setDuration(st::userpicBuilderEmojiSlideDuration); wrap->setDuration(st::universalDuration);
} }
} }
@ -213,7 +213,7 @@ void ColorsLine::processChange(
const auto left = anim::interpolate(wasLeft, nowLeft, value); const auto left = anim::interpolate(wasLeft, nowLeft, value);
_wraps[i]->moveToLeft(left, 0); _wraps[i]->moveToLeft(left, 0);
} }
}, 0., 1., st::userpicBuilderEmojiSlideDuration); }, 0., 1., st::universalDuration);
} }
void ColorsLine::setLastChosen() const { void ColorsLine::setLastChosen() const {

View File

@ -493,7 +493,7 @@ not_null<Ui::VerticalLayout*> CreateUserpicBuilder(
1. - progress); 1. - progress);
} }
state->circleButtons[now]->setSelectedProgress(progress); state->circleButtons[now]->setSelectedProgress(progress);
}, 0., 1., st::userpicBuilderEmojiSlideDuration); }, 0., 1., st::universalDuration);
state->colorIndex = now; state->colorIndex = now;
const auto result = isSpecial const auto result = isSpecial

View File

@ -1491,7 +1491,7 @@ void AttachWebView::show(
_catchingCancelInShowCall = true; _catchingCancelInShowCall = true;
_panel = Ui::BotWebView::Show({ _panel = Ui::BotWebView::Show({
.url = url, .url = url,
.userDataPath = _session->domain().local().webviewDataPath(), .storageId = _session->local().resolveStorageIdBots(),
.title = std::move(title), .title = std::move(title),
.bottom = rpl::single('@' + _bot->username()), .bottom = rpl::single('@' + _bot->username()),
.delegate = static_cast<Ui::BotWebView::Delegate*>(this), .delegate = static_cast<Ui::BotWebView::Delegate*>(this),

View File

@ -119,7 +119,6 @@ introCodeDigitFont: font(20px);
introCodeDigitHeight: 50px; introCodeDigitHeight: 50px;
introCodeDigitBorderWidth: 4px; introCodeDigitBorderWidth: 4px;
introCodeDigitSkip: 10px; introCodeDigitSkip: 10px;
introCodeDigitAnimatioDuration: 120;
introPasswordHint: FlatLabel(introDescription) { introPasswordHint: FlatLabel(introDescription) {
textFg: windowFg; textFg: windowFg;

View File

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/painter.h" #include "ui/painter.h"
#include "ui/rect.h" #include "ui/rect.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "styles/style_basic.h"
#include "styles/style_intro.h" #include "styles/style_intro.h"
#include "styles/style_layers.h" // boxRadius #include "styles/style_layers.h" // boxRadius
@ -91,7 +92,6 @@ void CodeDigit::setDigit(int digit) {
} }
_dataDigit = digit; _dataDigit = digit;
if (_viewDigit != digit) { if (_viewDigit != digit) {
constexpr auto kDuration = st::introCodeDigitAnimatioDuration;
_animation.stop(); _animation.stop();
if (digit == kDigitNone) { if (digit == kDigitNone) {
_animation.start([=](float64 value) { _animation.start([=](float64 value) {
@ -99,10 +99,10 @@ void CodeDigit::setDigit(int digit) {
if (!value) { if (!value) {
_viewDigit = digit; _viewDigit = digit;
} }
}, 1., 0., kDuration); }, 1., 0., st::universalDuration);
} else { } else {
_viewDigit = digit; _viewDigit = digit;
_animation.start([=] { update(); }, 0., 1., kDuration); _animation.start([=] { update(); }, 0, 1., st::universalDuration);
} }
} }
} }

View File

@ -224,6 +224,7 @@ void Step::createSession(
account->createSession(user, std::move(settings)); account->createSession(user, std::move(settings));
// "this" is already deleted here by creating the main widget. // "this" is already deleted here by creating the main widget.
account->local().enforceModernStorageIdBots();
account->local().writeMtpData(); account->local().writeMtpData();
auto &session = account->session(); auto &session = account->session();
session.data().chatsFilters().setPreloaded(filters); session.data().chatsFilters().setPreloaded(filters);

View File

@ -292,12 +292,12 @@ void Controller::initControls() {
} }
void Controller::show( void Controller::show(
const QString &dataPath, const Webview::StorageId &storageId,
Prepared page, Prepared page,
base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues) { base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues) {
page.script = fillInChannelValuesScript(std::move(inChannelValues)); page.script = fillInChannelValuesScript(std::move(inChannelValues));
InvokeQueued(_container, [=, page = std::move(page)]() mutable { InvokeQueued(_container, [=, page = std::move(page)]() mutable {
showInWindow(dataPath, std::move(page)); showInWindow(storageId, std::move(page));
}); });
} }
@ -389,7 +389,7 @@ void Controller::createWindow() {
window->show(); window->show();
} }
void Controller::createWebview(const QString &dataPath) { void Controller::createWebview(const Webview::StorageId &storageId) {
Expects(!_webview); Expects(!_webview);
const auto window = _window.get(); const auto window = _window.get();
@ -397,7 +397,7 @@ void Controller::createWebview(const QString &dataPath) {
_container, _container,
Webview::WindowConfig{ Webview::WindowConfig{
.opaqueBg = st::windowBg->c, .opaqueBg = st::windowBg->c,
.userDataPath = dataPath, .storageId = storageId,
}); });
const auto raw = _webview.get(); const auto raw = _webview.get();
@ -558,7 +558,9 @@ void Controller::createWebview(const QString &dataPath) {
raw->init(R"()"); raw->init(R"()");
} }
void Controller::showInWindow(const QString &dataPath, Prepared page) { void Controller::showInWindow(
const Webview::StorageId &storageId,
Prepared page) {
Expects(_container != nullptr); Expects(_container != nullptr);
const auto url = page.url; const auto url = page.url;
@ -571,7 +573,7 @@ void Controller::showInWindow(const QString &dataPath, Prepared page) {
const auto index = i->second; const auto index = i->second;
_index = index; _index = index;
if (!_webview) { if (!_webview) {
createWebview(dataPath); createWebview(storageId);
if (_webview && _webview->widget()) { if (_webview && _webview->widget()) {
auto id = u"iv/page%1.html"_q.arg(index); auto id = u"iv/page%1.html"_q.arg(index);
if (!_hash.isEmpty()) { if (!_hash.isEmpty()) {

View File

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "iv/iv_delegate.h" #include "iv/iv_delegate.h"
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/text/text.h" #include "ui/text/text.h"
#include "webview/webview_common.h"
class Painter; class Painter;
@ -69,7 +70,7 @@ public:
}; };
void show( void show(
const QString &dataPath, const Webview::StorageId &storageId,
Prepared page, Prepared page,
base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues); base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues);
void update(Prepared page); void update(Prepared page);
@ -90,11 +91,11 @@ public:
private: private:
void createWindow(); void createWindow();
void createWebview(const QString &dataPath); void createWebview(const Webview::StorageId &storageId);
[[nodiscard]] QByteArray navigateScript(int index, const QString &hash); [[nodiscard]] QByteArray navigateScript(int index, const QString &hash);
[[nodiscard]] QByteArray reloadScript(int index); [[nodiscard]] QByteArray reloadScript(int index);
void showInWindow(const QString &dataPath, Prepared page); void showInWindow(const Webview::StorageId &storageId, Prepared page);
[[nodiscard]] QByteArray fillInChannelValuesScript( [[nodiscard]] QByteArray fillInChannelValuesScript(
base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues); base::flat_map<QByteArray, rpl::producer<bool>> inChannelValues);
[[nodiscard]] QByteArray toggleInChannelScript( [[nodiscard]] QByteArray toggleInChannelScript(

View File

@ -31,13 +31,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "lottie/lottie_common.h" // Lottie::ReadContent. #include "lottie/lottie_common.h" // Lottie::ReadContent.
#include "main/main_account.h" #include "main/main_account.h"
#include "main/main_domain.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "main/session/session_show.h" #include "main/session/session_show.h"
#include "media/streaming/media_streaming_loader.h" #include "media/streaming/media_streaming_loader.h"
#include "media/view/media_view_open_common.h" #include "media/view/media_view_open_common.h"
#include "storage/file_download.h" #include "storage/file_download.h"
#include "storage/storage_domain.h" #include "storage/storage_account.h"
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "ui/layers/layer_widget.h" #include "ui/layers/layer_widget.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
@ -348,9 +347,8 @@ void Shown::showWindowed(Prepared result) {
createController(); createController();
} }
const auto domain = &_session->domain();
_controller->show( _controller->show(
domain->local().webviewDataPath(), _session->local().resolveStorageIdOther(),
std::move(result), std::move(result),
base::duplicate(_inChannelValues)); base::duplicate(_inChannelValues));
} }

View File

@ -2644,6 +2644,10 @@ bool MainWidget::eventFilter(QObject *o, QEvent *e) {
if (e->type() == QEvent::FocusIn) { if (e->type() == QEvent::FocusIn) {
if (widget && relevantForDialogsFocus(widget)) { if (widget && relevantForDialogsFocus(widget)) {
_dialogs->updateHasFocus(widget); _dialogs->updateHasFocus(widget);
} else if (widget == window()) {
crl::on_main(this, [=] {
_controller->widget()->setInnerFocus();
});
} }
} else if (e->type() == QEvent::MouseButtonPress) { } else if (e->type() == QEvent::MouseButtonPress) {
if (widget && (widget->window() == window())) { if (widget && (widget->window() == window())) {

View File

@ -11,8 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "payments/ui/payments_panel.h" #include "payments/ui/payments_panel.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "main/main_account.h" #include "main/main_account.h"
#include "main/main_domain.h" #include "storage/storage_account.h"
#include "storage/storage_domain.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history.h" #include "history/history.h"
#include "data/data_user.h" // UserData::isBot. #include "data/data_user.h" // UserData::isBot.
@ -25,7 +24,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h" #include "apiwrap.h"
#include "api/api_cloud_password.h" #include "api/api_cloud_password.h"
#include "window/themes/window_theme.h" #include "window/themes/window_theme.h"
#include "webview/webview_interface.h"
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
@ -877,8 +875,8 @@ void CheckoutProcess::performInitialSilentValidation() {
_form->validateInformation(saved); _form->validateInformation(saved);
} }
QString CheckoutProcess::panelWebviewDataPath() { Webview::StorageId CheckoutProcess::panelWebviewStorageId() {
return _session->domain().local().webviewDataPath(); return _session->local().resolveStorageIdOther();
} }
Webview::ThemeParams CheckoutProcess::panelWebviewThemeParams() { Webview::ThemeParams CheckoutProcess::panelWebviewThemeParams() {

View File

@ -7,8 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "payments/ui/payments_panel_delegate.h"
#include "base/weak_ptr.h" #include "base/weak_ptr.h"
#include "payments/ui/payments_panel_delegate.h"
#include "webview/webview_common.h"
class HistoryItem; class HistoryItem;
class PasscodeBox; class PasscodeBox;
@ -153,7 +154,7 @@ private:
void panelShowBox(object_ptr<Ui::BoxContent> box) override; void panelShowBox(object_ptr<Ui::BoxContent> box) override;
QVariant panelClickHandlerContext() override; QVariant panelClickHandlerContext() override;
QString panelWebviewDataPath() override; Webview::StorageId panelWebviewStorageId() override;
Webview::ThemeParams panelWebviewThemeParams() override; Webview::ThemeParams panelWebviewThemeParams() override;
std::optional<QDate> panelOverrideExpireDateThreshold() override; std::optional<QDate> panelOverrideExpireDateThreshold() override;

View File

@ -547,7 +547,7 @@ bool Panel::createWebview(const Webview::ThemeParams &params) {
container, container,
Webview::WindowConfig{ Webview::WindowConfig{
.opaqueBg = params.opaqueBg, .opaqueBg = params.opaqueBg,
.userDataPath = _delegate->panelWebviewDataPath(), .storageId = _delegate->panelWebviewStorageId(),
}); });
const auto raw = &_webview->window; const auto raw = &_webview->window;

View File

@ -18,6 +18,7 @@ class BoxContent;
namespace Webview { namespace Webview {
struct ThemeParams; struct ThemeParams;
struct StorageId;
} // namespace Webview } // namespace Webview
namespace Payments::Ui { namespace Payments::Ui {
@ -59,7 +60,7 @@ public:
virtual void panelShowBox(object_ptr<BoxContent> box) = 0; virtual void panelShowBox(object_ptr<BoxContent> box) = 0;
virtual QVariant panelClickHandlerContext() = 0; virtual QVariant panelClickHandlerContext() = 0;
virtual QString panelWebviewDataPath() = 0; virtual Webview::StorageId panelWebviewStorageId() = 0;
virtual Webview::ThemeParams panelWebviewThemeParams() = 0; virtual Webview::ThemeParams panelWebviewThemeParams() = 0;
virtual std::optional<QDate> panelOverrideExpireDateThreshold() = 0; virtual std::optional<QDate> panelOverrideExpireDateThreshold() = 0;

View File

@ -165,16 +165,7 @@ Cover::Cover(
}, _name->lifetime()); }, _name->lifetime());
} }
Cover::~Cover() { Cover::~Cover() = default;
if (_emojiStatusPanel.hasFocus()) {
// Panel will try to return focus to the layer widget, the problem is
// we are destroying the layer widget probably right now and focusing
// it will lead to a crash, because it destroys its children (how we
// got here) after it clears focus out of itself. So if you return
// the focus inside a child destructor, it won't be cleared at all.
window()->setFocus();
}
}
void Cover::setupChildGeometry() { void Cover::setupChildGeometry() {
using namespace rpl::mappers; using namespace rpl::mappers;

View File

@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/serialize_peer.h" #include "storage/serialize_peer.h"
#include "storage/serialize_document.h" #include "storage/serialize_document.h"
#include "main/main_account.h" #include "main/main_account.h"
#include "main/main_domain.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "mtproto/mtproto_config.h" #include "mtproto/mtproto_config.h"
#include "mtproto/mtproto_dc_options.h" #include "mtproto/mtproto_dc_options.h"
@ -35,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_drafts.h" #include "data/data_drafts.h"
#include "export/export_settings.h" #include "export/export_settings.h"
#include "webview/webview_interface.h"
#include "window/themes/window_theme.h" #include "window/themes/window_theme.h"
namespace Storage { namespace Storage {
@ -91,6 +93,7 @@ enum { // Local Storage Keys
lskMasksKeys = 0x16, // no data lskMasksKeys = 0x16, // no data
lskCustomEmojiKeys = 0x17, // no data lskCustomEmojiKeys = 0x17, // no data
lskSearchSuggestions = 0x18, // no data lskSearchSuggestions = 0x18, // no data
lskWebviewTokens = 0x19, // data: QByteArray bots, QByteArray other
}; };
auto EmptyMessageDraftSources() auto EmptyMessageDraftSources()
@ -303,6 +306,7 @@ Account::ReadMapResult Account::readMapWith(
quint64 legacyBackgroundKeyDay = 0, legacyBackgroundKeyNight = 0; quint64 legacyBackgroundKeyDay = 0, legacyBackgroundKeyNight = 0;
quint64 userSettingsKey = 0, recentHashtagsAndBotsKey = 0, exportSettingsKey = 0; quint64 userSettingsKey = 0, recentHashtagsAndBotsKey = 0, exportSettingsKey = 0;
quint64 searchSuggestionsKey = 0; quint64 searchSuggestionsKey = 0;
QByteArray webviewStorageTokenBots, webviewStorageTokenOther;
while (!map.stream.atEnd()) { while (!map.stream.atEnd()) {
quint32 keyType; quint32 keyType;
map.stream >> keyType; map.stream >> keyType;
@ -411,6 +415,11 @@ Account::ReadMapResult Account::readMapWith(
case lskSearchSuggestions: { case lskSearchSuggestions: {
map.stream >> searchSuggestionsKey; map.stream >> searchSuggestionsKey;
} break; } break;
case lskWebviewTokens: {
map.stream
>> webviewStorageTokenBots
>> webviewStorageTokenOther;
} break;
default: default:
LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType)); LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType));
return ReadMapResult::Failed; return ReadMapResult::Failed;
@ -448,6 +457,8 @@ Account::ReadMapResult Account::readMapWith(
_exportSettingsKey = exportSettingsKey; _exportSettingsKey = exportSettingsKey;
_searchSuggestionsKey = searchSuggestionsKey; _searchSuggestionsKey = searchSuggestionsKey;
_oldMapVersion = mapData.version; _oldMapVersion = mapData.version;
_webviewStorageIdBots.token = webviewStorageTokenBots;
_webviewStorageIdOther.token = webviewStorageTokenOther;
if (_oldMapVersion < AppVersion) { if (_oldMapVersion < AppVersion) {
writeMapDelayed(); writeMapDelayed();
@ -553,6 +564,12 @@ void Account::writeMap() {
mapSize += sizeof(quint32) + 3 * sizeof(quint64); mapSize += sizeof(quint32) + 3 * sizeof(quint64);
} }
if (_searchSuggestionsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_searchSuggestionsKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (!_webviewStorageIdBots.token.isEmpty()
|| !_webviewStorageIdOther.token.isEmpty()) {
mapSize += sizeof(quint32)
+ Serialize::bytearraySize(_webviewStorageIdBots.token)
+ Serialize::bytearraySize(_webviewStorageIdOther.token);
}
EncryptedDescriptor mapData(mapSize); EncryptedDescriptor mapData(mapSize);
if (!self.isEmpty()) { if (!self.isEmpty()) {
@ -616,6 +633,13 @@ void Account::writeMap() {
mapData.stream << quint32(lskSearchSuggestions); mapData.stream << quint32(lskSearchSuggestions);
mapData.stream << quint64(_searchSuggestionsKey); mapData.stream << quint64(_searchSuggestionsKey);
} }
if (!_webviewStorageIdBots.token.isEmpty()
|| !_webviewStorageIdOther.token.isEmpty()) {
mapData.stream << quint32(lskWebviewTokens);
mapData.stream
<< _webviewStorageIdBots.token
<< _webviewStorageIdOther.token;
}
map.writeEncrypted(mapData, _localKey); map.writeEncrypted(mapData, _localKey);
_mapChanged = false; _mapChanged = false;
@ -655,11 +679,27 @@ void Account::reset() {
_cacheTotalTimeLimit = Database::Settings().totalTimeLimit; _cacheTotalTimeLimit = Database::Settings().totalTimeLimit;
_cacheBigFileTotalSizeLimit = Database::Settings().totalSizeLimit; _cacheBigFileTotalSizeLimit = Database::Settings().totalSizeLimit;
_cacheBigFileTotalTimeLimit = Database::Settings().totalTimeLimit; _cacheBigFileTotalTimeLimit = Database::Settings().totalTimeLimit;
const auto wvbots = _webviewStorageIdBots.path;
const auto wvother = _webviewStorageIdOther.path;
const auto wvclear = [](Webview::StorageId &storageId) {
Webview::ClearStorageDataByToken(
base::take(storageId).token.toStdString());
};
wvclear(_webviewStorageIdBots);
wvclear(_webviewStorageIdOther);
_mapChanged = true; _mapChanged = true;
writeMap(); writeMap();
writeMtpData(); writeMtpData();
crl::async([base = _basePath, temp = _tempPath, names = std::move(names)] { crl::async([
base = _basePath,
temp = _tempPath,
names = std::move(names),
wvbots,
wvother
] {
for (const auto &name : names) { for (const auto &name : names) {
if (!name.endsWith(u"map0"_q) if (!name.endsWith(u"map0"_q)
&& !name.endsWith(u"map1"_q) && !name.endsWith(u"map1"_q)
@ -669,6 +709,12 @@ void Account::reset() {
} }
} }
QDir(LegacyTempDirectory()).removeRecursively(); QDir(LegacyTempDirectory()).removeRecursively();
if (!wvbots.isEmpty()) {
QDir(wvbots).removeRecursively();
}
if (!wvother.isEmpty()) {
QDir(wvother).removeRecursively();
}
QDir(temp).removeRecursively(); QDir(temp).removeRecursively();
}); });
@ -3080,6 +3126,54 @@ bool Account::isBotTrustedOpenWebView(PeerId botId) {
&& ((i->second & BotTrustFlag::OpenWebView) != 0); && ((i->second & BotTrustFlag::OpenWebView) != 0);
} }
void Account::enforceModernStorageIdBots() {
if (_webviewStorageIdBots.token.isEmpty()) {
_webviewStorageIdBots.token = QByteArray::fromStdString(
Webview::GenerateStorageToken());
writeMapDelayed();
}
}
Webview::StorageId Account::resolveStorageIdBots() {
if (!_webviewStorageIdBots) {
auto &token = _webviewStorageIdBots.token;
const auto legacy = Webview::LegacyStorageIdToken();
if (token.isEmpty()) {
auto legacyTaken = false;
const auto &list = _owner->domain().accounts();
for (const auto &[index, account] : list) {
if (account.get() != _owner.get()) {
const auto &id = account->local()._webviewStorageIdBots;
if (id.token == legacy) {
legacyTaken = true;
break;
}
}
}
token = legacyTaken
? QByteArray::fromStdString(Webview::GenerateStorageToken())
: legacy;
writeMapDelayed();
}
_webviewStorageIdBots.path = (token == legacy)
? (BaseGlobalPath() + u"webview"_q)
: (_databasePath + u"wvbots"_q);
}
return _webviewStorageIdBots;
}
Webview::StorageId Account::resolveStorageIdOther() {
if (!_webviewStorageIdOther) {
if (_webviewStorageIdOther.token.isEmpty()) {
_webviewStorageIdOther.token = QByteArray::fromStdString(
Webview::GenerateStorageToken());
writeMapDelayed();
}
_webviewStorageIdOther.path = _databasePath + u"wvother"_q;
}
return _webviewStorageIdOther;
}
bool Account::encrypt( bool Account::encrypt(
const void *src, const void *src,
void *dst, void *dst,

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/cache/storage_cache_database.h" #include "storage/cache/storage_cache_database.h"
#include "data/stickers/data_stickers_set.h" #include "data/stickers/data_stickers_set.h"
#include "data/data_drafts.h" #include "data/data_drafts.h"
#include "webview/webview_common.h"
class History; class History;
@ -169,6 +170,10 @@ public:
void markBotTrustedOpenWebView(PeerId botId); void markBotTrustedOpenWebView(PeerId botId);
[[nodiscard]] bool isBotTrustedOpenWebView(PeerId botId); [[nodiscard]] bool isBotTrustedOpenWebView(PeerId botId);
void enforceModernStorageIdBots();
[[nodiscard]] Webview::StorageId resolveStorageIdBots();
[[nodiscard]] Webview::StorageId resolveStorageIdOther();
[[nodiscard]] bool encrypt( [[nodiscard]] bool encrypt(
const void *src, const void *src,
void *dst, void *dst,
@ -309,6 +314,9 @@ private:
bool _recentHashtagsAndBotsWereRead = false; bool _recentHashtagsAndBotsWereRead = false;
bool _searchSuggestionsRead = false; bool _searchSuggestionsRead = false;
Webview::StorageId _webviewStorageIdBots;
Webview::StorageId _webviewStorageIdOther;
int _oldMapVersion = 0; int _oldMapVersion = 0;
base::Timer _writeMapTimer; base::Timer _writeMapTimer;

View File

@ -268,10 +268,6 @@ void Domain::clearOldVersion() {
_oldVersion = 0; _oldVersion = 0;
} }
QString Domain::webviewDataPath() const {
return BaseGlobalPath() + "webview";
}
rpl::producer<> Domain::localPasscodeChanged() const { rpl::producer<> Domain::localPasscodeChanged() const {
return _passcodeKeyChanged.events(); return _passcodeKeyChanged.events();
} }

View File

@ -44,8 +44,6 @@ public:
[[nodiscard]] int oldVersion() const; [[nodiscard]] int oldVersion() const;
void clearOldVersion(); void clearOldVersion();
[[nodiscard]] QString webviewDataPath() const;
[[nodiscard]] rpl::producer<> localPasscodeChanged() const; [[nodiscard]] rpl::producer<> localPasscodeChanged() const;
[[nodiscard]] bool hasLocalPasscode() const; [[nodiscard]] bool hasLocalPasscode() const;

View File

@ -313,12 +313,12 @@ Panel::Progress::Progress(QWidget *parent, Fn<QRect()> rect)
} }
Panel::Panel( Panel::Panel(
const QString &userDataPath, const Webview::StorageId &storageId,
rpl::producer<QString> title, rpl::producer<QString> title,
not_null<Delegate*> delegate, not_null<Delegate*> delegate,
MenuButtons menuButtons, MenuButtons menuButtons,
bool allowClipboardRead) bool allowClipboardRead)
: _userDataPath(userDataPath) : _storageId(storageId)
, _delegate(delegate) , _delegate(delegate)
, _menuButtons(menuButtons) , _menuButtons(menuButtons)
, _widget(std::make_unique<SeparatePanel>()) , _widget(std::make_unique<SeparatePanel>())
@ -597,7 +597,7 @@ bool Panel::createWebview(const Webview::ThemeParams &params) {
container, container,
Webview::WindowConfig{ Webview::WindowConfig{
.opaqueBg = params.opaqueBg, .opaqueBg = params.opaqueBg,
.userDataPath = _userDataPath, .storageId = _storageId,
}); });
const auto raw = &_webview->window; const auto raw = &_webview->window;
@ -1339,7 +1339,7 @@ rpl::lifetime &Panel::lifetime() {
std::unique_ptr<Panel> Show(Args &&args) { std::unique_ptr<Panel> Show(Args &&args) {
auto result = std::make_unique<Panel>( auto result = std::make_unique<Panel>(
args.userDataPath, args.storageId,
std::move(args.title), std::move(args.title),
args.delegate, args.delegate,
args.menuButtons, args.menuButtons,

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/object_ptr.h" #include "base/object_ptr.h"
#include "base/weak_ptr.h" #include "base/weak_ptr.h"
#include "base/flags.h" #include "base/flags.h"
#include "webview/webview_common.h"
class QJsonObject; class QJsonObject;
class QJsonValue; class QJsonValue;
@ -23,7 +24,6 @@ class SeparatePanel;
namespace Webview { namespace Webview {
struct Available; struct Available;
struct ThemeParams;
} // namespace Webview } // namespace Webview
namespace Ui::BotWebView { namespace Ui::BotWebView {
@ -72,7 +72,7 @@ public:
class Panel final : public base::has_weak_ptr { class Panel final : public base::has_weak_ptr {
public: public:
Panel( Panel(
const QString &userDataPath, const Webview::StorageId &storageId,
rpl::producer<QString> title, rpl::producer<QString> title,
not_null<Delegate*> delegate, not_null<Delegate*> delegate,
MenuButtons menuButtons, MenuButtons menuButtons,
@ -144,7 +144,7 @@ private:
[[nodiscard]] QRect progressRect() const; [[nodiscard]] QRect progressRect() const;
void setupProgressGeometry(); void setupProgressGeometry();
QString _userDataPath; Webview::StorageId _storageId;
const not_null<Delegate*> _delegate; const not_null<Delegate*> _delegate;
bool _closeNeedConfirmation = false; bool _closeNeedConfirmation = false;
bool _hasSettingsButton = false; bool _hasSettingsButton = false;
@ -172,7 +172,7 @@ private:
struct Args { struct Args {
QString url; QString url;
QString userDataPath; Webview::StorageId storageId;
rpl::producer<QString> title; rpl::producer<QString> title;
rpl::producer<QString> bottom; rpl::producer<QString> bottom;
not_null<Delegate*> delegate; not_null<Delegate*> delegate;

View File

@ -632,7 +632,7 @@ historyPollRadio: Radio(defaultRadio) {
diameter: 18px; diameter: 18px;
thickness: 2px; thickness: 2px;
skip: 65px; // * 0.1 skip: 65px; // * 0.1
duration: 120; duration: universalDuration;
rippleAreaPadding: 8px; rippleAreaPadding: 8px;
} }
historyPollRadioOpacity: 0.7; historyPollRadioOpacity: 0.7;

View File

@ -40,7 +40,7 @@ void SendButton::setType(Type type) {
[=] { update(); }, [=] { update(); },
0., 0.,
1., 1.,
st::historyRecordVoiceDuration); st::universalDuration);
setPointerCursor(_type != Type::Slowmode); setPointerCursor(_type != Type::Slowmode);
update(); update();
} }

View File

@ -35,9 +35,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/style/style_palette_colorizer.h" #include "ui/style/style_palette_colorizer.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "webview/webview_interface.h"
#include "boxes/background_box.h" #include "boxes/background_box.h"
#include "core/application.h" #include "core/application.h"
#include "webview/webview_common.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"

@ -1 +1 @@
Subproject commit 7c346c6b042266b5adb116a2114df1d46b37c03f Subproject commit 9f9bcaaec922644406faadda4d37014c9dec2dd9