diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 00005c93..1292f8ee 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -773,6 +773,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) m_settings->registerSetting("UpdateDialogGeometry", ""); + m_settings->registerSetting("AccountsDialogGeometry", ""); + m_settings->registerSetting("AccountsDialogSplitterState", ""); + // paste.ee API key m_settings->registerSetting("PasteEEAPIKey", "multimc"); diff --git a/launcher/minecraft/auth/AccountData.cpp b/launcher/minecraft/auth/AccountData.cpp index 54086ad7..c25c4e2f 100644 --- a/launcher/minecraft/auth/AccountData.cpp +++ b/launcher/minecraft/auth/AccountData.cpp @@ -245,19 +245,15 @@ bool AccountData::resumeStateFromV3(QJsonObject data) { return false; } auto typeS = typeV.toString(); - if(typeS == "MSA") { - type = AccountType::MSA; - } else { + if(typeS != "MSA") { qWarning() << "Failed to parse account data: type is not recognized."; return false; } - if(type == AccountType::MSA) { - msaToken = tokenFromJSONV3(data, "msa"); - userToken = tokenFromJSONV3(data, "utoken"); - xboxApiToken = tokenFromJSONV3(data, "xrp-main"); - mojangservicesToken = tokenFromJSONV3(data, "xrp-mc"); - } + msaToken = tokenFromJSONV3(data, "msa"); + userToken = tokenFromJSONV3(data, "utoken"); + xboxApiToken = tokenFromJSONV3(data, "xrp-main"); + mojangservicesToken = tokenFromJSONV3(data, "xrp-mc"); yggdrasilToken = tokenFromJSONV3(data, "ygg"); minecraftProfile = profileFromJSONV3(data, "profile"); @@ -275,13 +271,11 @@ bool AccountData::resumeStateFromV3(QJsonObject data) { QJsonObject AccountData::saveState() const { QJsonObject output; - if (type == AccountType::MSA) { - output["type"] = "MSA"; - tokenToJSONV3(output, msaToken, "msa"); - tokenToJSONV3(output, userToken, "utoken"); - tokenToJSONV3(output, xboxApiToken, "xrp-main"); - tokenToJSONV3(output, mojangservicesToken, "xrp-mc"); - } + output["type"] = "MSA"; + tokenToJSONV3(output, msaToken, "msa"); + tokenToJSONV3(output, userToken, "utoken"); + tokenToJSONV3(output, xboxApiToken, "xrp-main"); + tokenToJSONV3(output, mojangservicesToken, "xrp-mc"); tokenToJSONV3(output, yggdrasilToken, "ygg"); profileToJSONV3(output, minecraftProfile, "profile"); diff --git a/launcher/minecraft/auth/AccountData.h b/launcher/minecraft/auth/AccountData.h index 6926eaad..4160b181 100644 --- a/launcher/minecraft/auth/AccountData.h +++ b/launcher/minecraft/auth/AccountData.h @@ -36,10 +36,6 @@ struct MinecraftProfile { Katabasis::Validity validity = Katabasis::Validity::None; }; -enum class AccountType { - MSA -}; - enum class AccountState { Unchecked, Offline, @@ -68,11 +64,6 @@ struct AccountData { QString lastError() const; - AccountType type = AccountType::MSA; - bool legacy = false; - bool canMigrateToMSA = false; - bool mustMigrateToMSA = false; - Katabasis::Token msaToken; Katabasis::Token userToken; Katabasis::Token xboxApiToken; diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index 2ad59996..7df64e3d 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -451,6 +451,8 @@ bool AccountList::loadList() return false; } + m_accounts.append(Entry{false, nullptr}); + QFile file(m_listFilePath); // Try to open the file and fail if we can't. @@ -505,7 +507,6 @@ bool AccountList::loadList() bool AccountList::loadV3(QJsonObject& root) { beginResetModel(); - m_accounts.append(Entry{false, nullptr}); QJsonArray accounts = root.value("accounts").toArray(); for (QJsonValue accountVal : accounts) { diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index 2a461517..826c689d 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -48,7 +48,6 @@ MinecraftAccountPtr MinecraftAccount::loadFromJsonV3(const QJsonObject& json) { MinecraftAccountPtr MinecraftAccount::createBlankMSA() { MinecraftAccountPtr account(new MinecraftAccount()); - account->data.type = AccountType::MSA; return account; } diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h index 464d1aa2..3cb96dea 100644 --- a/launcher/minecraft/auth/MinecraftAccount.h +++ b/launcher/minecraft/auth/MinecraftAccount.h @@ -116,10 +116,6 @@ public: /* queries */ bool isActive() const; - bool canMigrate() const { - return data.canMigrateToMSA; - } - bool ownsMinecraft() const { return data.minecraftEntitlement.ownsMinecraft; } @@ -129,15 +125,7 @@ public: /* queries */ } QString typeString() const { - switch(data.type) { - case AccountType::MSA: { - return "msa"; - } - break; - default: { - return "unknown"; - } - } + return "msa"; } QPixmap getFace() const; diff --git a/launcher/ui/dialogs/AccountsDialog.cpp b/launcher/ui/dialogs/AccountsDialog.cpp index b6e2e6e9..a972a54a 100644 --- a/launcher/ui/dialogs/AccountsDialog.cpp +++ b/launcher/ui/dialogs/AccountsDialog.cpp @@ -59,10 +59,19 @@ AccountsDialog::AccountsDialog(QWidget *parent, const QString& internalId) : QDi connect(ui->saveSkinButton, &QPushButton::clicked, this, &AccountsDialog::onSaveSkinClicked); connect(ui->openSkinsButton, &QPushButton::clicked, this, &AccountsDialog::onOpenSkinsFolderClicked); - connect(ui->refreshButton, &QPushButton::clicked, this, &AccountsDialog::onRefreshButtonClicked); connect(ui->signOutButton, &QPushButton::clicked, this, &AccountsDialog::onSignOutButtonClicked); - connect(ui->refreshButton_Setup, &QPushButton::clicked, this, &AccountsDialog::onRefreshButtonClicked); connect(ui->signOutButton_Setup, &QPushButton::clicked, this, &AccountsDialog::onSignOutButtonClicked); + connect(ui->signOutButton_Demo, &QPushButton::clicked, this, &AccountsDialog::onSignOutButtonClicked); + connect(ui->signOutButton_Expired, &QPushButton::clicked, this, &AccountsDialog::onSignOutButtonClicked); + + connect(ui->removeAndSignInButton, &QPushButton::clicked, this, &AccountsDialog::onRemoveAndSignInButtonClicked); + + connect(ui->getMinecraftButton, &QPushButton::clicked, this, &AccountsDialog::onGetMinecraftButtonClicked); + + connect(ui->refreshButton, &QPushButton::clicked, this, &AccountsDialog::onRefreshButtonClicked); + connect(ui->refreshButton_Setup, &QPushButton::clicked, this, &AccountsDialog::onRefreshButtonClicked); + connect(ui->refreshButton_Demo, &QPushButton::clicked, this, &AccountsDialog::onRefreshButtonClicked); + connect(ui->getFreshCodeButton, &QPushButton::clicked, this, &AccountsDialog::onGetFreshCodeButtonClicked); QItemSelectionModel *selectionModel = ui->accountListView->selectionModel(); @@ -128,6 +137,9 @@ AccountsDialog::AccountsDialog(QWidget *parent, const QString& internalId) : QDi connect(ui->createProfileButton, &QCommandLinkButton::clicked, this, &AccountsDialog::onCreateProfileButtonClicked); setNameStatus(NameStatus::NotSet, QString()); + + restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("AccountsDialogGeometry").toByteArray())); + ui->splitter->restoreState(QByteArray::fromBase64(APPLICATION->settings()->get("AccountsDialogSplitterState").toByteArray())); } AccountsDialog::~AccountsDialog() @@ -135,6 +147,14 @@ AccountsDialog::~AccountsDialog() delete ui; } +void AccountsDialog::closeEvent(QCloseEvent* event) +{ + APPLICATION->settings()->set("AccountsDialogSplitterState", ui->splitter->saveState().toBase64()); + APPLICATION->settings()->set("AccountsDialogGeometry", saveGeometry().toBase64()); + QDialog::closeEvent(event); +} + + void AccountsDialog::onRevertChangesClicked(bool) { revertEdits(); @@ -363,6 +383,32 @@ void AccountsDialog::updateStates() return; } + if(m_currentAccount->accountState() == AccountState::Expired) + { + ui->accountPageStack->setCurrentWidget(ui->expiredPage); + if(m_currentAccount->hasProfile()) + { + ui->selectedAccountLabel_Expired->setText(m_currentAccount->profileName()); + ui->selectedAccountIconLabel_Expired->setIcon(m_currentAccount->getFace()); + } + else + { + ui->selectedAccountLabel_Expired->setText(m_currentAccount->gamerTag()); + ui->selectedAccountIconLabel_Expired->setIcon(APPLICATION->getThemedIcon("noaccount")); + } + return; + } + + // Demo account (no Minecraft entitlement) + if(!m_currentAccount->ownsMinecraft()) + { + ui->accountPageStack->setCurrentWidget(ui->demoPage); + ui->setupProfilePage->setEnabled(accountIsReady); + ui->selectedAccountLabel_Demo->setText(m_currentAccount->gamerTag()); + ui->selectedAccountIconLabel_Demo->setIcon(APPLICATION->getThemedIcon("noaccount")); + return; + } + // Profile setup page if(!m_currentAccount->hasProfile()) { @@ -373,32 +419,31 @@ void AccountsDialog::updateStates() return; } - ui->fullAccountPage->setEnabled(accountIsReady); - // Full account page + ui->fullAccountPage->setEnabled(accountIsReady); if(prevAccount != m_currentAccount) { revertEdits(); - - m_capesModel->setAccount(m_currentAccount); - ui->accountPageStack->setCurrentWidget(ui->fullAccountPage); - ui->selectedAccountLabel->setText(m_currentAccount->profileName()); - ui->selectedAccountIconLabel->setIcon(m_currentAccount->getFace()); - - QByteArray playerSkinData = m_currentAccount->getSkin(); - QImage image; - QString textureID; - Skins::readSkinFromData(playerSkinData, image, textureID); - auto maybeEntry = m_skinsModel->skinEntryByTextureID(textureID); - m_playerSkinState = SkinState{ - m_currentAccount->getCurrentCape(), - m_currentAccount->getSkinModel(), - (!maybeEntry.isNull()) ? maybeEntry : Skins::SkinEntry("player", "", image, textureID, playerSkinData) - }; - - updateModelToMatchSkin(); - updateSkinDisplay(); } + + m_capesModel->setAccount(m_currentAccount); + ui->accountPageStack->setCurrentWidget(ui->fullAccountPage); + ui->selectedAccountLabel->setText(m_currentAccount->profileName()); + ui->selectedAccountIconLabel->setIcon(m_currentAccount->getFace()); + + QByteArray playerSkinData = m_currentAccount->getSkin(); + QImage image; + QString textureID; + Skins::readSkinFromData(playerSkinData, image, textureID); + auto maybeEntry = m_skinsModel->skinEntryByTextureID(textureID); + m_playerSkinState = SkinState{ + m_currentAccount->getCurrentCape(), + m_currentAccount->getSkinModel(), + (!maybeEntry.isNull()) ? maybeEntry : Skins::SkinEntry("player", "", image, textureID, playerSkinData) + }; + + updateModelToMatchSkin(); + updateSkinDisplay(); } void AccountsDialog::updateModelToMatchSkin() @@ -639,6 +684,21 @@ void AccountsDialog::onSignOutButtonClicked(bool) } } +void AccountsDialog::onRemoveAndSignInButtonClicked(bool) +{ + if(m_currentAccount) + { + m_accounts->removeAccount(m_currentAccount->internalId()); + } + ui->accountListView->setCurrentIndex(m_accounts->index(0)); +} + +void AccountsDialog::onGetMinecraftButtonClicked(bool) +{ + DesktopServices::openUrl(QUrl("https://www.minecraft.net/en-us/store/minecraft-java-bedrock-edition-pc")); +} + + void AccountsDialog::setNameStatus(AccountsDialog::NameStatus status, QString errorString = QString()) { nameStatus = status; diff --git a/launcher/ui/dialogs/AccountsDialog.h b/launcher/ui/dialogs/AccountsDialog.h index 551839e6..1bf4f50e 100644 --- a/launcher/ui/dialogs/AccountsDialog.h +++ b/launcher/ui/dialogs/AccountsDialog.h @@ -53,6 +53,9 @@ public: Error } nameStatus = NameStatus::NotSet; +protected: + void closeEvent(QCloseEvent *event) override; + // Skins stuff private slots: void onSkinSelectionChanged(const class QItemSelection &selected, const class QItemSelection &deselected); @@ -95,6 +98,9 @@ private slots: // Account display page void onRefreshButtonClicked(bool); void onSignOutButtonClicked(bool); + void onRemoveAndSignInButtonClicked(bool); + void onGetMinecraftButtonClicked(bool); + void onAccountChanged(MinecraftAccount * account); void onAccountActivityChanged(MinecraftAccount * account, bool active); diff --git a/launcher/ui/dialogs/AccountsDialog.ui b/launcher/ui/dialogs/AccountsDialog.ui index c02ceadd..60693180 100644 --- a/launcher/ui/dialogs/AccountsDialog.ui +++ b/launcher/ui/dialogs/AccountsDialog.ui @@ -6,8 +6,8 @@ 0 0 - 1085 - 1022 + 927 + 600 @@ -63,7 +63,7 @@ QFrame::Raised - 0 + 4 @@ -135,7 +135,7 @@ - Refresh + Refresh Account @@ -353,6 +353,12 @@ Qt::ScrollBarAlwaysOff + + QListView::Adjust + + + 5 + QListView::IconMode @@ -539,7 +545,7 @@ - Refresh + Refresh Account @@ -635,6 +641,283 @@ Choose your name carefully: + + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 32 + 32 + + + + + 32 + 32 + + + + + + + + + 15 + + + + Account Name Here + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Sign Out + + + + + + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + This account's authentication tokens have expired and it needs to be signed in into again. + + + true + + + createProfileNameEdit + + + + + + + Remove and Sign In Again + + + + + + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 32 + 32 + + + + + 32 + 32 + + + + + + + + + 15 + + + + Account Name Here + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Refresh Account + + + + + + + Sign Out + + + + + + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + This account doesn't own Minecraft yet. Without purchasing the game, you can only play the demo. + + + true + + + createProfileNameEdit + + + + + + + Get Minecraft + + + + + + + + + + + @@ -667,7 +950,6 @@ Choose your name carefully: -