Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97
2024-06-10 10:00:52 +03:00
66 changed files with 2109 additions and 1018 deletions

View File

@ -35,7 +35,7 @@
*/
#include "AccountListPage.h"
#include "minecraft/auth/AccountData.h"
#include "ui/dialogs/skins/SkinManageDialog.h"
#include "ui_AccountListPage.h"
#include <QItemSelectionModel>
@ -47,11 +47,6 @@
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/MSALoginDialog.h"
#include "ui/dialogs/OfflineLoginDialog.h"
#include "ui/dialogs/ProgressDialog.h"
#include "ui/dialogs/SkinUploadDialog.h"
#include "minecraft/services/SkinDelete.h"
#include "tasks/Task.h"
#include "Application.h"
@ -233,8 +228,7 @@ void AccountListPage::updateButtonStates()
}
ui->actionRemove->setEnabled(accountIsReady);
ui->actionSetDefault->setEnabled(accountIsReady);
ui->actionUploadSkin->setEnabled(accountIsReady && accountIsOnline);
ui->actionDeleteSkin->setEnabled(accountIsReady && accountIsOnline);
ui->actionManageSkins->setEnabled(accountIsReady && accountIsOnline);
ui->actionRefresh->setEnabled(accountIsReady && accountIsOnline);
if (m_accounts->defaultAccount().get() == nullptr) {
@ -247,29 +241,13 @@ void AccountListPage::updateButtonStates()
ui->listView->resizeColumnToContents(3);
}
void AccountListPage::on_actionUploadSkin_triggered()
void AccountListPage::on_actionManageSkins_triggered()
{
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() > 0) {
QModelIndex selected = selection.first();
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
SkinUploadDialog dialog(account, this);
SkinManageDialog dialog(this, account);
dialog.exec();
}
}
void AccountListPage::on_actionDeleteSkin_triggered()
{
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() <= 0)
return;
QModelIndex selected = selection.first();
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
ProgressDialog prog(this);
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;
}
}

View File

@ -76,8 +76,7 @@ class AccountListPage : public QMainWindow, public BasePage {
void on_actionRefresh_triggered();
void on_actionSetDefault_triggered();
void on_actionNoDefault_triggered();
void on_actionUploadSkin_triggered();
void on_actionDeleteSkin_triggered();
void on_actionManageSkins_triggered();
void listChanged();

View File

@ -59,14 +59,8 @@
<addaction name="actionSetDefault"/>
<addaction name="actionNoDefault"/>
<addaction name="separator"/>
<addaction name="actionUploadSkin"/>
<addaction name="actionDeleteSkin"/>
<addaction name="actionManageSkins"/>
</widget>
<action name="actionRemove">
<property name="text">
<string>Remo&amp;ve</string>
</property>
</action>
<action name="actionSetDefault">
<property name="text">
<string>&amp;Set Default</string>
@ -80,17 +74,12 @@
<string>&amp;No Default</string>
</property>
</action>
<action name="actionUploadSkin">
<action name="actionManageSkins">
<property name="text">
<string>&amp;Upload Skin</string>
</property>
</action>
<action name="actionDeleteSkin">
<property name="text">
<string>&amp;Delete Skin</string>
<string>&amp;Manage Skins</string>
</property>
<property name="toolTip">
<string>Delete the currently active skin and go back to the default one</string>
<string>Manage Skins</string>
</property>
</action>
<action name="actionAddMicrosoft">
@ -111,6 +100,11 @@
<string>Refresh the account tokens</string>
</property>
</action>
<action name="actionRemove">
<property name="text">
<string>Remo&amp;ve</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -173,6 +173,17 @@ void LauncherPage::on_downloadsDirBrowseBtn_clicked()
}
}
void LauncherPage::on_skinsDirBrowseBtn_clicked()
{
QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Skins Folder"), ui->skinsDirTextBox->text());
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if (!raw_dir.isEmpty() && QDir(raw_dir).exists()) {
QString cooked_dir = FS::NormalizePath(raw_dir);
ui->skinsDirTextBox->setText(cooked_dir);
}
}
void LauncherPage::on_metadataDisableBtn_clicked()
{
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
@ -185,6 +196,7 @@ void LauncherPage::applySettings()
// Updates
if (APPLICATION->updater()) {
APPLICATION->updater()->setAutomaticallyChecksForUpdates(ui->autoUpdateCheckBox->isChecked());
APPLICATION->updater()->setUpdateCheckInterval(ui->updateIntervalSpinBox->value() * 3600);
}
s->set("MenuBarInsteadOfToolBar", ui->preferMenuBarCheckBox->isChecked());
@ -208,6 +220,7 @@ void LauncherPage::applySettings()
s->set("CentralModsDir", ui->modsDirTextBox->text());
s->set("IconsDir", ui->iconsDirTextBox->text());
s->set("DownloadsDir", ui->downloadsDirTextBox->text());
s->set("SkinsDir", ui->skinsDirTextBox->text());
s->set("DownloadsDirWatchRecursive", ui->downloadsDirWatchRecursiveCheckBox->isChecked());
auto sortMode = (InstSortMode)ui->sortingModeGroup->checkedId();
@ -234,6 +247,7 @@ void LauncherPage::loadSettings()
// Updates
if (APPLICATION->updater()) {
ui->autoUpdateCheckBox->setChecked(APPLICATION->updater()->getAutomaticallyChecksForUpdates());
ui->updateIntervalSpinBox->setValue(APPLICATION->updater()->getUpdateCheckInterval() / 3600);
}
// Toolbar/menu bar settings (not applicable if native menu bar is present)
@ -269,6 +283,7 @@ void LauncherPage::loadSettings()
ui->modsDirTextBox->setText(s->get("CentralModsDir").toString());
ui->iconsDirTextBox->setText(s->get("IconsDir").toString());
ui->downloadsDirTextBox->setText(s->get("DownloadsDir").toString());
ui->skinsDirTextBox->setText(s->get("SkinsDir").toString());
ui->downloadsDirWatchRecursiveCheckBox->setChecked(s->get("DownloadsDirWatchRecursive").toBool());
QString sortMode = s->get("InstSortMode").toString();

View File

@ -74,6 +74,7 @@ class LauncherPage : public QWidget, public BasePage {
void on_modsDirBrowseBtn_clicked();
void on_iconsDirBrowseBtn_clicked();
void on_downloadsDirBrowseBtn_clicked();
void on_skinsDirBrowseBtn_clicked();
void on_metadataDisableBtn_clicked();
/*!

View File

@ -58,6 +58,33 @@
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="updateSetingsLayout">
<item row="0" column="0">
<widget class="QLabel" name="updateIntervalLabel">
<property name="text">
<string>Update interval</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="updateIntervalSpinBox">
<property name="toolTip">
<string>Set it to 0 to only check on launch</string>
</property>
<property name="suffix">
<string>h</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>99999999</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
@ -67,7 +94,7 @@
<string>Folders</string>
</property>
<layout class="QGridLayout" name="foldersBoxLayout">
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="labelDownloadsDir">
<property name="text">
<string>&amp;Downloads:</string>
@ -90,13 +117,16 @@
<item row="0" column="1">
<widget class="QLineEdit" name="instDirTextBox"/>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QLineEdit" name="downloadsDirTextBox"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="iconsDirTextBox"/>
</item>
<item row="3" column="2">
<item row="3" column="1">
<widget class="QLineEdit" name="skinsDirTextBox"/>
</item>
<item row="4" column="2">
<widget class="QToolButton" name="downloadsDirBrowseBtn">
<property name="text">
<string>Browse</string>
@ -147,7 +177,24 @@
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<item row="3" column="2">
<widget class="QToolButton" name="skinsDirBrowseBtn">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelSkinsDir">
<property name="text">
<string>&amp;Skins:</string>
</property>
<property name="buddy">
<cstring>skinsDirTextBox</cstring>
</property>
</widget>
</item>
<item row="5" column="1" colspan="2">
<widget class="QCheckBox" name="downloadsDirWatchRecursiveCheckBox">
<property name="toolTip">
<string>When enabled, in addition to the downloads folder, its sub folders will also be searched when looking for resources (e.g. when looking for blocked mods on CurseForge).</string>

View File

@ -21,6 +21,7 @@
#include "ui_ImportFTBPage.h"
#include <QFileDialog>
#include <QFileInfo>
#include <QWidget>
#include "FileSystem.h"
#include "ListModel.h"
@ -58,8 +59,8 @@ ImportFTBPage::ImportFTBPage(NewInstanceDialog* dialog, QWidget* parent) : QWidg
connect(ui->searchEdit, &QLineEdit::textChanged, this, &ImportFTBPage::triggerSearch);
connect(ui->browseButton, &QPushButton::clicked, this, [this] {
auto path = listModel->getPath();
QString dir = QFileDialog::getExistingDirectory(this, tr("Select FTBApp instances directory"), path, QFileDialog::ShowDirsOnly);
QString dir = QFileDialog::getExistingDirectory(this, tr("Select FTBApp instances directory"), listModel->getUserPath(),
QFileDialog::ShowDirsOnly);
if (!dir.isEmpty())
listModel->setPath(dir);
});

View File

@ -24,45 +24,76 @@
#include <QIcon>
#include <QProcessEnvironment>
#include "Application.h"
#include "Exception.h"
#include "FileSystem.h"
#include "Json.h"
#include "StringUtils.h"
#include "modplatform/import_ftb/PackHelpers.h"
#include "ui/widgets/ProjectItem.h"
namespace FTBImportAPP {
QString getStaticPath()
QString getFTBRoot()
{
QString partialPath;
QString partialPath = QDir::homePath();
#if defined(Q_OS_OSX)
partialPath = FS::PathCombine(QDir::homePath(), "Library/Application Support");
#elif defined(Q_OS_WIN32)
partialPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", "");
#else
partialPath = QDir::homePath();
partialPath = FS::PathCombine(partialPath, "Library/Application Support");
#endif
return FS::PathCombine(partialPath, ".ftba");
}
static const QString FTB_APP_PATH = FS::PathCombine(getStaticPath(), "instances");
QString getDynamicPath()
{
auto settingsPath = FS::PathCombine(getFTBRoot(), "storage", "settings.json");
if (!QFileInfo::exists(settingsPath))
settingsPath = FS::PathCombine(getFTBRoot(), "bin", "settings.json");
if (!QFileInfo::exists(settingsPath)) {
qWarning() << "The ftb app setings doesn't exist.";
return {};
}
try {
auto doc = Json::requireDocument(FS::read(settingsPath));
return Json::requireString(Json::requireObject(doc), "instanceLocation");
} catch (const Exception& e) {
qCritical() << "Could not read ftb settings file: " << e.cause();
}
return {};
}
ListModel::ListModel(QObject* parent) : QAbstractListModel(parent), m_instances_path(getDynamicPath()) {}
void ListModel::update()
{
beginResetModel();
modpacks.clear();
m_modpacks.clear();
QString instancesPath = getPath();
if (auto instancesInfo = QFileInfo(instancesPath); instancesInfo.exists() && instancesInfo.isDir()) {
QDirIterator directoryIterator(instancesPath, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable | QDir::Hidden,
auto wasPathAdded = [this](QString path) {
for (auto pack : m_modpacks) {
if (pack.path == path)
return true;
}
return false;
};
auto scanPath = [this, wasPathAdded](QString path) {
if (path.isEmpty())
return;
if (auto instancesInfo = QFileInfo(path); !instancesInfo.exists() || !instancesInfo.isDir())
return;
QDirIterator directoryIterator(path, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable | QDir::Hidden,
QDirIterator::FollowSymlinks);
while (directoryIterator.hasNext()) {
auto modpack = parseDirectory(directoryIterator.next());
if (!modpack.path.isEmpty())
modpacks.append(modpack);
auto currentPath = directoryIterator.next();
if (!wasPathAdded(currentPath)) {
auto modpack = parseDirectory(currentPath);
if (!modpack.path.isEmpty())
m_modpacks.append(modpack);
}
}
} else {
qDebug() << "Couldn't find ftb instances folder: " << instancesPath;
}
};
scanPath(APPLICATION->settings()->get("FTBAppInstancesPath").toString());
scanPath(m_instances_path);
endResetModel();
}
@ -70,11 +101,11 @@ void ListModel::update()
QVariant ListModel::data(const QModelIndex& index, int role) const
{
int pos = index.row();
if (pos >= modpacks.size() || pos < 0 || !index.isValid()) {
if (pos >= m_modpacks.size() || pos < 0 || !index.isValid()) {
return QVariant();
}
auto pack = modpacks.at(pos);
auto pack = m_modpacks.at(pos);
if (role == Qt::ToolTipRole) {
}
@ -110,9 +141,9 @@ QVariant ListModel::data(const QModelIndex& index, int role) const
FilterModel::FilterModel(QObject* parent) : QSortFilterProxyModel(parent)
{
currentSorting = Sorting::ByGameVersion;
sortings.insert(tr("Sort by Name"), Sorting::ByName);
sortings.insert(tr("Sort by Game Version"), Sorting::ByGameVersion);
m_currentSorting = Sorting::ByGameVersion;
m_sortings.insert(tr("Sort by Name"), Sorting::ByName);
m_sortings.insert(tr("Sort by Game Version"), Sorting::ByGameVersion);
}
bool FilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
@ -120,12 +151,12 @@ bool FilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) co
Modpack leftPack = sourceModel()->data(left, Qt::UserRole).value<Modpack>();
Modpack rightPack = sourceModel()->data(right, Qt::UserRole).value<Modpack>();
if (currentSorting == Sorting::ByGameVersion) {
if (m_currentSorting == Sorting::ByGameVersion) {
Version lv(leftPack.mcVersion);
Version rv(rightPack.mcVersion);
return lv < rv;
} else if (currentSorting == Sorting::ByName) {
} else if (m_currentSorting == Sorting::ByName) {
return StringUtils::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
}
@ -136,39 +167,39 @@ bool FilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) co
bool FilterModel::filterAcceptsRow([[maybe_unused]] int sourceRow, [[maybe_unused]] const QModelIndex& sourceParent) const
{
if (searchTerm.isEmpty()) {
if (m_searchTerm.isEmpty()) {
return true;
}
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
Modpack pack = sourceModel()->data(index, Qt::UserRole).value<Modpack>();
return pack.name.contains(searchTerm, Qt::CaseInsensitive);
return pack.name.contains(m_searchTerm, Qt::CaseInsensitive);
}
void FilterModel::setSearchTerm(const QString term)
{
searchTerm = term.trimmed();
m_searchTerm = term.trimmed();
invalidate();
}
const QMap<QString, FilterModel::Sorting> FilterModel::getAvailableSortings()
{
return sortings;
return m_sortings;
}
QString FilterModel::translateCurrentSorting()
{
return sortings.key(currentSorting);
return m_sortings.key(m_currentSorting);
}
void FilterModel::setSorting(Sorting s)
{
currentSorting = s;
m_currentSorting = s;
invalidate();
}
FilterModel::Sorting FilterModel::getCurrentSorting()
{
return currentSorting;
return m_currentSorting;
}
void ListModel::setPath(QString path)
{
@ -176,11 +207,11 @@ void ListModel::setPath(QString path)
update();
}
QString ListModel::getPath()
QString ListModel::getUserPath()
{
auto path = APPLICATION->settings()->get("FTBAppInstancesPath").toString();
if (path.isEmpty() || !QFileInfo(path).exists())
path = FTB_APP_PATH;
if (path.isEmpty())
path = m_instances_path;
return path;
}
} // namespace FTBImportAPP

View File

@ -42,28 +42,29 @@ class FilterModel : public QSortFilterProxyModel {
bool lessThan(const QModelIndex& left, const QModelIndex& right) const override;
private:
QMap<QString, Sorting> sortings;
Sorting currentSorting;
QString searchTerm;
QMap<QString, Sorting> m_sortings;
Sorting m_currentSorting;
QString m_searchTerm;
};
class ListModel : public QAbstractListModel {
Q_OBJECT
public:
ListModel(QObject* parent) : QAbstractListModel(parent) {}
ListModel(QObject* parent);
virtual ~ListModel() = default;
int rowCount(const QModelIndex& parent) const { return modpacks.size(); }
int rowCount(const QModelIndex& parent) const { return m_modpacks.size(); }
int columnCount(const QModelIndex& parent) const { return 1; }
QVariant data(const QModelIndex& index, int role) const;
void update();
QString getPath();
QString getUserPath();
void setPath(QString path);
private:
ModpackList modpacks;
ModpackList m_modpacks;
const QString m_instances_path;
};
} // namespace FTBImportAPP