/* 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-2017 John Preston, https://desktop.telegram.org */ #pragma once #include #include #include #include "base/timer.h" #include "chat_helpers/stickers.h" namespace Storage { class Downloader; class Uploader; class Facade; } // namespace Storage namespace Window { namespace Notifications { class System; } // namespace Notifications enum class Column; } // namespace Window namespace Calls { class Instance; } // namespace Calls namespace ChatHelpers { enum class SelectorTab; } // namespace ChatHelpers class ApiWrap; class AuthSessionData final { public: base::Variable &contactsLoaded() { return _contactsLoaded; } base::Variable &allChatsLoaded() { return _allChatsLoaded; } base::Observable &moreChatsLoaded() { return _moreChatsLoaded; } base::Observable &pendingHistoryResize() { return _pendingHistoryResize; } struct ItemVisibilityQuery { not_null item; not_null isVisible; }; base::Observable &queryItemVisibility() { return _queryItemVisibility; } void markItemLayoutChanged(not_null item) { _itemLayoutChanged.fire_copy(item); } rpl::producer> itemLayoutChanged() const { return _itemLayoutChanged.events(); } void requestItemRepaint(not_null item) { _itemRepaintRequest.fire_copy(item); } rpl::producer> itemRepaintRequest() const { return _itemRepaintRequest.events(); } void markItemRemoved(not_null item) { _itemRemoved.fire_copy(item); } rpl::producer> itemRemoved() const { return _itemRemoved.events(); } void markHistoryUnloaded(not_null history) { _historyUnloaded.fire_copy(history); } rpl::producer> historyUnloaded() const { return _historyUnloaded.events(); } void markHistoryCleared(not_null history) { _historyCleared.fire_copy(history); } rpl::producer> historyCleared() const { return _historyCleared.events(); } using MegagroupParticipant = std::tuple< not_null, not_null>; void removeMegagroupParticipant( not_null channel, not_null user) { _megagroupParticipantRemoved.fire({ channel, user }); } auto megagroupParticipantRemoved() const { return _megagroupParticipantRemoved.events(); } auto megagroupParticipantRemoved( not_null channel) const { return megagroupParticipantRemoved() | rpl::filter([channel](auto updateChannel, auto user) { return (updateChannel == channel); }) | rpl::map([](auto updateChannel, auto user) { return user; }); } void addNewMegagroupParticipant( not_null channel, not_null user) { _megagroupParticipantAdded.fire({ channel, user }); } auto megagroupParticipantAdded() const { return _megagroupParticipantAdded.events(); } auto megagroupParticipantAdded( not_null channel) const { return megagroupParticipantAdded() | rpl::filter([channel](auto updateChannel, auto user) { return (updateChannel == channel); }) | rpl::map([](auto updateChannel, auto user) { return user; }); } void moveFrom(AuthSessionData &&other) { _variables = std::move(other._variables); } QByteArray serialize() const; void constructFromSerialized(const QByteArray &serialized); bool lastSeenWarningSeen() const { return _variables.lastSeenWarningSeen; } void setLastSeenWarningSeen(bool lastSeenWarningSeen) { _variables.lastSeenWarningSeen = lastSeenWarningSeen; } ChatHelpers::SelectorTab selectorTab() const { return _variables.selectorTab; } void setSelectorTab(ChatHelpers::SelectorTab tab) { _variables.selectorTab = tab; } bool tabbedSelectorSectionEnabled() const { return _variables.tabbedSelectorSectionEnabled; } void setTabbedSelectorSectionEnabled(bool enabled); bool thirdSectionInfoEnabled() const { return _variables.thirdSectionInfoEnabled; } void setThirdSectionInfoEnabled(bool enabled); auto thirdSectionInfoEnabledValue() const { return _thirdSectionInfoEnabledValue.events_starting_with( thirdSectionInfoEnabled()); } bool tabbedReplacedWithInfo() const { return _tabbedReplacedWithInfo; } void setTabbedReplacedWithInfo(bool enabled); auto tabbedReplacedWithInfoValue() const { return _tabbedReplacedWithInfoValue.events_starting_with( tabbedReplacedWithInfo()); } void setSmallDialogsList(bool enabled) { _variables.smallDialogsList = enabled; } bool smallDialogsList() const { return _variables.smallDialogsList; } void setLastTimeVideoPlayedAt(TimeMs time) { _lastTimeVideoPlayedAt = time; } TimeMs lastTimeVideoPlayedAt() const { return _lastTimeVideoPlayedAt; } void setSoundOverride(const QString &key, const QString &path) { _variables.soundOverrides.insert(key, path); } void clearSoundOverrides() { _variables.soundOverrides.clear(); } QString getSoundPath(const QString &key) const; void setTabbedSelectorSectionTooltipShown(int shown) { _variables.tabbedSelectorSectionTooltipShown = shown; } int tabbedSelectorSectionTooltipShown() const { return _variables.tabbedSelectorSectionTooltipShown; } void setFloatPlayerColumn(Window::Column column) { _variables.floatPlayerColumn = column; } Window::Column floatPlayerColumn() const { return _variables.floatPlayerColumn; } void setFloatPlayerCorner(RectPart corner) { _variables.floatPlayerCorner = corner; } RectPart floatPlayerCorner() const { return _variables.floatPlayerCorner; } void setDialogsWidthRatio(float64 ratio) { _variables.dialogsWidthRatio = ratio; } float64 dialogsWidthRatio() const { return _variables.dialogsWidthRatio.current(); } rpl::producer dialogsWidthRatioChanges() const { return _variables.dialogsWidthRatio.changes(); } void markStickersUpdated() { _stickersUpdated.fire({}); } rpl::producer<> stickersUpdated() const { return _stickersUpdated.events(); } void markSavedGifsUpdated() { _savedGifsUpdated.fire({}); } rpl::producer<> savedGifsUpdated() const { return _savedGifsUpdated.events(); } void setGroupStickersSectionHidden(PeerId peerId) { _variables.groupStickersSectionHidden.insert(peerId); } bool isGroupStickersSectionHidden(PeerId peerId) const { return _variables.groupStickersSectionHidden.contains(peerId); } void removeGroupStickersSectionHidden(PeerId peerId) { _variables.groupStickersSectionHidden.remove(peerId); } bool stickersUpdateNeeded(TimeMs now) const { return stickersUpdateNeeded(_lastStickersUpdate, now); } void setLastStickersUpdate(TimeMs update) { _lastStickersUpdate = update; } bool recentStickersUpdateNeeded(TimeMs now) const { return stickersUpdateNeeded(_lastRecentStickersUpdate, now); } void setLastRecentStickersUpdate(TimeMs update) { _lastRecentStickersUpdate = update; } bool favedStickersUpdateNeeded(TimeMs now) const { return stickersUpdateNeeded(_lastFavedStickersUpdate, now); } void setLastFavedStickersUpdate(TimeMs update) { _lastFavedStickersUpdate = update; } bool featuredStickersUpdateNeeded(TimeMs now) const { return stickersUpdateNeeded(_lastFeaturedStickersUpdate, now); } void setLastFeaturedStickersUpdate(TimeMs update) { _lastFeaturedStickersUpdate = update; } bool savedGifsUpdateNeeded(TimeMs now) const { return stickersUpdateNeeded(_lastSavedGifsUpdate, now); } void setLastSavedGifsUpdate(TimeMs update) { _lastSavedGifsUpdate = update; } int featuredStickerSetsUnreadCount() const { return _featuredStickerSetsUnreadCount.current(); } void setFeaturedStickerSetsUnreadCount(int count) { _featuredStickerSetsUnreadCount = count; } rpl::producer featuredStickerSetsUnreadCountValue() const { return _featuredStickerSetsUnreadCount.value(); } const Stickers::Sets &stickerSets() const { return _stickerSets; } Stickers::Sets &stickerSetsRef() { return _stickerSets; } const Stickers::Order &stickerSetsOrder() const { return _stickerSetsOrder; } Stickers::Order &stickerSetsOrderRef() { return _stickerSetsOrder; } const Stickers::Order &featuredStickerSetsOrder() const { return _featuredStickerSetsOrder; } Stickers::Order &featuredStickerSetsOrderRef() { return _featuredStickerSetsOrder; } const Stickers::Order &archivedStickerSetsOrder() const { return _archivedStickerSetsOrder; } Stickers::Order &archivedStickerSetsOrderRef() { return _archivedStickerSetsOrder; } const Stickers::SavedGifs &savedGifs() const { return _savedGifs; } Stickers::SavedGifs &savedGifsRef() { return _savedGifs; } private: struct Variables { Variables(); static constexpr auto kDefaultDialogsWidthRatio = 5. / 14; bool lastSeenWarningSeen = false; ChatHelpers::SelectorTab selectorTab; // per-window bool tabbedSelectorSectionEnabled = false; // per-window int tabbedSelectorSectionTooltipShown = 0; QMap soundOverrides; Window::Column floatPlayerColumn; // per-window RectPart floatPlayerCorner; // per-window base::flat_set groupStickersSectionHidden; bool thirdSectionInfoEnabled = true; // per-window bool smallDialogsList = false; // per-window rpl::variable dialogsWidthRatio = kDefaultDialogsWidthRatio; // per-window }; bool stickersUpdateNeeded(TimeMs lastUpdate, TimeMs now) const { constexpr auto kStickersUpdateTimeout = TimeMs(3600'000); return (lastUpdate == 0) || (now >= lastUpdate + kStickersUpdateTimeout); } base::Variable _contactsLoaded = { false }; base::Variable _allChatsLoaded = { false }; base::Observable _moreChatsLoaded; base::Observable _pendingHistoryResize; base::Observable _queryItemVisibility; rpl::event_stream> _itemLayoutChanged; rpl::event_stream> _itemRepaintRequest; rpl::event_stream> _itemRemoved; rpl::event_stream> _historyUnloaded; rpl::event_stream> _historyCleared; rpl::event_stream _megagroupParticipantRemoved; rpl::event_stream _megagroupParticipantAdded; rpl::event_stream<> _stickersUpdated; rpl::event_stream<> _savedGifsUpdated; TimeMs _lastStickersUpdate = 0; TimeMs _lastRecentStickersUpdate = 0; TimeMs _lastFavedStickersUpdate = 0; TimeMs _lastFeaturedStickersUpdate = 0; TimeMs _lastSavedGifsUpdate = 0; rpl::variable _featuredStickerSetsUnreadCount = 0; Stickers::Sets _stickerSets; Stickers::Order _stickerSetsOrder; Stickers::Order _featuredStickerSetsOrder; Stickers::Order _archivedStickerSetsOrder; Stickers::SavedGifs _savedGifs; rpl::event_stream _thirdSectionInfoEnabledValue; bool _tabbedReplacedWithInfo = false; rpl::event_stream _tabbedReplacedWithInfoValue; Variables _variables; TimeMs _lastTimeVideoPlayedAt = 0; }; // One per Messenger. class AuthSession; AuthSession &Auth(); class AuthSession final : private base::Subscriber { public: AuthSession(UserId userId); AuthSession(const AuthSession &other) = delete; AuthSession &operator=(const AuthSession &other) = delete; static bool Exists(); UserId userId() const { return _userId; } PeerId userPeerId() const { return peerFromUser(userId()); } UserData *user() const; bool validateSelf(const MTPUser &user); Storage::Downloader &downloader() { return *_downloader; } Storage::Uploader &uploader() { return *_uploader; } Storage::Facade &storage() { return *_storage; } base::Observable &downloaderTaskFinished(); Window::Notifications::System ¬ifications() { return *_notifications; } AuthSessionData &data() { return _data; } void saveDataDelayed(TimeMs delay = kDefaultSaveDelay); ApiWrap &api() { return *_api; } Calls::Instance &calls() { return *_calls; } void checkAutoLock(); void checkAutoLockIn(TimeMs time); base::Observable documentUpdated; base::Observable, MsgId>> messageIdChanging; ~AuthSession(); private: static constexpr auto kDefaultSaveDelay = TimeMs(1000); const UserId _userId = 0; AuthSessionData _data; base::Timer _saveDataTimer; TimeMs _shouldLockAt = 0; base::Timer _autoLockTimer; const std::unique_ptr _api; const std::unique_ptr _calls; const std::unique_ptr _downloader; const std::unique_ptr _uploader; const std::unique_ptr _storage; const std::unique_ptr _notifications; };