mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-10-19 04:55:19 +00:00
feat: show loading progress in modman
This commit is contained in:
@@ -5,5 +5,8 @@
|
||||
class ProgressCallback
|
||||
{
|
||||
public:
|
||||
ProgressCallback() = default;
|
||||
virtual ~ProgressCallback() = default;
|
||||
|
||||
virtual void OnProgress(size_t current, size_t total) = 0;
|
||||
};
|
||||
|
@@ -4,6 +4,40 @@
|
||||
#include "Web/UiCommunication.h"
|
||||
#include "ZoneLoading.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr double MIN_PROGRESS_TO_REPORT = 0.005;
|
||||
|
||||
class EventProgressReporter : public ProgressCallback
|
||||
{
|
||||
public:
|
||||
explicit EventProgressReporter(std::string zoneName)
|
||||
: m_zone_name(std::move(zoneName)),
|
||||
m_last_progress(0)
|
||||
{
|
||||
}
|
||||
|
||||
void OnProgress(const size_t current, const size_t total) override
|
||||
{
|
||||
const double percentage = static_cast<double>(current) / static_cast<double>(total);
|
||||
|
||||
if (percentage - m_last_progress >= MIN_PROGRESS_TO_REPORT)
|
||||
{
|
||||
m_last_progress = percentage;
|
||||
ui::NotifyZoneLoadProgress(m_zone_name, percentage);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_zone_name;
|
||||
double m_last_progress;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void FastFileContext::Destroy()
|
||||
{
|
||||
// Unload all zones
|
||||
@@ -12,7 +46,7 @@ void FastFileContext::Destroy()
|
||||
|
||||
result::Expected<Zone*, std::string> FastFileContext::LoadFastFile(const std::string& path)
|
||||
{
|
||||
auto zone = ZoneLoading::LoadZone(path, std::nullopt);
|
||||
auto zone = ZoneLoading::LoadZone(path, std::make_unique<EventProgressReporter>(fs::path(path).filename().replace_extension().string()));
|
||||
if (!zone)
|
||||
return result::Unexpected(std::move(zone.error()));
|
||||
|
||||
|
@@ -7,6 +7,15 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
class ZoneLoadProgressDto
|
||||
{
|
||||
public:
|
||||
std::string zoneName;
|
||||
double percentage;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(ZoneLoadProgressDto, zoneName, percentage);
|
||||
|
||||
class ZoneLoadedDto
|
||||
{
|
||||
public:
|
||||
@@ -71,6 +80,15 @@ namespace
|
||||
|
||||
namespace ui
|
||||
{
|
||||
void NotifyZoneLoadProgress(std::string zoneName, const double percentage)
|
||||
{
|
||||
const ZoneLoadProgressDto dto{
|
||||
.zoneName = std::move(zoneName),
|
||||
.percentage = percentage,
|
||||
};
|
||||
Notify(*ModManContext::Get().m_main_webview, "zoneLoadProgress", dto);
|
||||
}
|
||||
|
||||
void NotifyZoneLoaded(std::string zoneName, std::string fastFilePath)
|
||||
{
|
||||
const ZoneLoadedDto dto{
|
||||
|
@@ -4,6 +4,7 @@
|
||||
|
||||
namespace ui
|
||||
{
|
||||
void NotifyZoneLoadProgress(std::string zoneName, double percentage);
|
||||
void NotifyZoneLoaded(std::string zoneName, std::string fastFilePath);
|
||||
void NotifyZoneUnloaded(std::string zoneName);
|
||||
|
||||
|
@@ -1,14 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import { webviewBinds } from "@/native";
|
||||
import { webviewAddEventListener, webviewBinds } from "@/native";
|
||||
import { useZoneStore } from "@/stores/ZoneStore";
|
||||
import SpinningLoader from "@/components/SpinningLoader.vue";
|
||||
|
||||
const zoneStore = useZoneStore();
|
||||
const loadingFastFile = ref(false);
|
||||
const unlinkingFastFile = ref(false);
|
||||
const lastPercentage = ref<number>(0);
|
||||
|
||||
const performingAction = computed<boolean>(() => loadingFastFile.value || unlinkingFastFile.value);
|
||||
const progressBarWidth = computed<string>(() => `${lastPercentage.value * 100}%`);
|
||||
|
||||
async function openFastFileSelect() {
|
||||
return await webviewBinds.openFileDialog({ filters: [{ name: "Fastfiles", filter: "*.ff" }] });
|
||||
@@ -21,6 +23,7 @@ async function onOpenFastFileClick() {
|
||||
if (!fastFilePath) return;
|
||||
|
||||
loadingFastFile.value = true;
|
||||
lastPercentage.value = 0;
|
||||
|
||||
webviewBinds
|
||||
.loadFastFile(fastFilePath)
|
||||
@@ -29,6 +32,7 @@ async function onOpenFastFileClick() {
|
||||
})
|
||||
.finally(() => {
|
||||
loadingFastFile.value = false;
|
||||
lastPercentage.value = 1;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,6 +47,7 @@ async function onUnlinkFastFileClick() {
|
||||
|
||||
let loadedZoneName: string;
|
||||
try {
|
||||
lastPercentage.value = 0;
|
||||
loadedZoneName = (await webviewBinds.loadFastFile(fastFilePath)).zoneName;
|
||||
} catch (e: unknown) {
|
||||
console.error("Failed to load fastfile:", e as string);
|
||||
@@ -50,6 +55,7 @@ async function onUnlinkFastFileClick() {
|
||||
}
|
||||
|
||||
try {
|
||||
lastPercentage.value = 0;
|
||||
await webviewBinds.unlinkZone(loadedZoneName);
|
||||
} catch (e: unknown) {
|
||||
console.error("Failed to unlink fastfile:", e as string);
|
||||
@@ -59,6 +65,7 @@ async function onUnlinkFastFileClick() {
|
||||
}
|
||||
} finally {
|
||||
unlinkingFastFile.value = false;
|
||||
lastPercentage.value = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +74,11 @@ function onUnloadClicked(zoneName: string) {
|
||||
console.error("Failed to unload zone:", e);
|
||||
});
|
||||
}
|
||||
|
||||
webviewAddEventListener("zoneLoadProgress", (dto) => {
|
||||
console.log(dto);
|
||||
lastPercentage.value = dto.percentage;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -94,10 +106,18 @@ function onUnloadClicked(zoneName: string) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="progressbar-wrapper">
|
||||
<div
|
||||
class="progressbar"
|
||||
:class="{ visible: performingAction }"
|
||||
:style="{ width: progressBarWidth }"
|
||||
></div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -117,4 +137,24 @@ function onUnloadClicked(zoneName: string) {
|
||||
.zone > button {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.progressbar-wrapper {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 0.35rem 0.4rem;
|
||||
}
|
||||
|
||||
.progressbar {
|
||||
opacity: 0;
|
||||
height: 0.4rem;
|
||||
border-radius: 2.5rem;
|
||||
background-color: #b9772c;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
|
||||
&.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -14,13 +14,24 @@
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0;
|
||||
padding-top: 10vh;
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
justify-content: start;
|
||||
text-align: center;
|
||||
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
@@ -1,3 +1,8 @@
|
||||
export interface ZoneLoadProgressDto {
|
||||
zoneName: string;
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
export interface ZoneLoadedDto {
|
||||
zoneName: string;
|
||||
filePath: string;
|
||||
@@ -13,6 +18,7 @@ export interface ZoneBinds {
|
||||
}
|
||||
|
||||
export interface ZoneEventMap {
|
||||
zoneLoadProgress: ZoneLoadProgressDto;
|
||||
zoneLoaded: ZoneLoadedDto;
|
||||
zoneUnloaded: ZoneUnloadedDto;
|
||||
}
|
||||
|
@@ -60,8 +60,6 @@ namespace
|
||||
m_block_shift(pointerBitCount - blockBitCount),
|
||||
m_offset_mask(std::numeric_limits<uintptr_t>::max() >> (sizeof(uintptr_t) * 8 - (pointerBitCount - blockBitCount))),
|
||||
m_last_fill_size(0),
|
||||
m_has_progress_callback(progressCallback.has_value()),
|
||||
m_progress_callback(std::move(progressCallback).value_or(nullptr)),
|
||||
m_progress_current_size(0uz),
|
||||
m_progress_total_size(0uz)
|
||||
{
|
||||
@@ -74,7 +72,12 @@ namespace
|
||||
|
||||
m_insert_block = blocks[insertBlock];
|
||||
|
||||
m_progress_total_size = CalculateTotalSize();
|
||||
if (progressCallback)
|
||||
{
|
||||
m_has_progress_callback = true;
|
||||
m_progress_callback = *std::move(progressCallback);
|
||||
m_progress_total_size = CalculateTotalSize();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] unsigned GetPointerBitCount() const override
|
||||
@@ -452,7 +455,8 @@ namespace
|
||||
{
|
||||
m_block_offsets[block.m_index] += size;
|
||||
|
||||
if (m_has_progress_callback)
|
||||
// We cannot know the full size of the temp block
|
||||
if (m_has_progress_callback && block.m_type != XBlockType::BLOCK_TYPE_TEMP)
|
||||
{
|
||||
m_progress_current_size += size;
|
||||
m_progress_callback->OnProgress(m_progress_current_size, m_progress_total_size);
|
||||
@@ -473,7 +477,11 @@ namespace
|
||||
size_t result = 0uz;
|
||||
|
||||
for (const auto& block : m_blocks)
|
||||
result += block->m_buffer_size;
|
||||
{
|
||||
// We cannot know the full size of the temp block
|
||||
if (block->m_type != XBlockType::BLOCK_TYPE_TEMP)
|
||||
result += block->m_buffer_size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@@ -28,10 +28,11 @@ result::Expected<std::unique_ptr<Zone>, std::string> ZoneLoading::LoadZone(const
|
||||
for (auto game = 0u; game < static_cast<unsigned>(GameId::COUNT); game++)
|
||||
{
|
||||
const auto* factory = IZoneLoaderFactory::GetZoneLoaderFactoryForGame(static_cast<GameId>(game));
|
||||
zoneLoader = factory->CreateLoaderForHeader(header, zoneName, std::move(progressCallback));
|
||||
|
||||
if (zoneLoader)
|
||||
if (factory->InspectZoneHeader(header))
|
||||
{
|
||||
zoneLoader = factory->CreateLoaderForHeader(header, zoneName, std::move(progressCallback));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zoneLoader)
|
||||
|
Reference in New Issue
Block a user