mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Support logout of a secondary account.
This commit is contained in:
parent
5e045ec02c
commit
bc144377c0
18 changed files with 189 additions and 81 deletions
|
@ -1722,7 +1722,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
|||
Api::EntitiesFromMTP(&session(), d.ventities().v)
|
||||
};
|
||||
if (IsForceLogoutNotification(d)) {
|
||||
Core::App().forceLogOut(text);
|
||||
Core::App().forceLogOut(&session().account(), text);
|
||||
} else if (d.is_popup()) {
|
||||
const auto &windows = session().windows();
|
||||
if (!windows.empty()) {
|
||||
|
|
|
@ -451,15 +451,33 @@ void Application::startLocalStorage() {
|
|||
_saveSettingsTimer.setCallback([=] { Local::writeSettings(); });
|
||||
}
|
||||
|
||||
void Application::forceLogOut(const TextWithEntities &explanation) {
|
||||
void Application::logout(Main::Account *account) {
|
||||
if (account) {
|
||||
account->logOut();
|
||||
} else {
|
||||
accounts().resetWithForgottenPasscode();
|
||||
|
||||
if (Global::LocalPasscode()) {
|
||||
Global::SetLocalPasscode(false);
|
||||
Global::RefLocalPasscodeChanged().notify();
|
||||
}
|
||||
Core::App().unlockPasscode();
|
||||
Core::App().unlockTerms();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::forceLogOut(
|
||||
not_null<Main::Account*> account,
|
||||
const TextWithEntities &explanation) {
|
||||
const auto box = Ui::show(Box<InformBox>(
|
||||
explanation,
|
||||
tr::lng_passcode_logout(tr::now)));
|
||||
box->setCloseByEscape(false);
|
||||
box->setCloseByOutsideClick(false);
|
||||
const auto weak = base::make_weak(account.get());
|
||||
connect(box, &QObject::destroyed, [=] {
|
||||
crl::on_main(this, [=] {
|
||||
activeAccount().forcedLogOut();
|
||||
crl::on_main(weak, [=] {
|
||||
account->forcedLogOut();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -189,7 +189,10 @@ public:
|
|||
bool openLocalUrl(const QString &url, QVariant context);
|
||||
bool openInternalUrl(const QString &url, QVariant context);
|
||||
|
||||
void forceLogOut(const TextWithEntities &explanation);
|
||||
void logout(Main::Account *account = nullptr);
|
||||
void forceLogOut(
|
||||
not_null<Main::Account*> account,
|
||||
const TextWithEntities &explanation);
|
||||
void checkLocalTime();
|
||||
void lockByPasscode();
|
||||
void unlockPasscode();
|
||||
|
|
|
@ -1118,8 +1118,7 @@ void Session::setupUserIsContactViewer() {
|
|||
Session::~Session() {
|
||||
// Optimization: clear notifications before destroying items.
|
||||
_session->notifications().clearAllFast();
|
||||
|
||||
clear();
|
||||
clearLocalStorage();
|
||||
}
|
||||
|
||||
template <typename Method>
|
||||
|
@ -3840,6 +3839,8 @@ void Session::clearLocalStorage() {
|
|||
|
||||
_cache->close();
|
||||
_cache->clear();
|
||||
_bigFileCache->close();
|
||||
_bigFileCache->clear();
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -170,7 +170,6 @@ void Account::destroySession() {
|
|||
if (!sessionExists()) {
|
||||
return;
|
||||
}
|
||||
session().data().clear();
|
||||
|
||||
_sessionValue = nullptr;
|
||||
_session = nullptr;
|
||||
|
@ -442,6 +441,10 @@ void Account::logOut() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Account::loggingOut() const {
|
||||
return _loggingOut;
|
||||
}
|
||||
|
||||
void Account::forcedLogOut() {
|
||||
if (sessionExists()) {
|
||||
resetAuthorizationKeys();
|
||||
|
@ -451,20 +454,10 @@ void Account::forcedLogOut() {
|
|||
|
||||
void Account::loggedOut() {
|
||||
_loggingOut = false;
|
||||
if (Global::LocalPasscode()) {
|
||||
Global::SetLocalPasscode(false);
|
||||
Global::RefLocalPasscodeChanged().notify();
|
||||
}
|
||||
Core::App().unlockPasscode();
|
||||
Core::App().unlockTerms();
|
||||
Media::Player::mixer()->stopAndClear();
|
||||
Global::SetVoiceMsgPlaybackDoubled(false);
|
||||
if (const auto window = Core::App().activeWindow()) {
|
||||
window->tempDirDelete(Local::ClearManagerAll);
|
||||
window->setupIntro();
|
||||
}
|
||||
if (sessionExists()) {
|
||||
session().data().clearLocalStorage();
|
||||
}
|
||||
destroySession();
|
||||
local().reset();
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
|
||||
void logOut();
|
||||
void forcedLogOut();
|
||||
[[nodiscard]] bool loggingOut() const;
|
||||
|
||||
[[nodiscard]] AppConfig &appConfig() const {
|
||||
Expects(_appConfig != nullptr);
|
||||
|
@ -95,6 +96,10 @@ public:
|
|||
[[nodiscard]] rpl::producer<> configUpdates() const;
|
||||
void clearMtp();
|
||||
|
||||
rpl::lifetime &lifetime() {
|
||||
return _lifetime;
|
||||
}
|
||||
|
||||
private:
|
||||
void createSession(
|
||||
const MTPUser &user,
|
||||
|
|
|
@ -30,34 +30,51 @@ bool Accounts::started() const {
|
|||
Storage::StartResult Accounts::start(const QByteArray &passcode) {
|
||||
Expects(!started());
|
||||
|
||||
auto active = -1;
|
||||
const auto callback = [&](int index, std::unique_ptr<Account> account) {
|
||||
Expects(account != nullptr);
|
||||
Expects(!_accounts.contains(index));
|
||||
|
||||
if (_accounts.empty()) {
|
||||
active = index;
|
||||
}
|
||||
_accounts.emplace(index, std::move(account));
|
||||
};
|
||||
const auto result = _local->start(passcode, callback);
|
||||
const auto result = _local->start(passcode);
|
||||
if (result == Storage::StartResult::Success) {
|
||||
Assert(started());
|
||||
|
||||
for (const auto &[index, account] : _accounts) {
|
||||
account->startMtp();
|
||||
}
|
||||
if (Local::oldSettingsVersion() < AppVersion) {
|
||||
Local::writeSettings();
|
||||
}
|
||||
|
||||
activate(active);
|
||||
activateAfterStarting();
|
||||
} else {
|
||||
Assert(!started());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Accounts::accountAddedInStorage(
|
||||
int index,
|
||||
std::unique_ptr<Account> account) {
|
||||
Expects(account != nullptr);
|
||||
Expects(!_accounts.contains(index));
|
||||
|
||||
if (_accounts.empty()) {
|
||||
_activeIndex = index;
|
||||
}
|
||||
_accounts.emplace(index, std::move(account));
|
||||
};
|
||||
|
||||
void Accounts::resetWithForgottenPasscode() {
|
||||
if (_accounts.empty()) {
|
||||
_local->startFromScratch();
|
||||
activateAfterStarting();
|
||||
} else {
|
||||
for (const auto &[index, account] : _accounts) {
|
||||
account->logOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Accounts::activateAfterStarting() {
|
||||
Expects(started());
|
||||
|
||||
for (const auto &[index, account] : _accounts) {
|
||||
watchSession(account.get());
|
||||
}
|
||||
|
||||
activate(_activeIndex);
|
||||
}
|
||||
|
||||
const base::flat_map<int, std::unique_ptr<Account>> &Accounts::list() const {
|
||||
return _accounts;
|
||||
}
|
||||
|
@ -97,8 +114,6 @@ rpl::producer<Session*> Accounts::activeSessionValue() const {
|
|||
}
|
||||
|
||||
int Accounts::add() {
|
||||
Expects(!Core::App().locked());
|
||||
|
||||
auto index = 0;
|
||||
while (_accounts.contains(index)) {
|
||||
++index;
|
||||
|
@ -108,10 +123,57 @@ int Accounts::add() {
|
|||
std::make_unique<Account>(_dataName, index)
|
||||
).first->second.get();
|
||||
_local->startAdded(account);
|
||||
account->startMtp();
|
||||
watchSession(account);
|
||||
return index;
|
||||
}
|
||||
|
||||
void Accounts::watchSession(not_null<Account*> account) {
|
||||
account->startMtp();
|
||||
account->sessionChanges(
|
||||
) | rpl::filter([=](Session *session) {
|
||||
return !session && _accounts.size() > 1;
|
||||
}) | rpl::start_with_next([=](Session *session) {
|
||||
if (account == _active.current()) {
|
||||
activateAuthedAccount();
|
||||
}
|
||||
crl::on_main(&Core::App(), [=] {
|
||||
removeRedundantAccounts();
|
||||
});
|
||||
}, account->lifetime());
|
||||
}
|
||||
|
||||
void Accounts::activateAuthedAccount() {
|
||||
Expects(started());
|
||||
|
||||
if (_active.current()->sessionExists()) {
|
||||
return;
|
||||
}
|
||||
for (auto i = _accounts.begin(); i != _accounts.end(); ++i) {
|
||||
if (i->second->sessionExists()) {
|
||||
activate(i->first);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Accounts::removeRedundantAccounts() {
|
||||
Expects(started());
|
||||
|
||||
const auto was = _accounts.size();
|
||||
activateAuthedAccount();
|
||||
for (auto i = _accounts.begin(); i != _accounts.end();) {
|
||||
if (i->second.get() == _active.current()
|
||||
|| i->second->sessionExists()) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
i = _accounts.erase(i);
|
||||
}
|
||||
if (_accounts.size() != was) {
|
||||
scheduleWriteAccounts();
|
||||
}
|
||||
}
|
||||
|
||||
void Accounts::activate(int index) {
|
||||
Expects(_accounts.contains(index));
|
||||
|
||||
|
@ -121,7 +183,16 @@ void Accounts::activate(int index) {
|
|||
_active.current()->sessionValue(
|
||||
) | rpl::start_to_stream(_activeSessions, _activeLifetime);
|
||||
|
||||
scheduleWriteAccounts();
|
||||
}
|
||||
|
||||
void Accounts::scheduleWriteAccounts() {
|
||||
if (_writeAccountsScheduled) {
|
||||
return;
|
||||
}
|
||||
_writeAccountsScheduled = true;
|
||||
crl::on_main(&Core::App(), [=] {
|
||||
_writeAccountsScheduled = false;
|
||||
_local->writeAccounts();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ public:
|
|||
~Accounts();
|
||||
|
||||
[[nodiscard]] bool started() const;
|
||||
Storage::StartResult start(const QByteArray &passcode);
|
||||
[[nodiscard]] Storage::StartResult start(const QByteArray &passcode);
|
||||
void resetWithForgottenPasscode();
|
||||
|
||||
[[nodiscard]] Storage::Accounts &local() const {
|
||||
return *_local;
|
||||
|
@ -44,13 +45,23 @@ public:
|
|||
[[nodiscard]] int add();
|
||||
void activate(int index);
|
||||
|
||||
// Interface for Storage::Accounts.
|
||||
void accountAddedInStorage(int index, std::unique_ptr<Account> account);
|
||||
|
||||
private:
|
||||
void activateAfterStarting();
|
||||
void activateAuthedAccount();
|
||||
void removeRedundantAccounts();
|
||||
void watchSession(not_null<Account*> account);
|
||||
void scheduleWriteAccounts();
|
||||
|
||||
const QString _dataName;
|
||||
const std::unique_ptr<Storage::Accounts> _local;
|
||||
|
||||
base::flat_map<int, std::unique_ptr<Account>> _accounts;
|
||||
rpl::variable<Account*> _active = nullptr;
|
||||
int _activeIndex = 0;
|
||||
bool _writeAccountsScheduled = false;
|
||||
|
||||
rpl::event_stream<Session*> _activeSessions;
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ Session::Session(
|
|||
}
|
||||
|
||||
Session::~Session() {
|
||||
data().clear();
|
||||
ClickHandler::clearActive();
|
||||
ClickHandler::unpressed();
|
||||
}
|
||||
|
|
|
@ -652,22 +652,29 @@ void MainWindow::onShowNewChannel() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::onLogout() {
|
||||
void MainWindow::showLogoutConfirmation() {
|
||||
if (isHidden()) {
|
||||
showFromTray();
|
||||
}
|
||||
|
||||
const auto callback = [=] {
|
||||
if (account().sessionExists()
|
||||
&& account().session().data().exportInProgress()) {
|
||||
const auto account = Core::App().passcodeLocked()
|
||||
? nullptr
|
||||
: sessionController()
|
||||
? &sessionController()->session().account()
|
||||
: nullptr;
|
||||
const auto weak = base::make_weak(account);
|
||||
const auto callback = crl::guard(weak, [=] {
|
||||
if (account
|
||||
&& account->sessionExists()
|
||||
&& account->session().data().exportInProgress()) {
|
||||
Ui::hideLayer();
|
||||
account().session().data().stopExportWithConfirmation([=] {
|
||||
account().logOut();
|
||||
account->session().data().stopExportWithConfirmation([=] {
|
||||
Core::App().logout(account);
|
||||
});
|
||||
} else {
|
||||
account().logOut();
|
||||
Core::App().logout(account);
|
||||
}
|
||||
};
|
||||
});
|
||||
Ui::show(Box<ConfirmBox>(
|
||||
tr::lng_sure_logout(tr::now),
|
||||
tr::lng_settings_logout(tr::now),
|
||||
|
|
|
@ -113,6 +113,8 @@ public:
|
|||
not_null<PhotoData*> photo);
|
||||
void hideMediaPreview();
|
||||
|
||||
void showLogoutConfirmation();
|
||||
|
||||
void updateControlsGeometry() override;
|
||||
|
||||
protected:
|
||||
|
@ -137,7 +139,6 @@ public slots:
|
|||
void onShowAddContact();
|
||||
void onShowNewGroup();
|
||||
void onShowNewChannel();
|
||||
void onLogout();
|
||||
|
||||
signals:
|
||||
void tempDirCleared(int task);
|
||||
|
|
|
@ -756,10 +756,10 @@ void MainWindow::createGlobalMenu() {
|
|||
|
||||
auto file = psMainMenu->addMenu(tr::lng_mac_menu_file(tr::now));
|
||||
|
||||
psLogout = file->addAction(
|
||||
tr::lng_mac_menu_logout(tr::now),
|
||||
App::wnd(),
|
||||
SLOT(onLogout()));
|
||||
psLogout = file->addAction(tr::lng_mac_menu_logout(tr::now));
|
||||
connect(psLogout, &QAction::triggered, psLogout, [] {
|
||||
if (App::wnd()) App::wnd()->showLogoutConfirmation();
|
||||
});
|
||||
|
||||
auto quit = file->addAction(
|
||||
tr::lng_mac_menu_quit_telegram(tr::now, lt_telegram, qsl("Telegram")),
|
||||
|
|
|
@ -681,7 +681,10 @@ void MainWindow::createGlobalMenu() {
|
|||
prefs->setMenuRole(QAction::PreferencesRole);
|
||||
|
||||
QMenu *file = psMainMenu.addMenu(tr::lng_mac_menu_file(tr::now));
|
||||
psLogout = file->addAction(tr::lng_mac_menu_logout(tr::now), App::wnd(), SLOT(onLogout()));
|
||||
psLogout = file->addAction(tr::lng_mac_menu_logout(tr::now));
|
||||
connect(psLogout, &QAction::triggered, psLogout, [] {
|
||||
if (App::wnd()) App::wnd()->showLogoutConfirmation();
|
||||
});
|
||||
|
||||
QMenu *edit = psMainMenu.addMenu(tr::lng_mac_menu_edit(tr::now));
|
||||
psUndo = edit->addAction(tr::lng_mac_menu_undo(tr::now), this, SLOT(psMacUndo()), QKeySequence::Undo);
|
||||
|
|
|
@ -202,7 +202,7 @@ void FillMenu(
|
|||
}
|
||||
addAction(
|
||||
tr::lng_settings_logout(tr::now),
|
||||
[=] { window->widget()->onLogout(); });
|
||||
[=] { window->widget()->showLogoutConfirmation(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,10 +41,8 @@ Accounts::Accounts(not_null<Main::Accounts*> owner, const QString &dataName)
|
|||
|
||||
Accounts::~Accounts() = default;
|
||||
|
||||
StartResult Accounts::start(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback) {
|
||||
const auto modern = startModern(passcode, callback);
|
||||
StartResult Accounts::start(const QByteArray &passcode) {
|
||||
const auto modern = startModern(passcode);
|
||||
if (modern == StartModernResult::Success) {
|
||||
if (_oldVersion < AppVersion) {
|
||||
writeAccounts();
|
||||
|
@ -53,20 +51,14 @@ StartResult Accounts::start(
|
|||
} else if (modern == StartModernResult::IncorrectPasscode) {
|
||||
return StartResult::IncorrectPasscode;
|
||||
} else if (modern == StartModernResult::Failed) {
|
||||
startWithSingleAccount(
|
||||
passcode,
|
||||
std::move(callback),
|
||||
std::make_unique<Main::Account>(_dataName, 0));
|
||||
startFromScratch();
|
||||
return StartResult::Success;
|
||||
}
|
||||
auto legacy = std::make_unique<Main::Account>(_dataName, 0);
|
||||
const auto result = legacy->legacyStart(passcode);
|
||||
if (result == StartResult::Success) {
|
||||
_oldVersion = legacy->local().oldMapVersion();
|
||||
startWithSingleAccount(
|
||||
passcode,
|
||||
std::move(callback),
|
||||
std::move(legacy));
|
||||
startWithSingleAccount(passcode, std::move(legacy));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -79,7 +71,6 @@ void Accounts::startAdded(not_null<Main::Account*> account) {
|
|||
|
||||
void Accounts::startWithSingleAccount(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback,
|
||||
std::unique_ptr<Main::Account> account) {
|
||||
Expects(account != nullptr);
|
||||
|
||||
|
@ -90,7 +81,7 @@ void Accounts::startWithSingleAccount(
|
|||
generateLocalKey();
|
||||
account->start(_localKey);
|
||||
}
|
||||
callback(0, std::move(account));
|
||||
_owner->accountAddedInStorage(0, std::move(account));
|
||||
writeAccounts();
|
||||
}
|
||||
|
||||
|
@ -119,8 +110,7 @@ void Accounts::encryptLocalKey(const QByteArray &passcode) {
|
|||
}
|
||||
|
||||
Accounts::StartModernResult Accounts::startModern(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback) {
|
||||
const QByteArray &passcode) {
|
||||
const auto name = ComputeKeyName(_dataName);
|
||||
|
||||
FileReadDescriptor keyData;
|
||||
|
@ -185,7 +175,7 @@ Accounts::StartModernResult Accounts::startModern(
|
|||
const auto userId = account->willHaveUserId();
|
||||
if (!users.contains(userId)
|
||||
&& (userId != 0 || (users.empty() && i + 1 == count))) {
|
||||
callback(index, std::move(account));
|
||||
_owner->accountAddedInStorage(index, std::move(account));
|
||||
users.emplace(userId);
|
||||
}
|
||||
}
|
||||
|
@ -223,6 +213,12 @@ void Accounts::writeAccounts() {
|
|||
key.writeEncrypted(keyData, _localKey);
|
||||
}
|
||||
|
||||
void Accounts::startFromScratch() {
|
||||
startWithSingleAccount(
|
||||
QByteArray(),
|
||||
std::make_unique<Main::Account>(_dataName, 0));
|
||||
}
|
||||
|
||||
bool Accounts::checkPasscode(const QByteArray &passcode) const {
|
||||
Expects(!_passcodeKeySalt.isEmpty());
|
||||
Expects(_passcodeKey != nullptr);
|
||||
|
|
|
@ -29,11 +29,10 @@ public:
|
|||
Accounts(not_null<Main::Accounts*> owner, const QString &dataName);
|
||||
~Accounts();
|
||||
|
||||
[[nodiscard]] StartResult start(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback);
|
||||
[[nodiscard]] StartResult start(const QByteArray &passcode);
|
||||
void startAdded(not_null<Main::Account*> account);
|
||||
void writeAccounts();
|
||||
void startFromScratch();
|
||||
|
||||
[[nodiscard]] bool checkPasscode(const QByteArray &passcode) const;
|
||||
void setPasscode(const QByteArray &passcode);
|
||||
|
@ -49,12 +48,9 @@ private:
|
|||
Empty,
|
||||
};
|
||||
|
||||
[[nodiscard]] StartModernResult startModern(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback);
|
||||
[[nodiscard]] StartModernResult startModern(const QByteArray &passcode);
|
||||
void startWithSingleAccount(
|
||||
const QByteArray &passcode,
|
||||
Fn<void(int, std::unique_ptr<Main::Account>)> callback,
|
||||
std::unique_ptr<Main::Account> account);
|
||||
void generateLocalKey();
|
||||
void encryptLocalKey(const QByteArray &passcode);
|
||||
|
|
|
@ -68,7 +68,7 @@ void Controller::showAccount(not_null<Main::Account*> account) {
|
|||
} else {
|
||||
setupIntro();
|
||||
}
|
||||
}, _lifetime);
|
||||
}, _accountLifetime);
|
||||
}
|
||||
|
||||
void Controller::finishFirstShow() {
|
||||
|
|
|
@ -117,7 +117,9 @@ PasscodeLockWidget::PasscodeLockWidget(
|
|||
connect(_passcode, &Ui::MaskedInputField::submitted, [=] { submit(); });
|
||||
|
||||
_submit->setClickedCallback([=] { submit(); });
|
||||
_logout->setClickedCallback([=] { window->widget()->onLogout(); });
|
||||
_logout->setClickedCallback([=] {
|
||||
window->widget()->showLogoutConfirmation();
|
||||
});
|
||||
}
|
||||
|
||||
void PasscodeLockWidget::paintContent(Painter &p) {
|
||||
|
|
Loading…
Add table
Reference in a new issue