diff options
author | Petr Mrázek <peterix@gmail.com> | 2021-12-04 01:18:05 +0100 |
---|---|---|
committer | Petr Mrázek <peterix@gmail.com> | 2021-12-04 01:18:05 +0100 |
commit | 3c46d8a412956a759f61ae802c540ef72d00b35d (patch) | |
tree | f16564ba6be96b68ba5257a982c144320fff7911 /launcher/ui | |
parent | ffcef673de9fe848a92d23e02a2abed8df16eb9f (diff) | |
download | PrismLauncher-3c46d8a412956a759f61ae802c540ef72d00b35d.tar.gz PrismLauncher-3c46d8a412956a759f61ae802c540ef72d00b35d.tar.bz2 PrismLauncher-3c46d8a412956a759f61ae802c540ef72d00b35d.zip |
GH-4071 Heavily refactor and rearchitect account system
This makes the account system much more modular
and makes it treat errors as something recoverable,
unless they come directly from the MSA refresh token
becoming invalid.
Diffstat (limited to 'launcher/ui')
-rw-r--r-- | launcher/ui/dialogs/LoginDialog.cpp | 2 | ||||
-rw-r--r-- | launcher/ui/dialogs/MSALoginDialog.cpp | 2 | ||||
-rw-r--r-- | launcher/ui/dialogs/ProfileSetupDialog.cpp | 10 | ||||
-rw-r--r-- | launcher/ui/dialogs/SkinUploadDialog.cpp | 15 | ||||
-rw-r--r-- | launcher/ui/pages/global/AccountListPage.cpp | 16 | ||||
-rw-r--r-- | launcher/ui/widgets/ErrorFrame.cpp | 134 | ||||
-rw-r--r-- | launcher/ui/widgets/ErrorFrame.h | 49 | ||||
-rw-r--r-- | launcher/ui/widgets/ErrorFrame.ui | 92 |
8 files changed, 290 insertions, 30 deletions
diff --git a/launcher/ui/dialogs/LoginDialog.cpp b/launcher/ui/dialogs/LoginDialog.cpp index bf0806e1..194315a7 100644 --- a/launcher/ui/dialogs/LoginDialog.cpp +++ b/launcher/ui/dialogs/LoginDialog.cpp @@ -43,7 +43,7 @@ void LoginDialog::accept() // Setup the login task and start it m_account = MinecraftAccount::createFromUsername(ui->userTextBox->text()); - m_loginTask = m_account->login(nullptr, ui->passTextBox->text()); + m_loginTask = m_account->login(ui->passTextBox->text()); connect(m_loginTask.get(), &Task::failed, this, &LoginDialog::onTaskFailed); connect(m_loginTask.get(), &Task::succeeded, this, &LoginDialog::onTaskSucceeded); connect(m_loginTask.get(), &Task::status, this, &LoginDialog::onTaskStatus); diff --git a/launcher/ui/dialogs/MSALoginDialog.cpp b/launcher/ui/dialogs/MSALoginDialog.cpp index 15c04061..f46aa3b9 100644 --- a/launcher/ui/dialogs/MSALoginDialog.cpp +++ b/launcher/ui/dialogs/MSALoginDialog.cpp @@ -37,7 +37,7 @@ int MSALoginDialog::exec() { // Setup the login task and start it m_account = MinecraftAccount::createBlankMSA(); - m_loginTask = m_account->loginMSA(nullptr); + m_loginTask = m_account->loginMSA(); connect(m_loginTask.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed); connect(m_loginTask.get(), &Task::succeeded, this, &MSALoginDialog::onTaskSucceeded); connect(m_loginTask.get(), &Task::status, this, &MSALoginDialog::onTaskStatus); diff --git a/launcher/ui/dialogs/ProfileSetupDialog.cpp b/launcher/ui/dialogs/ProfileSetupDialog.cpp index d3e2b9a4..76b6af49 100644 --- a/launcher/ui/dialogs/ProfileSetupDialog.cpp +++ b/launcher/ui/dialogs/ProfileSetupDialog.cpp @@ -25,8 +25,8 @@ #include "ui/dialogs/ProgressDialog.h" #include <Application.h> -#include "minecraft/auth/flows/AuthRequest.h" -#include "minecraft/auth/flows/Parsers.h" +#include "minecraft/auth/AuthRequest.h" +#include "minecraft/auth/Parsers.h" ProfileSetupDialog::ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidget *parent) @@ -150,6 +150,9 @@ void ProfileSetupDialog::checkFinished( QByteArray data, QList<QNetworkReply::RawHeaderPair> headers ) { + auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); + requestor->deleteLater(); + if(error == QNetworkReply::NoError) { auto doc = QJsonDocument::fromJson(data); auto root = doc.object(); @@ -231,6 +234,9 @@ void ProfileSetupDialog::setupProfileFinished( QByteArray data, QList<QNetworkReply::RawHeaderPair> headers ) { + auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); + requestor->deleteLater(); + isWorking = false; if(error == QNetworkReply::NoError) { /* diff --git a/launcher/ui/dialogs/SkinUploadDialog.cpp b/launcher/ui/dialogs/SkinUploadDialog.cpp index 4e6142fa..6a5a324f 100644 --- a/launcher/ui/dialogs/SkinUploadDialog.cpp +++ b/launcher/ui/dialogs/SkinUploadDialog.cpp @@ -20,16 +20,6 @@ void SkinUploadDialog::on_buttonBox_rejected() void SkinUploadDialog::on_buttonBox_accepted() { - AuthSessionPtr session = std::make_shared<AuthSession>(); - auto login = m_acct->refresh(session); - ProgressDialog prog(this); - if (prog.execWithTask((Task*)login.get()) != QDialog::Accepted) - { - //FIXME: recover with password prompt - CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Failed to login!"), QMessageBox::Warning)->exec(); - close(); - return; - } QString fileName; QString input = ui->skinPathTextBox->text(); QRegExp urlPrefixMatcher("^([a-z]+)://.+$"); @@ -91,11 +81,12 @@ void SkinUploadDialog::on_buttonBox_accepted() { model = SkinUpload::ALEX; } + ProgressDialog prog(this); SequentialTask skinUpload; - skinUpload.addTask(shared_qobject_ptr<SkinUpload>(new SkinUpload(this, session, FS::read(fileName), model))); + skinUpload.addTask(shared_qobject_ptr<SkinUpload>(new SkinUpload(this, m_acct->accessToken(), FS::read(fileName), model))); auto selectedCape = ui->capeCombo->currentData().toString(); if(selectedCape != m_acct->accountData()->minecraftProfile.currentCape) { - skinUpload.addTask(shared_qobject_ptr<CapeChange>(new CapeChange(this, session, selectedCape))); + skinUpload.addTask(shared_qobject_ptr<CapeChange>(new CapeChange(this, m_acct->accessToken(), selectedCape))); } if (prog.execWithTask(&skinUpload) != QDialog::Accepted) { diff --git a/launcher/ui/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp index 816dce47..d3eb2655 100644 --- a/launcher/ui/pages/global/AccountListPage.cpp +++ b/launcher/ui/pages/global/AccountListPage.cpp @@ -170,13 +170,7 @@ void AccountListPage::on_actionRefresh_triggered() { if (selection.size() > 0) { QModelIndex selected = selection.first(); MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>(); - AuthSessionPtr session = std::make_shared<AuthSession>(); - auto task = account->refresh(session); - if (task) { - ProgressDialog progDialog(this); - progDialog.execWithTask(task.get()); - // TODO: respond to results of the task - } + m_accounts->requestRefresh(account->internalId()); } } @@ -244,15 +238,9 @@ void AccountListPage::on_actionDeleteSkin_triggered() return; QModelIndex selected = selection.first(); - AuthSessionPtr session = std::make_shared<AuthSession>(); MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>(); - auto login = account->refresh(session); ProgressDialog prog(this); - if (prog.execWithTask((Task*)login.get()) != QDialog::Accepted) { - CustomMessageBox::selectable(this, tr("Skin Delete"), tr("Failed to login!"), QMessageBox::Warning)->exec(); - return; - } - auto deleteSkinTask = std::make_shared<SkinDelete>(this, session); + auto deleteSkinTask = std::make_shared<SkinDelete>(this, account->accessToken()); if (prog.execWithTask((Task*)deleteSkinTask.get()) != QDialog::Accepted) { CustomMessageBox::selectable(this, tr("Skin Delete"), tr("Failed to delete current skin!"), QMessageBox::Warning)->exec(); return; diff --git a/launcher/ui/widgets/ErrorFrame.cpp b/launcher/ui/widgets/ErrorFrame.cpp new file mode 100644 index 00000000..b3e41036 --- /dev/null +++ b/launcher/ui/widgets/ErrorFrame.cpp @@ -0,0 +1,134 @@ +/* Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <QMessageBox> +#include <QtGui> + +#include "ErrorFrame.h" +#include "ui_ErrorFrame.h" + +#include "ui/dialogs/CustomMessageBox.h" + +void ErrorFrame::clear() +{ + setTitle(QString()); + setDescription(QString()); +} + +ErrorFrame::ErrorFrame(QWidget *parent) : + QFrame(parent), + ui(new Ui::ErrorFrame) +{ + ui->setupUi(this); + ui->label_Description->setHidden(true); + ui->label_Title->setHidden(true); + updateHiddenState(); +} + +ErrorFrame::~ErrorFrame() +{ + delete ui; +} + +void ErrorFrame::updateHiddenState() +{ + if(ui->label_Description->isHidden() && ui->label_Title->isHidden()) + { + setHidden(true); + } + else + { + setHidden(false); + } +} + +void ErrorFrame::setTitle(QString text) +{ + if(text.isEmpty()) + { + ui->label_Title->setHidden(true); + } + else + { + ui->label_Title->setText(text); + ui->label_Title->setHidden(false); + } + updateHiddenState(); +} + +void ErrorFrame::setDescription(QString text) +{ + if(text.isEmpty()) + { + ui->label_Description->setHidden(true); + updateHiddenState(); + return; + } + else + { + ui->label_Description->setHidden(false); + updateHiddenState(); + } + ui->label_Description->setToolTip(""); + QString intermediatetext = text.trimmed(); + bool prev(false); + QChar rem('\n'); + QString finaltext; + finaltext.reserve(intermediatetext.size()); + foreach(const QChar& c, intermediatetext) + { + if(c == rem && prev){ + continue; + } + prev = c == rem; + finaltext += c; + } + QString labeltext; + labeltext.reserve(300); + if(finaltext.length() > 290) + { + ui->label_Description->setOpenExternalLinks(false); + ui->label_Description->setTextFormat(Qt::TextFormat::RichText); + desc = text; + // This allows injecting HTML here. + labeltext.append("<html><body>" + finaltext.left(287) + "<a href=\"#mod_desc\">...</a></body></html>"); + QObject::connect(ui->label_Description, &QLabel::linkActivated, this, &ErrorFrame::ellipsisHandler); + } + else + { + ui->label_Description->setTextFormat(Qt::TextFormat::PlainText); + labeltext.append(finaltext); + } + ui->label_Description->setText(labeltext); +} + +void ErrorFrame::ellipsisHandler(const QString &link) +{ + if(!currentBox) + { + currentBox = CustomMessageBox::selectable(this, QString(), desc); + connect(currentBox, &QMessageBox::finished, this, &ErrorFrame::boxClosed); + currentBox->show(); + } + else + { + currentBox->setText(desc); + } +} + +void ErrorFrame::boxClosed(int result) +{ + currentBox = nullptr; +} diff --git a/launcher/ui/widgets/ErrorFrame.h b/launcher/ui/widgets/ErrorFrame.h new file mode 100644 index 00000000..d5069a14 --- /dev/null +++ b/launcher/ui/widgets/ErrorFrame.h @@ -0,0 +1,49 @@ +/* Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <QFrame> + +namespace Ui +{ +class ErrorFrame; +} + +class ErrorFrame : public QFrame +{ + Q_OBJECT + +public: + explicit ErrorFrame(QWidget *parent = 0); + ~ErrorFrame(); + + void setTitle(QString text); + void setDescription(QString text); + + void clear(); + +public slots: + void ellipsisHandler(const QString& link ); + void boxClosed(int result); + +private: + void updateHiddenState(); + +private: + Ui::ErrorFrame *ui; + QString desc; + class QMessageBox * currentBox = nullptr; +}; diff --git a/launcher/ui/widgets/ErrorFrame.ui b/launcher/ui/widgets/ErrorFrame.ui new file mode 100644 index 00000000..0bb56743 --- /dev/null +++ b/launcher/ui/widgets/ErrorFrame.ui @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ErrorFrame</class> + <widget class="QFrame" name="ErrorFrame"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>527</width> + <height>113</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>120</height> + </size> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label_Title"> + <property name="text"> + <string notr="true"/> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_Description"> + <property name="toolTip"> + <string notr="true"/> + </property> + <property name="text"> + <string notr="true"/> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> |