update changelog
This commit is contained in:
1 parent
56495e9b64
commit
52424a86e3
8 files changed
+244
-7
No files matched your search
@@ -20,8 +20,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CUST_REV 6
|
||||
#define KIP_VERSION 251
|
||||
#define CUST_REV 7
|
||||
#define KIP_VERSION 260
|
||||
|
||||
#include "oc_common.hpp"
|
||||
#include "pcv/pcv_common.hpp"
|
||||
|
||||
@@ -84,3 +84,22 @@ void InfoGui::listUI() {
|
||||
this->listElement->addItem(gap, PARA_GAP);
|
||||
}
|
||||
}
|
||||
|
||||
void addWrappedTextItems(tsl::elm::List *list, const std::vector<std::string> ¶graphs) {
|
||||
const s32 maxWidth = tsl::cfg::FramebufferWidth - MARGIN_L - MARGIN_R;
|
||||
|
||||
for (const auto ¶ : paragraphs) {
|
||||
for (const auto &lineText : wrapText(para, maxWidth)) {
|
||||
auto *d = new FocusableDrawer([lineText](tsl::gfx::Renderer *r, s32 x, s32 y, s32 w, s32 h) {
|
||||
r->drawString((lineText + "\n").c_str(), false, x + MARGIN_L, y + LINE_H - 5, TEXT_SIZE, tsl::style::color::ColorText);
|
||||
});
|
||||
d->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, LINE_H);
|
||||
list->addItem(d, LINE_H);
|
||||
}
|
||||
|
||||
// paragraph gap
|
||||
auto *gap = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *, s32, s32, s32, s32) {});
|
||||
gap->setBoundaries(0, 0, tsl::cfg::FramebufferWidth, PARA_GAP);
|
||||
list->addItem(gap, PARA_GAP);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "base_menu_gui.h"
|
||||
|
||||
void addWrappedTextItems(tsl::elm::List *list, const std::vector<std::string> ¶graphs);
|
||||
|
||||
class InfoGui : public BaseMenuGui {
|
||||
public:
|
||||
InfoGui(std::string title, std::vector<std::string> strings);
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "update_confirm_gui.h"
|
||||
#include "info_gui.h"
|
||||
#include "update_gui.h"
|
||||
|
||||
#include <tesla.hpp>
|
||||
|
||||
UpdateConfirmGui::UpdateConfirmGui(UpdateGui *parent, int packageIndex, std::string packageName,
|
||||
std::string tag, std::vector<std::string> changelog)
|
||||
: m_parent(parent), m_packageIndex(packageIndex), m_packageName(std::move(packageName)),
|
||||
m_tag(std::move(tag)), m_changelog(std::move(changelog)) {
|
||||
}
|
||||
|
||||
void UpdateConfirmGui::listUI() {
|
||||
std::string header = m_packageName;
|
||||
if (!m_tag.empty())
|
||||
header += " " + m_tag;
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader(header));
|
||||
|
||||
addWrappedTextItems(this->listElement, m_changelog);
|
||||
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Confirm"));
|
||||
|
||||
auto *installItem = new tsl::elm::ListItem("Install Update");
|
||||
installItem->setValue("");
|
||||
installItem->setClickListener([this](u64 keys) -> bool {
|
||||
if ((keys & HidNpadButton_A) == HidNpadButton_A) {
|
||||
m_parent->startJob(m_packageIndex, false);
|
||||
tsl::goBack();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this->listElement->addItem(installItem);
|
||||
}
|
||||
|
||||
bool UpdateConfirmGui::handleInput(u64, u64, const HidTouchState &,
|
||||
HidAnalogStickState, HidAnalogStickState) {
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base_menu_gui.h"
|
||||
|
||||
class UpdateGui;
|
||||
|
||||
class UpdateConfirmGui : public BaseMenuGui {
|
||||
public:
|
||||
UpdateConfirmGui(UpdateGui *parent, int packageIndex, std::string packageName,
|
||||
std::string tag, std::vector<std::string> changelog);
|
||||
~UpdateConfirmGui() = default;
|
||||
|
||||
void listUI() override;
|
||||
bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos,
|
||||
HidAnalogStickState leftJoy, HidAnalogStickState rightJoy) override;
|
||||
|
||||
private:
|
||||
UpdateGui *m_parent;
|
||||
int m_packageIndex;
|
||||
std::string m_packageName;
|
||||
std::string m_tag;
|
||||
std::vector<std::string> m_changelog;
|
||||
};
|
||||
@@ -17,12 +17,14 @@
|
||||
#include "update_gui.h"
|
||||
#include "ult_ext.h"
|
||||
#include "base_menu_gui.h"
|
||||
#include "update_confirm_gui.h"
|
||||
#include "../format.h"
|
||||
#include "../style.h"
|
||||
|
||||
#include <tesla.hpp>
|
||||
#include <ultra.hpp>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -131,6 +133,29 @@ void UpdateGui::startJob(int packageIndex, bool extractOnly) {
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateGui::startChangelogFetch(int packageIndex) {
|
||||
if (isBusy()) return;
|
||||
|
||||
m_activePackage = packageIndex;
|
||||
m_resultMessage.clear();
|
||||
m_changelogTag.clear();
|
||||
m_changelogLines.clear();
|
||||
|
||||
ult::abortDownload.store(false, std::memory_order_release);
|
||||
|
||||
m_stage.store(UpdateStage::FetchingChangelog, std::memory_order_release);
|
||||
|
||||
if (R_SUCCEEDED(threadCreate(&m_thread, fetchChangelogEntry, this,
|
||||
nullptr, 0x8000, 0x20, -2))) {
|
||||
m_threadActive = true;
|
||||
threadStart(&m_thread);
|
||||
} else {
|
||||
m_resultMessage = "Failed to create thread";
|
||||
m_stage.store(UpdateStage::Failed, std::memory_order_release);
|
||||
m_threadActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateGui::requestCancel() {
|
||||
ult::abortDownload.store(true, std::memory_order_release);
|
||||
ult::abortUnzip.store(true, std::memory_order_release);
|
||||
@@ -186,6 +211,55 @@ void UpdateGui::jobBody() {
|
||||
m_stage.store(UpdateStage::Done, std::memory_order_release);
|
||||
}
|
||||
|
||||
/* static */ void UpdateGui::fetchChangelogEntry(void *arg) {
|
||||
static_cast<UpdateGui *>(arg)->fetchChangelogBody();
|
||||
}
|
||||
|
||||
void UpdateGui::fetchChangelogBody() {
|
||||
ult::createDirectory("sdmc:/config/horizon-oc/");
|
||||
|
||||
bool ok = ult::downloadFile(kReleaseApiUrl, kReleaseInfoPath, false, false);
|
||||
if (!ok || ult::abortDownload.load(std::memory_order_acquire)) {
|
||||
m_resultMessage = ult::abortDownload.load(std::memory_order_acquire)
|
||||
? "Changelog fetch cancelled"
|
||||
: "Could not fetch changelog -- check network";
|
||||
m_stage.store(
|
||||
ult::abortDownload.load() ? UpdateStage::Cancelled : UpdateStage::Failed,
|
||||
std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<ult::json_t, ult::JsonDeleter> root(ult::readJsonFromFile(kReleaseInfoPath));
|
||||
std::remove(kReleaseInfoPath);
|
||||
|
||||
if (!root) {
|
||||
m_resultMessage = "Could not parse changelog";
|
||||
m_stage.store(UpdateStage::Failed, std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
|
||||
m_changelogTag = ult::getStringFromJson(root.get(), "tag_name");
|
||||
const std::string body = ult::getStringFromJson(root.get(), "body");
|
||||
|
||||
m_changelogLines.clear();
|
||||
size_t pos = 0;
|
||||
while (pos <= body.size()) {
|
||||
size_t nl = body.find('\n', pos);
|
||||
std::string line = (nl == std::string::npos) ? body.substr(pos) : body.substr(pos, nl - pos);
|
||||
if (!line.empty() && line.back() == '\r')
|
||||
line.pop_back();
|
||||
if (!line.empty())
|
||||
m_changelogLines.push_back(line);
|
||||
if (nl == std::string::npos)
|
||||
break;
|
||||
pos = nl + 1;
|
||||
}
|
||||
if (m_changelogLines.empty())
|
||||
m_changelogLines.push_back("No changelog available for this release.");
|
||||
|
||||
m_stage.store(UpdateStage::ChangelogReady, std::memory_order_release);
|
||||
}
|
||||
|
||||
|
||||
void UpdateGui::listUI() {
|
||||
BaseMenuGui::refresh();
|
||||
@@ -201,7 +275,12 @@ void UpdateGui::listUI() {
|
||||
item->setClickListener([this, idx](u64 keys) -> bool {
|
||||
if (isBusy()) return false;
|
||||
if (keys & HidNpadButton_A) {
|
||||
startJob(idx, false);
|
||||
if (ult::limitedMemory) {
|
||||
m_status->setState(4, 100, kPackages[idx].displayName,
|
||||
"Updates cannot be performed on a 4MB overlay heap");
|
||||
return true;
|
||||
}
|
||||
startChangelogFetch(idx);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -242,6 +321,24 @@ void UpdateGui::pollJob() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stage == UpdateStage::FetchingChangelog) {
|
||||
m_status->setState(6, 0, pkgName, "Fetching changelog...");
|
||||
if (m_items[m_activePackage])
|
||||
m_items[m_activePackage]->setValue("...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (stage == UpdateStage::ChangelogReady) {
|
||||
reapThread();
|
||||
m_stage.store(UpdateStage::Idle, std::memory_order_release);
|
||||
m_status->setState(0, 0, "", "");
|
||||
if (m_items[m_activePackage])
|
||||
m_items[m_activePackage]->setValue("");
|
||||
|
||||
m_pendingChangelogConfirm = true;
|
||||
return;
|
||||
}
|
||||
|
||||
int panelStage = (stage == UpdateStage::Done) ? 3
|
||||
: (stage == UpdateStage::Failed) ? 4 : 5;
|
||||
|
||||
@@ -263,6 +360,13 @@ bool UpdateGui::handleInput(u64 keysDown, u64 keysHeld,
|
||||
const HidTouchState &touchPos,
|
||||
HidAnalogStickState leftJoy,
|
||||
HidAnalogStickState rightJoy) {
|
||||
if (m_pendingChangelogConfirm) {
|
||||
m_pendingChangelogConfirm = false;
|
||||
tsl::changeTo<UpdateConfirmGui>(this, m_activePackage, kPackages[m_activePackage].displayName,
|
||||
m_changelogTag, m_changelogLines);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((keysDown & HidNpadButton_R) && isBusy()) {
|
||||
requestCancel();
|
||||
return true;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base_menu_gui.h"
|
||||
|
||||
@@ -35,6 +36,8 @@ public:
|
||||
bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos,
|
||||
HidAnalogStickState leftJoy, HidAnalogStickState rightJoy) override;
|
||||
|
||||
void startJob(int packageIndex, bool extractOnly);
|
||||
|
||||
private:
|
||||
enum class UpdateStage {
|
||||
Idle,
|
||||
@@ -43,6 +46,8 @@ private:
|
||||
Done,
|
||||
Failed,
|
||||
Cancelled,
|
||||
FetchingChangelog,
|
||||
ChangelogReady,
|
||||
};
|
||||
|
||||
struct PackageInfo {
|
||||
@@ -56,11 +61,14 @@ private:
|
||||
{"Horizon OC + Extensions", "https://github.com/Horizon-OC/Horizon-OC/releases/latest/download/dist_ext.zip", "sdmc:/config/horizon-oc/dist_ext.zip"},
|
||||
};
|
||||
|
||||
static constexpr const char *kReleaseApiUrl = "https://api.github.com/repos/Horizon-OC/Horizon-OC/releases/latest";
|
||||
static constexpr const char *kReleaseInfoPath = "sdmc:/config/horizon-oc/release_info.json";
|
||||
|
||||
bool isBusy() const {
|
||||
return m_stage.load(std::memory_order_acquire) != UpdateStage::Idle;
|
||||
}
|
||||
|
||||
void startJob(int packageIndex, bool extractOnly);
|
||||
void startChangelogFetch(int packageIndex);
|
||||
void requestCancel();
|
||||
void reapThread();
|
||||
void pollJob();
|
||||
@@ -68,6 +76,9 @@ private:
|
||||
static void jobEntry(void *arg);
|
||||
void jobBody();
|
||||
|
||||
static void fetchChangelogEntry(void *arg);
|
||||
void fetchChangelogBody();
|
||||
|
||||
std::atomic<UpdateStage> m_stage{UpdateStage::Idle};
|
||||
int m_activePackage = -1;
|
||||
bool m_extractOnly = false;
|
||||
@@ -75,6 +86,11 @@ private:
|
||||
Thread m_thread{};
|
||||
std::string m_resultMessage;
|
||||
|
||||
std::string m_changelogTag;
|
||||
std::vector<std::string> m_changelogLines;
|
||||
|
||||
bool m_pendingChangelogConfirm = false;
|
||||
|
||||
tsl::elm::ListItem *m_items[2] = {nullptr, nullptr};
|
||||
UpdateStatusPanel *m_status = nullptr;
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@ INCLUDES := ../common/include src/hos src/soc src/i2c src/util src/pwr src/ipc
|
||||
EXEFS_SRC := exefs_src
|
||||
LIBNAMES := minIni
|
||||
# major minor patch
|
||||
TARGET_VERSION := 2.5.1
|
||||
KIP_VERSION := 251
|
||||
CUST_REV := 6
|
||||
TARGET_VERSION := 2.6.0
|
||||
KIP_VERSION := 260
|
||||
CUST_REV := 7
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
|
||||
Reference in new issue
Block a user