Merge branch 'develop' of github.com:Trial97/PrismLauncher into feature/java-downloader
This commit is contained in:
commit
cfdf4a9e1f
@ -64,7 +64,8 @@ modules:
|
|||||||
config-opts:
|
config-opts:
|
||||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
- -DBUILD_SHARED_LIBS:BOOL=ON
|
- -DBUILD_SHARED_LIBS:BOOL=ON
|
||||||
- -DGLFW_USE_WAYLAND=ON
|
- -DGLFW_USE_WAYLAND:BOOL=ON
|
||||||
|
- -DGLFW_BUILD_DOCS:BOOL=OFF
|
||||||
sources:
|
sources:
|
||||||
- type: git
|
- type: git
|
||||||
url: https://github.com/glfw/glfw.git
|
url: https://github.com/glfw/glfw.git
|
||||||
|
@ -818,25 +818,78 @@ QString NormalizePath(QString path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString BAD_PATH_CHARS = "\"?<>:;*|!+\r\n";
|
QString removeDuplicates(QString a)
|
||||||
static const QString BAD_FILENAME_CHARS = BAD_PATH_CHARS + "\\/";
|
{
|
||||||
|
auto b = a.split("");
|
||||||
|
b.removeDuplicates();
|
||||||
|
return b.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const QString BAD_WIN_CHARS = "\"?<>:*|\r\n";
|
||||||
|
|
||||||
|
static const QString BAD_FAT_CHARS = "<>:\"|?*+.,;=[]!";
|
||||||
|
static const QString BAD_NTFS_CHARS = "<>:\"|?*";
|
||||||
|
static const QString BAD_HFS_CHARS = ":";
|
||||||
|
|
||||||
|
static const QString BAD_FILENAME_CHARS = removeDuplicates(BAD_WIN_CHARS + BAD_FAT_CHARS + BAD_NTFS_CHARS + BAD_HFS_CHARS) + "\\/";
|
||||||
|
|
||||||
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < string.length(); i++)
|
for (int i = 0; i < string.length(); i++)
|
||||||
if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i)))
|
if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i)))
|
||||||
string[i] = replaceWith;
|
string[i] = replaceWith;
|
||||||
|
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RemoveInvalidPathChars(QString string, QChar replaceWith)
|
QString RemoveInvalidPathChars(QString path, QChar replaceWith)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < string.length(); i++)
|
QString invalidChars;
|
||||||
if (string.at(i) < ' ' || BAD_PATH_CHARS.contains(string.at(i)))
|
#ifdef Q_OS_WIN
|
||||||
string[i] = replaceWith;
|
invalidChars = BAD_WIN_CHARS;
|
||||||
|
#endif
|
||||||
|
|
||||||
return string;
|
// the null character is ignored in this check as it was not a problem until now
|
||||||
|
switch (statFS(path).fsType) {
|
||||||
|
case FilesystemType::FAT:
|
||||||
|
invalidChars += BAD_FAT_CHARS;
|
||||||
|
break;
|
||||||
|
case FilesystemType::NTFS:
|
||||||
|
/* fallthrough */
|
||||||
|
case FilesystemType::REFS: // similar to NTFS(should be available only on windows)
|
||||||
|
invalidChars += BAD_NTFS_CHARS;
|
||||||
|
break;
|
||||||
|
// case FilesystemType::EXT:
|
||||||
|
// case FilesystemType::EXT_2_OLD:
|
||||||
|
// case FilesystemType::EXT_2_3_4:
|
||||||
|
// case FilesystemType::XFS:
|
||||||
|
// case FilesystemType::BTRFS:
|
||||||
|
// case FilesystemType::NFS:
|
||||||
|
// case FilesystemType::ZFS:
|
||||||
|
case FilesystemType::APFS:
|
||||||
|
/* fallthrough */
|
||||||
|
case FilesystemType::HFS:
|
||||||
|
/* fallthrough */
|
||||||
|
case FilesystemType::HFSPLUS:
|
||||||
|
/* fallthrough */
|
||||||
|
case FilesystemType::HFSX:
|
||||||
|
invalidChars += BAD_HFS_CHARS;
|
||||||
|
break;
|
||||||
|
// case FilesystemType::FUSEBLK:
|
||||||
|
// case FilesystemType::F2FS:
|
||||||
|
// case FilesystemType::UNKNOWN:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidChars.size() != 0) {
|
||||||
|
for (int i = 0; i < path.length(); i++) {
|
||||||
|
if (path.at(i) < ' ' || invalidChars.contains(path.at(i))) {
|
||||||
|
path[i] = replaceWith;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DirNameFromString(QString string, QString inDir)
|
QString DirNameFromString(QString string, QString inDir)
|
||||||
|
@ -84,7 +84,7 @@ void LaunchController::decideAccount()
|
|||||||
|
|
||||||
// Find an account to use.
|
// Find an account to use.
|
||||||
auto accounts = APPLICATION->accounts();
|
auto accounts = APPLICATION->accounts();
|
||||||
if (accounts->count() <= 0) {
|
if (accounts->count() <= 0 || !accounts->anyAccountIsValid()) {
|
||||||
// Tell the user they need to log in at least one account in order to play.
|
// Tell the user they need to log in at least one account in order to play.
|
||||||
auto reply = CustomMessageBox::selectable(m_parentWidget, tr("No Accounts"),
|
auto reply = CustomMessageBox::selectable(m_parentWidget, tr("No Accounts"),
|
||||||
tr("In order to play Minecraft, you must have at least one Microsoft "
|
tr("In order to play Minecraft, you must have at least one Microsoft "
|
||||||
@ -128,12 +128,63 @@ void LaunchController::decideAccount()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LaunchController::askPlayDemo()
|
||||||
|
{
|
||||||
|
QMessageBox box(m_parentWidget);
|
||||||
|
box.setWindowTitle(tr("Play demo?"));
|
||||||
|
box.setText(
|
||||||
|
tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play "
|
||||||
|
"the demo?"));
|
||||||
|
box.setIcon(QMessageBox::Warning);
|
||||||
|
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
|
||||||
|
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
|
||||||
|
box.setDefaultButton(cancelButton);
|
||||||
|
|
||||||
|
box.exec();
|
||||||
|
return box.clickedButton() == demoButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LaunchController::askOfflineName(QString playerName, bool demo, bool& ok)
|
||||||
|
{
|
||||||
|
// we ask the user for a player name
|
||||||
|
QString message = tr("Choose your offline mode player name.");
|
||||||
|
if (demo) {
|
||||||
|
message = tr("Choose your demo mode player name.");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
||||||
|
QString usedname = lastOfflinePlayerName.isEmpty() ? playerName : lastOfflinePlayerName;
|
||||||
|
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok);
|
||||||
|
if (!ok)
|
||||||
|
return {};
|
||||||
|
if (name.length()) {
|
||||||
|
usedname = name;
|
||||||
|
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
||||||
|
}
|
||||||
|
return usedname;
|
||||||
|
}
|
||||||
|
|
||||||
void LaunchController::login()
|
void LaunchController::login()
|
||||||
{
|
{
|
||||||
decideAccount();
|
decideAccount();
|
||||||
|
|
||||||
// if no account is selected, we bail
|
|
||||||
if (!m_accountToUse) {
|
if (!m_accountToUse) {
|
||||||
|
// if no account is selected, ask about demo
|
||||||
|
if (!m_demo) {
|
||||||
|
m_demo = askPlayDemo();
|
||||||
|
}
|
||||||
|
if (m_demo) {
|
||||||
|
// we ask the user for a player name
|
||||||
|
bool ok = false;
|
||||||
|
auto name = askOfflineName("Player", m_demo, ok);
|
||||||
|
if (ok) {
|
||||||
|
m_session = std::make_shared<AuthSession>();
|
||||||
|
m_session->MakeDemo(name, MinecraftAccount::uuidFromUsername(name).toString().remove(QRegularExpression("[{}-]")));
|
||||||
|
launchInstance();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if no account is selected, we bail
|
||||||
emitFailed(tr("No account selected for launch."));
|
emitFailed(tr("No account selected for launch."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -180,24 +231,12 @@ void LaunchController::login()
|
|||||||
if (!m_session->wants_online) {
|
if (!m_session->wants_online) {
|
||||||
// we ask the user for a player name
|
// we ask the user for a player name
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
auto name = askOfflineName(m_session->player_name, m_session->demo, ok);
|
||||||
QString message = tr("Choose your offline mode player name.");
|
|
||||||
if (m_session->demo) {
|
|
||||||
message = tr("Choose your demo mode player name.");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
|
||||||
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
|
|
||||||
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok);
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
tryagain = false;
|
tryagain = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (name.length()) {
|
m_session->MakeOffline(name);
|
||||||
usedname = name;
|
|
||||||
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
|
||||||
}
|
|
||||||
m_session->MakeOffline(usedname);
|
|
||||||
// offline flavored game from here :3
|
// offline flavored game from here :3
|
||||||
}
|
}
|
||||||
if (m_accountToUse->ownsMinecraft()) {
|
if (m_accountToUse->ownsMinecraft()) {
|
||||||
@ -217,20 +256,10 @@ void LaunchController::login()
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// play demo ?
|
// play demo ?
|
||||||
QMessageBox box(m_parentWidget);
|
if (!m_session->demo) {
|
||||||
box.setWindowTitle(tr("Play demo?"));
|
m_session->demo = askPlayDemo();
|
||||||
box.setText(
|
}
|
||||||
tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play "
|
if (m_session->demo) { // play demo here
|
||||||
"the demo?"));
|
|
||||||
box.setIcon(QMessageBox::Warning);
|
|
||||||
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
|
|
||||||
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
|
|
||||||
box.setDefaultButton(cancelButton);
|
|
||||||
|
|
||||||
box.exec();
|
|
||||||
if (box.clickedButton() == demoButton) {
|
|
||||||
// play demo here
|
|
||||||
m_session->MakeDemo();
|
|
||||||
launchInstance();
|
launchInstance();
|
||||||
} else {
|
} else {
|
||||||
emitFailed(tr("Launch cancelled - account does not own Minecraft."));
|
emitFailed(tr("Launch cancelled - account does not own Minecraft."));
|
||||||
|
@ -74,6 +74,8 @@ class LaunchController : public Task {
|
|||||||
void login();
|
void login();
|
||||||
void launchInstance();
|
void launchInstance();
|
||||||
void decideAccount();
|
void decideAccount();
|
||||||
|
bool askPlayDemo();
|
||||||
|
QString askOfflineName(QString playerName, bool demo, bool& ok);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void readyForLaunch();
|
void readyForLaunch();
|
||||||
|
@ -289,9 +289,7 @@ std::optional<QStringList> extractSubDir(QuaZip* zip, const QString& subdir, con
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
QString file_name = zip->getCurrentFileName();
|
QString file_name = zip->getCurrentFileName();
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
file_name = FS::RemoveInvalidPathChars(file_name);
|
file_name = FS::RemoveInvalidPathChars(file_name);
|
||||||
#endif
|
|
||||||
if (!file_name.startsWith(subdir))
|
if (!file_name.startsWith(subdir))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ void Library::getApplicableFiles(const RuntimeContext& runtimeContext,
|
|||||||
{
|
{
|
||||||
bool local = isLocal();
|
bool local = isLocal();
|
||||||
auto actualPath = [&](QString relPath) {
|
auto actualPath = [&](QString relPath) {
|
||||||
|
relPath = FS::RemoveInvalidPathChars(relPath);
|
||||||
QFileInfo out(FS::PathCombine(storagePrefix(), relPath));
|
QFileInfo out(FS::PathCombine(storagePrefix(), relPath));
|
||||||
if (local && !overridePath.isEmpty()) {
|
if (local && !overridePath.isEmpty()) {
|
||||||
QString fileName = out.fileName();
|
QString fileName = out.fileName();
|
||||||
|
@ -30,8 +30,13 @@ bool AuthSession::MakeOffline(QString offline_playername)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuthSession::MakeDemo()
|
void AuthSession::MakeDemo(QString name, QString u)
|
||||||
{
|
{
|
||||||
player_name = "Player";
|
wants_online = false;
|
||||||
demo = true;
|
demo = true;
|
||||||
}
|
uuid = u;
|
||||||
|
session = "-";
|
||||||
|
access_token = "0";
|
||||||
|
player_name = name;
|
||||||
|
status = PlayableOnline; // needs online to download the assets
|
||||||
|
};
|
@ -10,7 +10,7 @@ class QNetworkAccessManager;
|
|||||||
|
|
||||||
struct AuthSession {
|
struct AuthSession {
|
||||||
bool MakeOffline(QString offline_playername);
|
bool MakeOffline(QString offline_playername);
|
||||||
void MakeDemo();
|
void MakeDemo(QString name, QString uuid);
|
||||||
|
|
||||||
QString serializeUserProperties();
|
QString serializeUserProperties();
|
||||||
|
|
||||||
|
@ -83,8 +83,6 @@ MinecraftAccountPtr MinecraftAccount::createOffline(const QString& username)
|
|||||||
account->data.yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc();
|
account->data.yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc();
|
||||||
account->data.yggdrasilToken.extra["userName"] = username;
|
account->data.yggdrasilToken.extra["userName"] = username;
|
||||||
account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
|
account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
|
||||||
account->data.minecraftEntitlement.ownsMinecraft = true;
|
|
||||||
account->data.minecraftEntitlement.canPlayMinecraft = true;
|
|
||||||
account->data.minecraftProfile.id = uuidFromUsername(username).toString().remove(QRegularExpression("[{}-]"));
|
account->data.minecraftProfile.id = uuidFromUsername(username).toString().remove(QRegularExpression("[{}-]"));
|
||||||
account->data.minecraftProfile.name = username;
|
account->data.minecraftProfile.name = username;
|
||||||
account->data.minecraftProfile.validity = Validity::Certain;
|
account->data.minecraftProfile.validity = Validity::Certain;
|
||||||
@ -253,6 +251,8 @@ void MinecraftAccount::fillSession(AuthSessionPtr session)
|
|||||||
session->player_name = data.profileName();
|
session->player_name = data.profileName();
|
||||||
// profile ID
|
// profile ID
|
||||||
session->uuid = data.profileId();
|
session->uuid = data.profileId();
|
||||||
|
if (session->uuid.isEmpty())
|
||||||
|
session->uuid = uuidFromUsername(session->player_name).toString().remove(QRegularExpression("[{}-]"));
|
||||||
// 'legacy' or 'mojang', depending on account type
|
// 'legacy' or 'mojang', depending on account type
|
||||||
session->user_type = typeString();
|
session->user_type = typeString();
|
||||||
if (!session->access_token.isEmpty()) {
|
if (!session->access_token.isEmpty()) {
|
||||||
|
@ -116,7 +116,7 @@ class MinecraftAccount : public QObject, public Usable {
|
|||||||
|
|
||||||
[[nodiscard]] AccountType accountType() const noexcept { return data.type; }
|
[[nodiscard]] AccountType accountType() const noexcept { return data.type; }
|
||||||
|
|
||||||
bool ownsMinecraft() const { return data.minecraftEntitlement.ownsMinecraft; }
|
bool ownsMinecraft() const { return data.type != AccountType::Offline && data.minecraftEntitlement.ownsMinecraft; }
|
||||||
|
|
||||||
bool hasProfile() const { return data.profileId().size() != 0; }
|
bool hasProfile() const { return data.profileId().size() != 0; }
|
||||||
|
|
||||||
|
@ -538,9 +538,7 @@ void FlameCreationTask::setupDownloadJob(QEventLoop& loop)
|
|||||||
}
|
}
|
||||||
for (const auto& result : results) {
|
for (const auto& result : results) {
|
||||||
auto fileName = result.fileName;
|
auto fileName = result.fileName;
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
fileName = FS::RemoveInvalidPathChars(fileName);
|
fileName = FS::RemoveInvalidPathChars(fileName);
|
||||||
#endif
|
|
||||||
auto relpath = FS::PathCombine(result.targetFolder, fileName);
|
auto relpath = FS::PathCombine(result.targetFolder, fileName);
|
||||||
|
|
||||||
if (!result.required && !selectedOptionalMods.contains(relpath)) {
|
if (!result.required && !selectedOptionalMods.contains(relpath)) {
|
||||||
|
@ -139,9 +139,7 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
|
|||||||
file.version = Json::requireString(obj, "displayName");
|
file.version = Json::requireString(obj, "displayName");
|
||||||
file.downloadUrl = Json::ensureString(obj, "downloadUrl");
|
file.downloadUrl = Json::ensureString(obj, "downloadUrl");
|
||||||
file.fileName = Json::requireString(obj, "fileName");
|
file.fileName = Json::requireString(obj, "fileName");
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
file.fileName = FS::RemoveInvalidPathChars(file.fileName);
|
file.fileName = FS::RemoveInvalidPathChars(file.fileName);
|
||||||
#endif
|
|
||||||
|
|
||||||
ModPlatform::IndexedVersionType::VersionType ver_type;
|
ModPlatform::IndexedVersionType::VersionType ver_type;
|
||||||
switch (Json::requireInteger(obj, "releaseType")) {
|
switch (Json::requireInteger(obj, "releaseType")) {
|
||||||
|
@ -241,9 +241,7 @@ bool ModrinthCreationTask::createInstance()
|
|||||||
|
|
||||||
for (auto file : m_files) {
|
for (auto file : m_files) {
|
||||||
auto fileName = file.path;
|
auto fileName = file.path;
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
fileName = FS::RemoveInvalidPathChars(fileName);
|
fileName = FS::RemoveInvalidPathChars(fileName);
|
||||||
#endif
|
|
||||||
auto file_path = FS::PathCombine(root_modpack_path, fileName);
|
auto file_path = FS::PathCombine(root_modpack_path, fileName);
|
||||||
if (!root_modpack_url.isParentOf(QUrl::fromLocalFile(file_path))) {
|
if (!root_modpack_url.isParentOf(QUrl::fromLocalFile(file_path))) {
|
||||||
// This means we somehow got out of the root folder, so abort here to prevent exploits
|
// This means we somehow got out of the root folder, so abort here to prevent exploits
|
||||||
|
@ -227,9 +227,7 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
|
|||||||
if (parent.contains("url")) {
|
if (parent.contains("url")) {
|
||||||
file.downloadUrl = Json::requireString(parent, "url");
|
file.downloadUrl = Json::requireString(parent, "url");
|
||||||
file.fileName = Json::requireString(parent, "filename");
|
file.fileName = Json::requireString(parent, "filename");
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
file.fileName = FS::RemoveInvalidPathChars(file.fileName);
|
file.fileName = FS::RemoveInvalidPathChars(file.fileName);
|
||||||
#endif
|
|
||||||
file.is_preferred = Json::requireBoolean(parent, "primary") || (files.count() == 1);
|
file.is_preferred = Json::requireBoolean(parent, "primary") || (files.count() == 1);
|
||||||
auto hash_list = Json::requireObject(parent, "hashes");
|
auto hash_list = Json::requireObject(parent, "hashes");
|
||||||
|
|
||||||
|
@ -83,8 +83,10 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings,
|
|||||||
data = file.readAll();
|
data = file.readAll();
|
||||||
file.close();
|
file.close();
|
||||||
} else {
|
} else {
|
||||||
if (minecraftVersion.isEmpty())
|
if (minecraftVersion.isEmpty()) {
|
||||||
emit failed(tr("Could not find \"version.json\" inside \"bin/modpack.jar\", but Minecraft version is unknown"));
|
emit failed(tr("Could not find \"version.json\" inside \"bin/modpack.jar\", but Minecraft version is unknown"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
components->setComponentVersion("net.minecraft", minecraftVersion, true);
|
components->setComponentVersion("net.minecraft", minecraftVersion, true);
|
||||||
components->installJarMods({ modpackJar });
|
components->installJarMods({ modpackJar });
|
||||||
|
|
||||||
@ -131,7 +133,9 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings,
|
|||||||
file.close();
|
file.close();
|
||||||
} else {
|
} else {
|
||||||
// This is the "Vanilla" modpack, excluded by the search code
|
// This is the "Vanilla" modpack, excluded by the search code
|
||||||
emit failed(tr("Unable to find a \"version.json\"!"));
|
components->setComponentVersion("net.minecraft", minecraftVersion, true);
|
||||||
|
components->saveNow();
|
||||||
|
emit succeeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,9 +84,7 @@ auto HttpMetaCache::getEntry(QString base, QString resource_path) -> MetaEntryPt
|
|||||||
|
|
||||||
auto HttpMetaCache::resolveEntry(QString base, QString resource_path, QString expected_etag) -> MetaEntryPtr
|
auto HttpMetaCache::resolveEntry(QString base, QString resource_path, QString expected_etag) -> MetaEntryPtr
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
resource_path = FS::RemoveInvalidPathChars(resource_path);
|
resource_path = FS::RemoveInvalidPathChars(resource_path);
|
||||||
#endif
|
|
||||||
auto entry = getEntry(base, resource_path);
|
auto entry = getEntry(base, resource_path);
|
||||||
// it's not present? generate a default stale entry
|
// it's not present? generate a default stale entry
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
Net::NetRequest::Ptr ImgurAlbumCreation::make(std::shared_ptr<ImgurAlbumCreation::Result> output, QList<ScreenShot::Ptr> screenshots)
|
Net::NetRequest::Ptr ImgurAlbumCreation::make(std::shared_ptr<ImgurAlbumCreation::Result> output, QList<ScreenShot::Ptr> screenshots)
|
||||||
{
|
{
|
||||||
auto up = makeShared<ImgurAlbumCreation>();
|
auto up = makeShared<ImgurAlbumCreation>();
|
||||||
up->m_url = BuildConfig.IMGUR_BASE_URL + "album.json";
|
up->m_url = BuildConfig.IMGUR_BASE_URL + "album";
|
||||||
up->m_sink.reset(new Sink(output));
|
up->m_sink.reset(new Sink(output));
|
||||||
up->m_screenshots = screenshots;
|
up->m_screenshots = screenshots;
|
||||||
return up;
|
return up;
|
||||||
@ -72,7 +72,7 @@ void ImgurAlbumCreation::init()
|
|||||||
qDebug() << "Setting up imgur upload";
|
qDebug() << "Setting up imgur upload";
|
||||||
auto api_headers = new Net::StaticHeaderProxy(
|
auto api_headers = new Net::StaticHeaderProxy(
|
||||||
QList<Net::HeaderPair>{ { "Content-Type", "application/x-www-form-urlencoded" },
|
QList<Net::HeaderPair>{ { "Content-Type", "application/x-www-form-urlencoded" },
|
||||||
{ "Authorization", QString("Client-ID %1").arg(BuildConfig.IMGUR_CLIENT_ID).toStdString().c_str() },
|
{ "Authorization", QString("Client-ID %1").arg(BuildConfig.IMGUR_CLIENT_ID).toUtf8() },
|
||||||
{ "Accept", "application/json" } });
|
{ "Accept", "application/json" } });
|
||||||
addHeaderProxy(api_headers);
|
addHeaderProxy(api_headers);
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,8 @@
|
|||||||
void ImgurUpload::init()
|
void ImgurUpload::init()
|
||||||
{
|
{
|
||||||
qDebug() << "Setting up imgur upload";
|
qDebug() << "Setting up imgur upload";
|
||||||
auto api_headers = new Net::StaticHeaderProxy(
|
auto api_headers = new Net::StaticHeaderProxy(QList<Net::HeaderPair>{
|
||||||
QList<Net::HeaderPair>{ { "Authorization", QString("Client-ID %1").arg(BuildConfig.IMGUR_CLIENT_ID).toStdString().c_str() },
|
{ "Authorization", QString("Client-ID %1").arg(BuildConfig.IMGUR_CLIENT_ID).toUtf8() }, { "Accept", "application/json" } });
|
||||||
{ "Accept", "application/json" } });
|
|
||||||
addHeaderProxy(api_headers);
|
addHeaderProxy(api_headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,14 +69,14 @@ QNetworkReply* ImgurUpload::getReply(QNetworkRequest& request)
|
|||||||
QHttpPart filePart;
|
QHttpPart filePart;
|
||||||
filePart.setBodyDevice(file);
|
filePart.setBodyDevice(file);
|
||||||
filePart.setHeader(QNetworkRequest::ContentTypeHeader, "image/png");
|
filePart.setHeader(QNetworkRequest::ContentTypeHeader, "image/png");
|
||||||
filePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"image\"");
|
filePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"image\"; filename=\"" + file->fileName() + "\"");
|
||||||
multipart->append(filePart);
|
multipart->append(filePart);
|
||||||
QHttpPart typePart;
|
QHttpPart typePart;
|
||||||
typePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"type\"");
|
typePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"type\"");
|
||||||
typePart.setBody("file");
|
typePart.setBody("file");
|
||||||
multipart->append(typePart);
|
multipart->append(typePart);
|
||||||
QHttpPart namePart;
|
QHttpPart namePart;
|
||||||
namePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"name\"");
|
namePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"title\"");
|
||||||
namePart.setBody(m_fileInfo.baseName().toUtf8());
|
namePart.setBody(m_fileInfo.baseName().toUtf8());
|
||||||
multipart->append(namePart);
|
multipart->append(namePart);
|
||||||
|
|
||||||
@ -124,7 +123,7 @@ auto ImgurUpload::Sink::finalize(QNetworkReply&) -> Task::State
|
|||||||
Net::NetRequest::Ptr ImgurUpload::make(ScreenShot::Ptr m_shot)
|
Net::NetRequest::Ptr ImgurUpload::make(ScreenShot::Ptr m_shot)
|
||||||
{
|
{
|
||||||
auto up = makeShared<ImgurUpload>(m_shot->m_file);
|
auto up = makeShared<ImgurUpload>(m_shot->m_file);
|
||||||
up->m_url = std::move(BuildConfig.IMGUR_BASE_URL + "upload.json");
|
up->m_url = std::move(BuildConfig.IMGUR_BASE_URL + "image");
|
||||||
up->m_sink.reset(new Sink(m_shot));
|
up->m_sink.reset(new Sink(m_shot));
|
||||||
return up;
|
return up;
|
||||||
}
|
}
|
||||||
|
@ -868,30 +868,6 @@ void MainWindow::on_actionCopyInstance_triggered()
|
|||||||
runModalTask(task.get());
|
runModalTask(task.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::finalizeInstance(InstancePtr inst)
|
|
||||||
{
|
|
||||||
view->updateGeometries();
|
|
||||||
setSelectedInstanceById(inst->id());
|
|
||||||
if (APPLICATION->accounts()->anyAccountIsValid()) {
|
|
||||||
ProgressDialog loadDialog(this);
|
|
||||||
auto update = inst->createUpdateTask(Net::Mode::Online);
|
|
||||||
connect(update.get(), &Task::failed, [this](QString reason) {
|
|
||||||
QString error = QString("Instance load failed: %1").arg(reason);
|
|
||||||
CustomMessageBox::selectable(this, tr("Error"), error, QMessageBox::Warning)->show();
|
|
||||||
});
|
|
||||||
if (update) {
|
|
||||||
loadDialog.setSkipButton(true, tr("Abort"));
|
|
||||||
loadDialog.execWithTask(update.get());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
CustomMessageBox::selectable(this, tr("Error"),
|
|
||||||
tr("The launcher cannot download Minecraft or update instances unless you have at least "
|
|
||||||
"one account added.\nPlease add a Microsoft account."),
|
|
||||||
QMessageBox::Warning)
|
|
||||||
->show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::addInstance(const QString& url, const QMap<QString, QString>& extra_info)
|
void MainWindow::addInstance(const QString& url, const QMap<QString, QString>& extra_info)
|
||||||
{
|
{
|
||||||
QString groupName;
|
QString groupName;
|
||||||
|
@ -229,7 +229,6 @@ class MainWindow : public QMainWindow {
|
|||||||
|
|
||||||
void runModalTask(Task* task);
|
void runModalTask(Task* task);
|
||||||
void instanceFromInstanceTask(InstanceTask* task);
|
void instanceFromInstanceTask(InstanceTask* task);
|
||||||
void finalizeInstance(InstancePtr inst);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow* ui;
|
Ui::MainWindow* ui;
|
||||||
|
@ -484,7 +484,7 @@ void SkinManageDialog::on_userBtn_clicked()
|
|||||||
if (failReason.isEmpty()) {
|
if (failReason.isEmpty()) {
|
||||||
failReason = tr("the skin is invalid");
|
failReason = tr("the skin is invalid");
|
||||||
}
|
}
|
||||||
CustomMessageBox::selectable(this, tr("Usename not found"),
|
CustomMessageBox::selectable(this, tr("Username not found"),
|
||||||
tr("Unable to find the skin for '%1'\n because: %2.").arg(user, failReason), QMessageBox::Critical)
|
tr("Unable to find the skin for '%1'\n because: %2.").arg(user, failReason), QMessageBox::Critical)
|
||||||
->show();
|
->show();
|
||||||
QFile::remove(path);
|
QFile::remove(path);
|
||||||
@ -497,4 +497,4 @@ void SkinManageDialog::on_userBtn_clicked()
|
|||||||
s.setCapeId(mcProfile.currentCape);
|
s.setCapeId(mcProfile.currentCape);
|
||||||
}
|
}
|
||||||
m_list.updateSkin(&s);
|
m_list.updateSkin(&s);
|
||||||
}
|
}
|
||||||
|
@ -206,6 +206,7 @@ void LauncherPage::applySettings()
|
|||||||
// Updates
|
// Updates
|
||||||
if (APPLICATION->updater()) {
|
if (APPLICATION->updater()) {
|
||||||
APPLICATION->updater()->setAutomaticallyChecksForUpdates(ui->autoUpdateCheckBox->isChecked());
|
APPLICATION->updater()->setAutomaticallyChecksForUpdates(ui->autoUpdateCheckBox->isChecked());
|
||||||
|
APPLICATION->updater()->setUpdateCheckInterval(ui->updateIntervalSpinBox->value() * 3600);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->set("MenuBarInsteadOfToolBar", ui->preferMenuBarCheckBox->isChecked());
|
s->set("MenuBarInsteadOfToolBar", ui->preferMenuBarCheckBox->isChecked());
|
||||||
@ -257,6 +258,7 @@ void LauncherPage::loadSettings()
|
|||||||
// Updates
|
// Updates
|
||||||
if (APPLICATION->updater()) {
|
if (APPLICATION->updater()) {
|
||||||
ui->autoUpdateCheckBox->setChecked(APPLICATION->updater()->getAutomaticallyChecksForUpdates());
|
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)
|
// Toolbar/menu bar settings (not applicable if native menu bar is present)
|
||||||
|
@ -58,6 +58,33 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -10,72 +10,8 @@
|
|||||||
<height>685</height>
|
<height>685</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item row="3" column="0" colspan="2">
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout_4" columnstretch="0,0,0" rowminimumheight="0" columnminimumwidth="0,0,0">
|
|
||||||
<item row="0" column="2">
|
|
||||||
<widget class="QComboBox" name="versionSelectionBox"/>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Version selected:</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QComboBox" name="sortByBox"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0" colspan="2">
|
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QTextBrowser" name="packDescription">
|
|
||||||
<property name="openExternalLinks">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="openLinks">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QTreeView" name="packView">
|
|
||||||
<property name="alternatingRowColors">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="iconSize">
|
|
||||||
<size>
|
|
||||||
<width>96</width>
|
|
||||||
<height>48</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLineEdit" name="searchEdit">
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Search and filter...</string>
|
|
||||||
</property>
|
|
||||||
<property name="clearButtonEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QPushButton" name="pushButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Search</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" colspan="2">
|
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
@ -93,6 +29,63 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="searchEdit">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Search and filter...</string>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeView" name="packView">
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>96</width>
|
||||||
|
<height>48</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextBrowser" name="packDescription">
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="openLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="sortByBox"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Version selected:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="versionSelectionBox"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
|
@ -56,7 +56,6 @@ FlamePage::FlamePage(NewInstanceDialog* dialog, QWidget* parent)
|
|||||||
: QWidget(parent), ui(new Ui::FlamePage), dialog(dialog), m_fetch_progress(this, false)
|
: QWidget(parent), ui(new Ui::FlamePage), dialog(dialog), m_fetch_progress(this, false)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
connect(ui->searchButton, &QPushButton::clicked, this, &FlamePage::triggerSearch);
|
|
||||||
ui->searchEdit->installEventFilter(this);
|
ui->searchEdit->installEventFilter(this);
|
||||||
listModel = new Flame::ListModel(this);
|
listModel = new Flame::ListModel(this);
|
||||||
ui->packView->setModel(listModel);
|
ui->packView->setModel(listModel);
|
||||||
@ -73,7 +72,7 @@ FlamePage::FlamePage(NewInstanceDialog* dialog, QWidget* parent)
|
|||||||
m_fetch_progress.setFixedHeight(24);
|
m_fetch_progress.setFixedHeight(24);
|
||||||
m_fetch_progress.progressFormat("");
|
m_fetch_progress.progressFormat("");
|
||||||
|
|
||||||
ui->gridLayout->addWidget(&m_fetch_progress, 2, 0, 1, ui->gridLayout->columnCount());
|
ui->verticalLayout->insertWidget(2, &m_fetch_progress);
|
||||||
|
|
||||||
// index is used to set the sorting with the curseforge api
|
// index is used to set the sorting with the curseforge api
|
||||||
ui->sortByBox->addItem(tr("Sort by Featured"));
|
ui->sortByBox->addItem(tr("Sort by Featured"));
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
<height>600</height>
|
<height>600</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item row="0" column="0">
|
<item>
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
@ -29,25 +29,14 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<widget class="QLineEdit" name="searchEdit">
|
||||||
<item>
|
<property name="placeholderText">
|
||||||
<widget class="QLineEdit" name="searchEdit">
|
<string>Search and filter...</string>
|
||||||
<property name="placeholderText">
|
</property>
|
||||||
<string>Search and filter...</string>
|
</widget>
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="searchButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Search</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListView" name="packView">
|
<widget class="QListView" name="packView">
|
||||||
@ -77,7 +66,7 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="sortByBox"/>
|
<widget class="QComboBox" name="sortByBox"/>
|
||||||
|
@ -10,8 +10,49 @@
|
|||||||
<height>1011</height>
|
<height>1011</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item row="2" column="1">
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Note: If your FTB instances are not in the default location, select it using the button next to search.</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="searchEdit">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Search and filter...</string>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="browseButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select FTBApp instances directory</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="viewfolder">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="QTreeView" name="modpackList">
|
<widget class="QTreeView" name="modpackList">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
@ -21,7 +62,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="sortByBox">
|
<widget class="QComboBox" name="sortByBox">
|
||||||
@ -48,54 +89,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="searchEdit">
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Search and filter...</string>
|
|
||||||
</property>
|
|
||||||
<property name="clearButtonEnabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Search</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="browseButton">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Select FTBApp instances directory</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset theme="viewfolder">
|
|
||||||
<normaloff>.</normaloff>.</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="flat">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Note: If your FTB instances are not in the default location, select it using the button next to search.</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
<height>602</height>
|
<height>602</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_5">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item row="0" column="0">
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="searchEdit">
|
<widget class="QLineEdit" name="searchEdit">
|
||||||
@ -23,16 +23,9 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="pushButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Search</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item>
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
@ -134,22 +127,9 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout_4">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item row="0" column="1">
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Version selected:</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="2">
|
|
||||||
<widget class="QComboBox" name="versionSelectionBox"/>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QComboBox" name="sortByBox">
|
<widget class="QComboBox" name="sortByBox">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
@ -159,6 +139,19 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Version selected:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="versionSelectionBox"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -59,7 +59,6 @@ ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent)
|
|||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
connect(ui->searchButton, &QPushButton::clicked, this, &ModrinthPage::triggerSearch);
|
|
||||||
ui->searchEdit->installEventFilter(this);
|
ui->searchEdit->installEventFilter(this);
|
||||||
m_model = new Modrinth::ModpackListModel(this);
|
m_model = new Modrinth::ModpackListModel(this);
|
||||||
ui->packView->setModel(m_model);
|
ui->packView->setModel(m_model);
|
||||||
@ -76,7 +75,7 @@ ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent)
|
|||||||
m_fetch_progress.setFixedHeight(24);
|
m_fetch_progress.setFixedHeight(24);
|
||||||
m_fetch_progress.progressFormat("");
|
m_fetch_progress.progressFormat("");
|
||||||
|
|
||||||
ui->gridLayout->addWidget(&m_fetch_progress, 2, 0, 1, ui->gridLayout->columnCount());
|
ui->verticalLayout->insertWidget(1, &m_fetch_progress);
|
||||||
|
|
||||||
ui->sortByBox->addItem(tr("Sort by Relevance"));
|
ui->sortByBox->addItem(tr("Sort by Relevance"));
|
||||||
ui->sortByBox->addItem(tr("Sort by Total Downloads"));
|
ui->sortByBox->addItem(tr("Sort by Total Downloads"));
|
||||||
|
@ -10,8 +10,15 @@
|
|||||||
<height>600</height>
|
<height>600</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item row="2" column="0">
|
<item>
|
||||||
|
<widget class="QLineEdit" name="searchEdit">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Search and filter ...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListView" name="packView">
|
<widget class="QListView" name="packView">
|
||||||
@ -41,7 +48,7 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="sortByBox"/>
|
<widget class="QComboBox" name="sortByBox"/>
|
||||||
@ -61,24 +68,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
|
||||||
<layout class="QHBoxLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="searchEdit">
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Search and filter ...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="searchButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Search</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
@ -89,8 +78,6 @@
|
|||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>searchEdit</tabstop>
|
|
||||||
<tabstop>searchButton</tabstop>
|
|
||||||
<tabstop>packView</tabstop>
|
<tabstop>packView</tabstop>
|
||||||
<tabstop>packDescription</tabstop>
|
<tabstop>packDescription</tabstop>
|
||||||
<tabstop>sortByBox</tabstop>
|
<tabstop>sortByBox</tabstop>
|
||||||
|
@ -58,7 +58,6 @@ TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget* parent)
|
|||||||
: QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog), m_fetch_progress(this, false)
|
: QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog), m_fetch_progress(this, false)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
connect(ui->searchButton, &QPushButton::clicked, this, &TechnicPage::triggerSearch);
|
|
||||||
ui->searchEdit->installEventFilter(this);
|
ui->searchEdit->installEventFilter(this);
|
||||||
model = new Technic::ListModel(this);
|
model = new Technic::ListModel(this);
|
||||||
ui->packView->setModel(model);
|
ui->packView->setModel(model);
|
||||||
@ -72,7 +71,7 @@ TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget* parent)
|
|||||||
m_fetch_progress.setFixedHeight(24);
|
m_fetch_progress.setFixedHeight(24);
|
||||||
m_fetch_progress.progressFormat("");
|
m_fetch_progress.progressFormat("");
|
||||||
|
|
||||||
ui->gridLayout->addWidget(&m_fetch_progress, 2, 0, 1, ui->gridLayout->columnCount());
|
ui->verticalLayout->insertWidget(1, &m_fetch_progress);
|
||||||
|
|
||||||
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TechnicPage::onSelectionChanged);
|
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TechnicPage::onSelectionChanged);
|
||||||
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &TechnicPage::onVersionSelectionChanged);
|
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &TechnicPage::onVersionSelectionChanged);
|
||||||
|
@ -10,23 +10,41 @@
|
|||||||
<height>405</height>
|
<height>405</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item row="4" column="0" colspan="2">
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<widget class="QLineEdit" name="searchEdit">
|
||||||
<item row="0" column="2">
|
<property name="placeholderText">
|
||||||
<widget class="QComboBox" name="versionSelectionBox"/>
|
<string>Search and filter...</string>
|
||||||
</item>
|
</property>
|
||||||
<item row="0" column="1">
|
</widget>
|
||||||
<widget class="QLabel" name="label">
|
</item>
|
||||||
<property name="text">
|
<item>
|
||||||
<string>Version selected:</string>
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QListView" name="packView">
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="iconSize">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<size>
|
||||||
|
<width>48</width>
|
||||||
|
<height>48</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item>
|
||||||
|
<widget class="QTextBrowser" name="packDescription">
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
@ -42,46 +60,21 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
<item>
|
||||||
</item>
|
<widget class="QLabel" name="label">
|
||||||
<item row="3" column="0" colspan="2">
|
<property name="text">
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<string>Version selected:</string>
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QListView" name="packView">
|
|
||||||
<property name="alternatingRowColors">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="iconSize">
|
<property name="alignment">
|
||||||
<size>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
<width>48</width>
|
|
||||||
<height>48</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item>
|
||||||
<widget class="QTextBrowser" name="packDescription">
|
<widget class="QComboBox" name="versionSelectionBox"/>
|
||||||
<property name="openExternalLinks">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLineEdit" name="searchEdit">
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Search and filter...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QPushButton" name="searchButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Search</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@ -257,7 +257,7 @@ void PrismExternalUpdater::setBetaAllowed(bool allowed)
|
|||||||
|
|
||||||
void PrismExternalUpdater::resetAutoCheckTimer()
|
void PrismExternalUpdater::resetAutoCheckTimer()
|
||||||
{
|
{
|
||||||
if (priv->autoCheck) {
|
if (priv->autoCheck && priv->updateInterval > 0) {
|
||||||
int timeoutDuration = 0;
|
int timeoutDuration = 0;
|
||||||
auto now = QDateTime::currentDateTime();
|
auto now = QDateTime::currentDateTime();
|
||||||
if (priv->lastCheck.isValid()) {
|
if (priv->lastCheck.isValid()) {
|
||||||
|
@ -1113,7 +1113,6 @@ void PrismUpdaterApp::backupAppDir()
|
|||||||
"Qt*.dll",
|
"Qt*.dll",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
file_list.append("portable.txt");
|
|
||||||
logUpdate("manifest.txt empty or missing. making best guess at files to back up.");
|
logUpdate("manifest.txt empty or missing. making best guess at files to back up.");
|
||||||
}
|
}
|
||||||
logUpdate(tr("Backing up:\n %1").arg(file_list.join(",\n ")));
|
logUpdate(tr("Backing up:\n %1").arg(file_list.join(",\n ")));
|
||||||
|
Loading…
Reference in New Issue
Block a user