-
-
-
+
+
+
+
+
Install {{ game.mName }}?
+
+
+
+ Drop will add {{ game.mName }} to the queue to be downloaded.
+ While downloading, Drop may use up a large amount of resources,
+ particularly network bandwidth and CPU utilisation.
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+ {{ installError }}
+
+
+
+
+
+
+ install()"
+ :disabled="
+ !(versionOptions && versionOptions.length > 0 && !installDir)
+ "
+ :loading="installLoading"
+ type="submit"
+ class="w-full sm:w-fit"
+ >
+ Install
+
+
+
+
diff --git a/pages/queue.vue b/pages/queue.vue
index 6572203..52574dd 100644
--- a/pages/queue.vue
+++ b/pages/queue.vue
@@ -1,18 +1,23 @@
-
+
+
+
+ {{ formatKilobytes(stats.speed) }}
+ {{ formatTime(stats.time) }} left
+
+
+
+
-
+
-
![]()
+
@@ -30,31 +35,20 @@
{{ element.status }}
-
Loading...
-
@@ -65,19 +59,64 @@ import { XMarkIcon } from "@heroicons/vue/20/solid";
import { invoke } from "@tauri-apps/api/core";
import type { Game, GameStatus } from "~/types";
-const queue = useQueueState();
+const windowWidth = ref(window.innerWidth);
+window.addEventListener('resize', (event) => {
+ windowWidth.value = window.innerWidth;
+})
-const current = computed(() => queue.value.queue.at(0));
-const rest = computed(() => queue.value.queue.slice(1));
+const queue = useQueueState();
+const stats = useStatsState();
+const speedHistory = useState
>(() => []);
+const speedHistoryMax = computed(() => windowWidth.value / 8);
+const speedMax = computed(() => speedHistory.value.reduce((a, b) => a > b ? a : b) * 1.3);
+const previousGameId = ref();
const games: Ref<{
[key: string]: { game: Game; status: Ref; cover: string };
}> = ref({});
+
+function resetHistoryGraph() {
+ speedHistory.value = [];
+ stats.value = { time: 0, speed: 0 };
+}
+function checkReset(v: QueueState) {
+ const currentGame = v.queue.at(0);
+ // If we're finished
+ if (!currentGame && previousGameId.value) {
+ previousGameId.value = undefined;
+ resetHistoryGraph();
+ return;
+ }
+ // If we don't have a game
+ if (!currentGame) return;
+ // If we started a new download
+ if (currentGame && !previousGameId.value) {
+ previousGameId.value = currentGame.id;
+ resetHistoryGraph();
+ return;
+ }
+ // If it's a different game now
+ if (currentGame.id != previousGameId.value
+ ) {
+ previousGameId.value = currentGame.id;
+ resetHistoryGraph();
+ return;
+ }
+}
watch(queue, (v) => {
loadGamesForQueue(v);
+ checkReset(v);
});
+watch(stats, (v) => {
+ const newLength = speedHistory.value.push(v.speed);
+ if (newLength > speedHistoryMax.value) {
+ speedHistory.value.splice(0, 1);
+ }
+ checkReset(queue.value);
+})
+
function loadGamesForQueue(v: typeof queue.value) {
for (const { id } of v.queue) {
if (games.value[id]) return;
@@ -101,4 +140,32 @@ async function onEnd(event: { oldIndex: number; newIndex: number }) {
async function cancelGame(id: string) {
await invoke("cancel_game", { gameId: id });
}
+
+function formatKilobytes(bytes: number): string {
+ const units = ["KB", "MB", "GB", "TB", "PB"];
+ let value = bytes;
+ let unitIndex = 0;
+ const scalar = 1000;
+
+ while (value >= scalar && unitIndex < units.length - 1) {
+ value /= scalar;
+ unitIndex++;
+ }
+
+ return `${value.toFixed(1)} ${units[unitIndex]}/s`;
+}
+
+function formatTime(seconds: number): string {
+ if (seconds < 60) {
+ return `${Math.round(seconds)}s`;
+ }
+
+ const minutes = Math.floor(seconds / 60);
+ if (minutes < 60) {
+ return `${minutes}m ${Math.round(seconds % 60)}s`
+ }
+
+ const hours = Math.floor(minutes / 60);
+ return `${hours}h ${minutes % 60}m`;
+}
diff --git a/pages/settings.vue b/pages/settings.vue
index 1e92a0f..1363f89 100644
--- a/pages/settings.vue
+++ b/pages/settings.vue
@@ -9,25 +9,18 @@