added more import options
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
parent
ab648e58ce
commit
8bad255a91
@ -44,7 +44,7 @@
|
|||||||
CapeChange::CapeChange(QString token, QString cape) : NetRequest(), m_capeId(cape), m_token(token)
|
CapeChange::CapeChange(QString token, QString cape) : NetRequest(), m_capeId(cape), m_token(token)
|
||||||
{
|
{
|
||||||
logCat = taskMCSkinsLogC;
|
logCat = taskMCSkinsLogC;
|
||||||
};
|
}
|
||||||
|
|
||||||
QNetworkReply* CapeChange::getReply(QNetworkRequest& request)
|
QNetworkReply* CapeChange::getReply(QNetworkRequest& request)
|
||||||
{
|
{
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
SkinDelete::SkinDelete(QString token) : NetRequest(), m_token(token)
|
SkinDelete::SkinDelete(QString token) : NetRequest(), m_token(token)
|
||||||
{
|
{
|
||||||
logCat = taskMCSkinsLogC;
|
logCat = taskMCSkinsLogC;
|
||||||
};
|
}
|
||||||
|
|
||||||
QNetworkReply* SkinDelete::getReply(QNetworkRequest& request)
|
QNetworkReply* SkinDelete::getReply(QNetworkRequest& request)
|
||||||
{
|
{
|
||||||
|
@ -85,8 +85,6 @@ bool SkinList::update()
|
|||||||
} catch (const Exception& e) {
|
} catch (const Exception& e) {
|
||||||
qCritical() << "Couldn't load skins json:" << e.cause();
|
qCritical() << "Couldn't load skins json:" << e.cause();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
newSkins = loadMinecraftSkins();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsSave = false;
|
bool needsSave = false;
|
||||||
@ -108,7 +106,7 @@ bool SkinList::update()
|
|||||||
auto path = m_dir.absoluteFilePath(name);
|
auto path = m_dir.absoluteFilePath(name);
|
||||||
if (skinTexture.loadFromData(skin.data, "PNG") && skinTexture.save(path)) {
|
if (skinTexture.loadFromData(skin.data, "PNG") && skinTexture.save(path)) {
|
||||||
SkinModel s(path);
|
SkinModel s(path);
|
||||||
s.setModel(SkinModel::CLASSIC); // maybe better model detection
|
s.setModel(skin.variant == "slim" ? SkinModel::SLIM : SkinModel::CLASSIC);
|
||||||
s.setCapeId(m_acct->accountData()->minecraftProfile.currentCape);
|
s.setCapeId(m_acct->accountData()->minecraftProfile.currentCape);
|
||||||
s.setURL(skin.url);
|
s.setURL(skin.url);
|
||||||
newSkins << s;
|
newSkins << s;
|
||||||
@ -116,6 +114,7 @@ bool SkinList::update()
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nskin->setCapeId(m_acct->accountData()->minecraftProfile.currentCape);
|
nskin->setCapeId(m_acct->accountData()->minecraftProfile.currentCape);
|
||||||
|
nskin->setModel(skin.variant == "slim" ? SkinModel::SLIM : SkinModel::CLASSIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,14 +206,14 @@ bool SkinList::dropMimeData(const QMimeData* data,
|
|||||||
// files dropped from outside?
|
// files dropped from outside?
|
||||||
if (data->hasUrls()) {
|
if (data->hasUrls()) {
|
||||||
auto urls = data->urls();
|
auto urls = data->urls();
|
||||||
QStringList iconFiles;
|
QStringList skinFiles;
|
||||||
for (auto url : urls) {
|
for (auto url : urls) {
|
||||||
// only local files may be dropped...
|
// only local files may be dropped...
|
||||||
if (!url.isLocalFile())
|
if (!url.isLocalFile())
|
||||||
continue;
|
continue;
|
||||||
iconFiles += url.toLocalFile();
|
skinFiles << url.toLocalFile();
|
||||||
}
|
}
|
||||||
installSkins(iconFiles);
|
installSkins(skinFiles);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -261,20 +260,26 @@ int SkinList::rowCount(const QModelIndex& parent) const
|
|||||||
void SkinList::installSkins(const QStringList& iconFiles)
|
void SkinList::installSkins(const QStringList& iconFiles)
|
||||||
{
|
{
|
||||||
for (QString file : iconFiles)
|
for (QString file : iconFiles)
|
||||||
installSkin(file, {});
|
installSkin(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkinList::installSkin(const QString& file, const QString& name)
|
QString SkinList::installSkin(const QString& file, const QString& name)
|
||||||
{
|
{
|
||||||
|
if (file.isEmpty())
|
||||||
|
return tr("Path is empty.");
|
||||||
QFileInfo fileinfo(file);
|
QFileInfo fileinfo(file);
|
||||||
if (!fileinfo.isReadable() || !fileinfo.isFile())
|
if (!fileinfo.exists())
|
||||||
return;
|
return tr("File doesn't exist.");
|
||||||
|
if (!fileinfo.isFile())
|
||||||
|
return tr("Not a file.");
|
||||||
|
if (!fileinfo.isReadable())
|
||||||
|
return tr("File is not readable.");
|
||||||
if (fileinfo.suffix() != "png" && !SkinModel(fileinfo.absoluteFilePath()).isValid())
|
if (fileinfo.suffix() != "png" && !SkinModel(fileinfo.absoluteFilePath()).isValid())
|
||||||
return;
|
return tr("Skin images must be 64x64 or 64x32 pixel PNG files.");
|
||||||
|
|
||||||
QString target = FS::PathCombine(m_dir.absolutePath(), name.isEmpty() ? fileinfo.fileName() : name);
|
QString target = FS::PathCombine(m_dir.absolutePath(), name.isEmpty() ? fileinfo.fileName() : name);
|
||||||
QFile::copy(file, target);
|
|
||||||
|
return QFile::copy(file, target) ? "" : tr("Unable to copy file");
|
||||||
}
|
}
|
||||||
|
|
||||||
int SkinList::getSkinIndex(const QString& key) const
|
int SkinList::getSkinIndex(const QString& key) const
|
||||||
@ -311,10 +316,12 @@ bool SkinList::deleteSkin(const QString& key, const bool trash)
|
|||||||
if (trash) {
|
if (trash) {
|
||||||
if (FS::trash(s.getPath(), nullptr)) {
|
if (FS::trash(s.getPath(), nullptr)) {
|
||||||
m_skin_list.remove(idx);
|
m_skin_list.remove(idx);
|
||||||
|
save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (QFile::remove(s.getPath())) {
|
} else if (QFile::remove(s.getPath())) {
|
||||||
m_skin_list.remove(idx);
|
m_skin_list.remove(idx);
|
||||||
|
save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -361,33 +368,22 @@ bool SkinList::setData(const QModelIndex& idx, const QVariant& value, int role)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<SkinModel> SkinList::loadMinecraftSkins()
|
void SkinList::updateSkin(SkinModel s)
|
||||||
{
|
{
|
||||||
QString partialPath;
|
auto done = false;
|
||||||
#if defined(Q_OS_OSX)
|
for (auto i = 0; i < m_skin_list.size(); i++) {
|
||||||
partialPath = FS::PathCombine(QDir::homePath(), "Library/Application Support");
|
if (m_skin_list[i].getPath() == s.getPath()) {
|
||||||
#elif defined(Q_OS_WIN32)
|
m_skin_list[i].setCapeId(s.getCapeId());
|
||||||
partialPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", "");
|
m_skin_list[i].setModel(s.getModel());
|
||||||
#else
|
m_skin_list[i].setURL(s.getURL());
|
||||||
partialPath = QDir::homePath();
|
done = true;
|
||||||
#endif
|
break;
|
||||||
QVector<SkinModel> newSkins;
|
|
||||||
auto path = FS::PathCombine(partialPath, ".minecraft", "launcher_custom_skins.json");
|
|
||||||
auto manifestInfo = QFileInfo(path);
|
|
||||||
if (!manifestInfo.exists())
|
|
||||||
return {};
|
|
||||||
try {
|
|
||||||
auto doc = Json::requireDocument(manifestInfo.absoluteFilePath(), "SkinList JSON file");
|
|
||||||
const auto root = doc.object();
|
|
||||||
auto skins = Json::ensureObject(root, "customSkins");
|
|
||||||
for (auto key : skins.keys()) {
|
|
||||||
SkinModel s(m_dir, Json::ensureObject(skins, key));
|
|
||||||
if (s.isValid()) {
|
|
||||||
newSkins << s;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (const Exception& e) {
|
|
||||||
qCritical() << "Couldn't load minecraft skins json:" << e.cause();
|
|
||||||
}
|
}
|
||||||
return newSkins;
|
if (!done) {
|
||||||
|
beginInsertRows(QModelIndex(), m_skin_list.count(), m_skin_list.count() + 1);
|
||||||
|
m_skin_list.append(s);
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
save();
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ class SkinList : public QAbstractListModel {
|
|||||||
bool deleteSkin(const QString& key, const bool trash);
|
bool deleteSkin(const QString& key, const bool trash);
|
||||||
|
|
||||||
void installSkins(const QStringList& iconFiles);
|
void installSkins(const QStringList& iconFiles);
|
||||||
void installSkin(const QString& file, const QString& name);
|
QString installSkin(const QString& file, const QString& name = {});
|
||||||
|
|
||||||
const SkinModel* skin(const QString& key) const;
|
const SkinModel* skin(const QString& key) const;
|
||||||
SkinModel* skin(const QString& key);
|
SkinModel* skin(const QString& key);
|
||||||
@ -58,14 +58,14 @@ class SkinList : public QAbstractListModel {
|
|||||||
void save();
|
void save();
|
||||||
int getSelectedAccountSkin();
|
int getSelectedAccountSkin();
|
||||||
|
|
||||||
|
void updateSkin(SkinModel s);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// hide copy constructor
|
// hide copy constructor
|
||||||
SkinList(const SkinList&) = delete;
|
SkinList(const SkinList&) = delete;
|
||||||
// hide assign op
|
// hide assign op
|
||||||
SkinList& operator=(const SkinList&) = delete;
|
SkinList& operator=(const SkinList&) = delete;
|
||||||
|
|
||||||
QVector<SkinModel> loadMinecraftSkins();
|
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void directoryChanged(const QString& path);
|
void directoryChanged(const QString& path);
|
||||||
void fileChanged(const QString& path);
|
void fileChanged(const QString& path);
|
||||||
|
@ -31,28 +31,12 @@ SkinModel::SkinModel(QDir skinDir, QJsonObject obj)
|
|||||||
: m_cape_id(Json::ensureString(obj, "capeId")), m_model(Model::CLASSIC), m_url(Json::ensureString(obj, "url"))
|
: m_cape_id(Json::ensureString(obj, "capeId")), m_model(Model::CLASSIC), m_url(Json::ensureString(obj, "url"))
|
||||||
{
|
{
|
||||||
auto name = Json::ensureString(obj, "name");
|
auto name = Json::ensureString(obj, "name");
|
||||||
auto skinImage = Json::ensureString(obj, "skinImage");
|
|
||||||
if (!skinImage.isEmpty()) { // minecraft skin model
|
if (auto model = Json::ensureString(obj, "model"); model == "SLIM") {
|
||||||
skinImage = skinImage.mid(22);
|
m_model = Model::SLIM;
|
||||||
m_texture.loadFromData(QByteArray::fromBase64(skinImage.toUtf8()), "PNG");
|
|
||||||
auto textureId = Json::ensureString(obj, "textureId");
|
|
||||||
if (name.isEmpty()) {
|
|
||||||
name = textureId;
|
|
||||||
}
|
|
||||||
if (Json::ensureBoolean(obj, "slim", false)) {
|
|
||||||
m_model = Model::SLIM;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (auto model = Json::ensureString(obj, "model"); model == "SLIM") {
|
|
||||||
m_model = Model::SLIM;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_path = skinDir.absoluteFilePath(name) + ".png";
|
m_path = skinDir.absoluteFilePath(name) + ".png";
|
||||||
if (!QFileInfo(m_path).exists() && isValid()) {
|
m_texture = QPixmap(m_path);
|
||||||
m_texture.save(m_path, "PNG");
|
|
||||||
} else {
|
|
||||||
m_texture = QPixmap(m_path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SkinModel::name() const
|
QString SkinModel::name() const
|
||||||
@ -92,37 +76,3 @@ bool SkinModel::isValid() const
|
|||||||
{
|
{
|
||||||
return !m_texture.isNull() && (m_texture.size().height() == 32 || m_texture.size().height() == 64) && m_texture.size().width() == 64;
|
return !m_texture.isNull() && (m_texture.size().height() == 32 || m_texture.size().height() == 64) && m_texture.size().width() == 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap SkinModel::renderFrontBody() const
|
|
||||||
{
|
|
||||||
auto isSlim = m_model == SLIM;
|
|
||||||
auto slimOffset = isSlim ? 1 : 0;
|
|
||||||
auto isOldSkin = m_texture.height() < 64;
|
|
||||||
|
|
||||||
auto head = m_texture.copy(QRect(8, 8, 16, 16));
|
|
||||||
auto torso = m_texture.copy(QRect(20, 20, 28, 32));
|
|
||||||
auto rightArm = m_texture.copy(QRect(44, 20, 48 - slimOffset, 32));
|
|
||||||
auto rightLeg = m_texture.copy(QRect(4, 20, 8, 32));
|
|
||||||
QPixmap leftArm, leftLeg;
|
|
||||||
|
|
||||||
if (isOldSkin) {
|
|
||||||
leftArm = rightArm.transformed(QTransform().scale(-1, 1));
|
|
||||||
leftLeg = rightLeg.transformed(QTransform().scale(-1, 1));
|
|
||||||
} else {
|
|
||||||
leftArm = m_texture.copy(QRect(36, 52, 40 - slimOffset, 64));
|
|
||||||
leftLeg = m_texture.copy(QRect(20, 52, 24, 64));
|
|
||||||
}
|
|
||||||
QPixmap output(16, 32);
|
|
||||||
output.fill(Qt::black);
|
|
||||||
QPainter p;
|
|
||||||
if (!p.begin(&output))
|
|
||||||
return {};
|
|
||||||
p.drawPixmap(QPoint(4, 0), head);
|
|
||||||
p.drawPixmap(QPoint(4, 8), torso);
|
|
||||||
p.drawPixmap(QPoint(12, 8), leftArm);
|
|
||||||
p.drawPixmap(QPoint(slimOffset, 8), rightArm);
|
|
||||||
p.drawPixmap(QPoint(8, 20), leftLeg);
|
|
||||||
p.drawPixmap(QPoint(4, 20), leftArm);
|
|
||||||
|
|
||||||
return output.scaled(128, 128, Qt::KeepAspectRatioByExpanding, Qt::FastTransformation);
|
|
||||||
}
|
|
@ -26,6 +26,7 @@ class SkinModel {
|
|||||||
public:
|
public:
|
||||||
enum Model { CLASSIC, SLIM };
|
enum Model { CLASSIC, SLIM };
|
||||||
|
|
||||||
|
SkinModel() = default;
|
||||||
SkinModel(QString path);
|
SkinModel(QString path);
|
||||||
SkinModel(QDir skinDir, QJsonObject obj);
|
SkinModel(QDir skinDir, QJsonObject obj);
|
||||||
virtual ~SkinModel() = default;
|
virtual ~SkinModel() = default;
|
||||||
@ -47,8 +48,6 @@ class SkinModel {
|
|||||||
|
|
||||||
QJsonObject toJSON() const;
|
QJsonObject toJSON() const;
|
||||||
|
|
||||||
QPixmap renderFrontBody() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_path;
|
QString m_path;
|
||||||
QPixmap m_texture;
|
QPixmap m_texture;
|
||||||
|
@ -44,8 +44,8 @@
|
|||||||
|
|
||||||
SkinUpload::SkinUpload(QString token, SkinModel* skin) : NetRequest(), m_skin(skin), m_token(token)
|
SkinUpload::SkinUpload(QString token, SkinModel* skin) : NetRequest(), m_skin(skin), m_token(token)
|
||||||
{
|
{
|
||||||
logCat = taskUploadLogC;
|
logCat = taskMCSkinsLogC;
|
||||||
};
|
}
|
||||||
|
|
||||||
QNetworkReply* SkinUpload::getReply(QNetworkRequest& request)
|
QNetworkReply* SkinUpload::getReply(QNetworkRequest& request)
|
||||||
{
|
{
|
||||||
|
@ -55,6 +55,7 @@ class NetAction : public Task {
|
|||||||
virtual ~NetAction() = default;
|
virtual ~NetAction() = default;
|
||||||
|
|
||||||
QUrl url() { return m_url; }
|
QUrl url() { return m_url; }
|
||||||
|
void setUrl(QUrl url) { m_url = url; }
|
||||||
|
|
||||||
void setNetwork(shared_qobject_ptr<QNetworkAccessManager> network) { m_network = network; }
|
void setNetwork(shared_qobject_ptr<QNetworkAccessManager> network) { m_network = network; }
|
||||||
|
|
||||||
|
@ -16,37 +16,41 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include "SkinManageDialog.h"
|
||||||
#include <QFileInfo>
|
#include "ui_SkinManageDialog.h"
|
||||||
#include <QMimeDatabase>
|
|
||||||
#include <QPainter>
|
|
||||||
|
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QFileDialog>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QListView>
|
#include <QListView>
|
||||||
|
#include <QMimeDatabase>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "DesktopServices.h"
|
#include "DesktopServices.h"
|
||||||
|
#include "Json.h"
|
||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
#include "SkinManageDialog.h"
|
|
||||||
|
|
||||||
#include "minecraft/auth/AccountTask.h"
|
#include "minecraft/auth/AccountTask.h"
|
||||||
|
#include "minecraft/auth/Parsers.h"
|
||||||
#include "minecraft/skins/CapeChange.h"
|
#include "minecraft/skins/CapeChange.h"
|
||||||
#include "minecraft/skins/SkinDelete.h"
|
#include "minecraft/skins/SkinDelete.h"
|
||||||
#include "minecraft/skins/SkinList.h"
|
#include "minecraft/skins/SkinList.h"
|
||||||
#include "minecraft/skins/SkinModel.h"
|
#include "minecraft/skins/SkinModel.h"
|
||||||
#include "minecraft/skins/SkinUpload.h"
|
#include "minecraft/skins/SkinUpload.h"
|
||||||
|
|
||||||
|
#include "net/Download.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
#include "ui/dialogs/ProgressDialog.h"
|
#include "ui/dialogs/ProgressDialog.h"
|
||||||
#include "ui/instanceview/InstanceDelegate.h"
|
#include "ui/instanceview/InstanceDelegate.h"
|
||||||
#include "ui_SkinManageDialog.h"
|
|
||||||
|
|
||||||
SkinManageDialog::SkinManageDialog(QWidget* parent, MinecraftAccountPtr acct)
|
SkinManageDialog::SkinManageDialog(QWidget* parent, MinecraftAccountPtr acct)
|
||||||
: QDialog(parent), m_acct(acct), ui(new Ui::SkinManageDialog), m_list(this, APPLICATION->settings()->get("SkinsDir").toString(), acct)
|
: QDialog(parent), m_acct(acct), ui(new Ui::SkinManageDialog), m_list(this, APPLICATION->settings()->get("SkinsDir").toString(), acct)
|
||||||
@ -132,20 +136,15 @@ void SkinManageDialog::on_openDirBtn_clicked()
|
|||||||
DesktopServices::openDirectory(m_list.getDir(), true);
|
DesktopServices::openDirectory(m_list.getDir(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkinManageDialog::on_addBtn_clicked()
|
void SkinManageDialog::on_fileBtn_clicked()
|
||||||
{
|
{
|
||||||
auto filter = QMimeDatabase().mimeTypeForName("image/png").filterString();
|
auto filter = QMimeDatabase().mimeTypeForName("image/png").filterString();
|
||||||
QString raw_path = QFileDialog::getOpenFileName(this, tr("Select Skin Texture"), QString(), filter);
|
QString raw_path = QFileDialog::getOpenFileName(this, tr("Select Skin Texture"), QString(), filter);
|
||||||
if (raw_path.isEmpty() || !QFileInfo::exists(raw_path)) {
|
auto message = m_list.installSkin(raw_path, {});
|
||||||
|
if (!message.isEmpty()) {
|
||||||
|
CustomMessageBox::selectable(this, tr("Selected file is not a valid skin"), message, QMessageBox::Critical)->show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!SkinModel(raw_path).isValid()) {
|
|
||||||
CustomMessageBox::selectable(this, tr("Selected file is not a valid skin"),
|
|
||||||
tr("Skin images must be 64x64 or 64x32 pixel PNG files."), QMessageBox::Critical)
|
|
||||||
->show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_list.installSkin(raw_path, {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap previewCape(QPixmap capeImage)
|
QPixmap previewCape(QPixmap capeImage)
|
||||||
@ -337,3 +336,132 @@ void SkinManageDialog::on_action_Delete_Skin_triggered(bool checked)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkinManageDialog::on_urlBtn_clicked()
|
||||||
|
{
|
||||||
|
auto url = QUrl(ui->urlLine->text());
|
||||||
|
if (!url.isValid()) {
|
||||||
|
CustomMessageBox::selectable(this, tr("Invalid url"), tr("Invalid url"), QMessageBox::Critical)->show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ui->urlLine->setText("");
|
||||||
|
|
||||||
|
NetJob::Ptr job{ new NetJob(tr("Download skin"), APPLICATION->network()) };
|
||||||
|
|
||||||
|
auto path = FS::PathCombine(m_list.getDir(), url.fileName());
|
||||||
|
job->addNetAction(Net::Download::makeFile(url, path));
|
||||||
|
ProgressDialog dlg(this);
|
||||||
|
dlg.execWithTask(job.get());
|
||||||
|
SkinModel s(path);
|
||||||
|
if (!s.isValid()) {
|
||||||
|
CustomMessageBox::selectable(this, tr("URL is not a valid skin"), tr("Skin images must be 64x64 or 64x32 pixel PNG files."),
|
||||||
|
QMessageBox::Critical)
|
||||||
|
->show();
|
||||||
|
QFile::remove(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (QFileInfo(path).suffix().isEmpty()) {
|
||||||
|
QFile::rename(path, path + ".png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WaitTask : public Task {
|
||||||
|
public:
|
||||||
|
WaitTask() : m_loop(), m_done(false){};
|
||||||
|
virtual ~WaitTask() = default;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void quit()
|
||||||
|
{
|
||||||
|
m_done = true;
|
||||||
|
m_loop.quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void executeTask()
|
||||||
|
{
|
||||||
|
if (!m_done)
|
||||||
|
m_loop.exec();
|
||||||
|
emitSucceeded();
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
QEventLoop m_loop;
|
||||||
|
bool m_done;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SkinManageDialog::on_userBtn_clicked()
|
||||||
|
{
|
||||||
|
auto user = ui->urlLine->text();
|
||||||
|
if (user.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ui->urlLine->setText("");
|
||||||
|
MinecraftProfile mcProfile;
|
||||||
|
auto path = FS::PathCombine(m_list.getDir(), user + ".png");
|
||||||
|
|
||||||
|
NetJob::Ptr job{ new NetJob(tr("Download user skin"), APPLICATION->network(), 1) };
|
||||||
|
|
||||||
|
auto uuidOut = std::make_shared<QByteArray>();
|
||||||
|
auto profileOut = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
|
auto uuidLoop = makeShared<WaitTask>();
|
||||||
|
auto profileLoop = makeShared<WaitTask>();
|
||||||
|
|
||||||
|
auto getUUID = Net::Download::makeByteArray("https://api.mojang.com/users/profiles/minecraft/" + user, uuidOut);
|
||||||
|
auto getProfile = Net::Download::makeByteArray(QUrl(), profileOut);
|
||||||
|
auto downloadSkin = Net::Download::makeFile(QUrl(), path);
|
||||||
|
|
||||||
|
connect(getUUID.get(), &Task::aborted, uuidLoop.get(), &WaitTask::quit);
|
||||||
|
connect(getUUID.get(), &Task::failed, uuidLoop.get(), &WaitTask::quit);
|
||||||
|
connect(getProfile.get(), &Task::aborted, profileLoop.get(), &WaitTask::quit);
|
||||||
|
connect(getProfile.get(), &Task::failed, profileLoop.get(), &WaitTask::quit);
|
||||||
|
|
||||||
|
connect(getUUID.get(), &Task::succeeded, this, [uuidLoop, uuidOut, job, getProfile] {
|
||||||
|
try {
|
||||||
|
QJsonParseError parse_error{};
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(*uuidOut, &parse_error);
|
||||||
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
|
qWarning() << "Error while parsing JSON response from Minecraft skin service at " << parse_error.offset
|
||||||
|
<< " reason: " << parse_error.errorString();
|
||||||
|
uuidLoop->quit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto root = doc.object();
|
||||||
|
auto id = Json::ensureString(root, "id");
|
||||||
|
if (!id.isEmpty()) {
|
||||||
|
getProfile->setUrl("https://sessionserver.mojang.com/session/minecraft/profile/" + id);
|
||||||
|
} else {
|
||||||
|
job->abort();
|
||||||
|
}
|
||||||
|
} catch (const Exception& e) {
|
||||||
|
qCritical() << "Couldn't load skin json:" << e.cause();
|
||||||
|
}
|
||||||
|
uuidLoop->quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(getProfile.get(), &Task::succeeded, this, [profileLoop, profileOut, job, getProfile, &mcProfile, downloadSkin] {
|
||||||
|
if (Parsers::parseMinecraftProfileMojang(*profileOut, mcProfile)) {
|
||||||
|
downloadSkin->setUrl(mcProfile.skin.url);
|
||||||
|
} else {
|
||||||
|
job->abort();
|
||||||
|
}
|
||||||
|
profileLoop->quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
job->addNetAction(getUUID);
|
||||||
|
job->addTask(uuidLoop);
|
||||||
|
job->addNetAction(getProfile);
|
||||||
|
job->addTask(profileLoop);
|
||||||
|
job->addNetAction(downloadSkin);
|
||||||
|
ProgressDialog dlg(this);
|
||||||
|
dlg.execWithTask(job.get());
|
||||||
|
|
||||||
|
SkinModel s(path);
|
||||||
|
s.setModel(mcProfile.skin.variant == "slim" ? SkinModel::SLIM : SkinModel::CLASSIC);
|
||||||
|
s.setURL(mcProfile.skin.url);
|
||||||
|
if (m_capes.contains(mcProfile.currentCape)) {
|
||||||
|
s.setCapeId(mcProfile.currentCape);
|
||||||
|
}
|
||||||
|
m_list.updateSkin(s);
|
||||||
|
}
|
@ -40,7 +40,9 @@ class SkinManageDialog : public QDialog {
|
|||||||
void activated(QModelIndex);
|
void activated(QModelIndex);
|
||||||
void delayed_scroll(QModelIndex);
|
void delayed_scroll(QModelIndex);
|
||||||
void on_openDirBtn_clicked();
|
void on_openDirBtn_clicked();
|
||||||
void on_addBtn_clicked();
|
void on_fileBtn_clicked();
|
||||||
|
void on_urlBtn_clicked();
|
||||||
|
void on_userBtn_clicked();
|
||||||
void accept() override;
|
void accept() override;
|
||||||
void on_capeCombo_currentIndexChanged(int index);
|
void on_capeCombo_currentIndexChanged(int index);
|
||||||
void on_steveBtn_toggled(bool checked);
|
void on_steveBtn_toggled(bool checked);
|
||||||
|
@ -100,7 +100,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="buttonsHLayout" stretch="1,1,1,8">
|
<layout class="QHBoxLayout" name="buttonsHLayout" stretch="0,0,3,0,0,0,1">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="openDirBtn">
|
<widget class="QPushButton" name="openDirBtn">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -108,13 +108,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="addBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Import Skin</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="resetBtn">
|
<widget class="QPushButton" name="resetBtn">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -122,8 +115,42 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="urlLine">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string extracomment="URL or username"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="urlBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Import URL</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="userBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Import user</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="fileBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Import File</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="standardButtons">
|
<property name="standardButtons">
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
</property>
|
</property>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user