diff --git a/components/Header.vue b/components/Header.vue index e91edf5..75537eb 100644 --- a/components/Header.vue +++ b/components/Header.vue @@ -29,7 +29,6 @@
  1. diff --git a/components/HeaderQueueWidget.vue b/components/HeaderQueueWidget.vue index 105d14e..23c5ad5 100644 --- a/components/HeaderQueueWidget.vue +++ b/components/HeaderQueueWidget.vue @@ -1,17 +1,26 @@ diff --git a/composables/game.ts b/composables/game.ts new file mode 100644 index 0000000..5eba1d9 --- /dev/null +++ b/composables/game.ts @@ -0,0 +1,31 @@ +import { invoke } from "@tauri-apps/api/core"; +import { listen } from "@tauri-apps/api/event"; +import type { Game, GameStatus } from "~/types"; + +const gameRegistry: { [key: string]: Game } = {}; + +const gameStatusRegistry: { [key: string]: Ref } = {}; + +export const useGame = async (id: string) => { + if (!gameRegistry[id]) { + const data: { game: Game; status: GameStatus } = await invoke( + "fetch_game", + { + id, + } + ); + gameRegistry[id] = data.game; + if (!gameStatusRegistry[id]) { + gameStatusRegistry[id] = ref(data.status); + + listen(`update_game/${id}`, (event) => { + const payload: { status: GameStatus } = event.payload as any; + gameStatusRegistry[id].value = payload.status; + }); + } + } + + const game = gameRegistry[id]; + const status = gameStatusRegistry[id]; + return { game, status }; +}; diff --git a/composables/queue.ts b/composables/queue.ts index f684852..0487260 100644 --- a/composables/queue.ts +++ b/composables/queue.ts @@ -1,7 +1,7 @@ import { listen } from "@tauri-apps/api/event"; export type QueueState = { - queue: Array<{ id: string; status: string, progress: number }>; + queue: Array<{ id: string; status: string, progress: number | null }>; }; export const useQueueState = () => diff --git a/package.json b/package.json index 49c2009..c93e9a4 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "dependencies": { "@headlessui/vue": "^1.7.23", "@heroicons/vue": "^2.1.5", - "@prisma/client": "5.20.0", "@tauri-apps/api": ">=2.0.0", "@tauri-apps/plugin-deep-link": "~2", "@tauri-apps/plugin-dialog": "^2.0.1", @@ -22,14 +21,14 @@ "nuxt": "^3.13.0", "scss": "^0.2.4", "vue": "latest", - "vue-router": "latest" + "vue-router": "latest", + "vuedraggable": "^4.1.0" }, "devDependencies": { "@tailwindcss/forms": "^0.5.9", "@tauri-apps/cli": ">=2.0.0", "autoprefixer": "^10.4.20", "postcss": "^8.4.47", - "prisma": "^5.20.0", "sass-embedded": "^1.79.4", "tailwindcss": "^3.4.13" }, diff --git a/pages/library.vue b/pages/library.vue index c91ea64..ac7e24f 100644 --- a/pages/library.vue +++ b/pages/library.vue @@ -40,12 +40,10 @@ diff --git a/plugins/vuedraggable.ts b/plugins/vuedraggable.ts new file mode 100644 index 0000000..58d50a0 --- /dev/null +++ b/plugins/vuedraggable.ts @@ -0,0 +1,5 @@ +import draggable from "vuedraggable"; + +export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.vueApp.component("draggable", draggable); +}); diff --git a/prisma/schema.prisma b/prisma/schema.prisma deleted file mode 100644 index 1ca51a1..0000000 --- a/prisma/schema.prisma +++ /dev/null @@ -1,150 +0,0 @@ -// This should be copied from the main Drop repo -// TODO: do this automatically - -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") -} - -model User { - id String @id @default(uuid()) - username String @unique - admin Boolean @default(false) - - email String - displayName String - profilePicture String // Object - - authMecs LinkedAuthMec[] - clients Client[] -} - -enum AuthMec { - Simple -} - -model LinkedAuthMec { - userId String - mec AuthMec - - credentials Json - - user User @relation(fields: [userId], references: [id]) - - @@id([userId, mec]) -} - -enum ClientCapabilities { - DownloadAggregation -} - -enum Platform { - Windows @map("windows") - Linux @map("linux") -} - -// References a device -model Client { - id String @id @default(uuid()) - userId String - user User @relation(fields: [userId], references: [id]) - - endpoint String - capabilities ClientCapabilities[] - - name String - platform Platform - lastConnected DateTime -} - -enum MetadataSource { - Custom - GiantBomb -} - -model Game { - id String @id @default(uuid()) - - metadataSource MetadataSource - metadataId String - - // Any field prefixed with m is filled in from metadata - // Acts as a cache so we can search and filter it - mName String // Name of game - mShortDescription String // Short description - mDescription String // Supports markdown - mDevelopers Developer[] - mPublishers Publisher[] - - mReviewCount Int - mReviewRating Float - - mIconId String // linked to objects in s3 - mBannerId String // linked to objects in s3 - mCoverId String - mImageLibrary String[] // linked to objects in s3 - - versions GameVersion[] - libraryBasePath String @unique // Base dir for all the game versions - - @@unique([metadataSource, metadataId], name: "metadataKey") -} - -// A particular set of files that relate to the version -model GameVersion { - gameId String - game Game @relation(fields: [gameId], references: [id]) - versionName String // Sub directory for the game files - - platform Platform - launchCommand String // Command to run to start. Platform-specific. Windows games on Linux will wrap this command in Proton/Wine - setupCommand String // Command to setup game (dependencies and such) - dropletManifest Json // Results from droplet - - versionIndex Int - delta Boolean @default(false) - - @@id([gameId, versionName]) -} - -model Developer { - id String @id @default(uuid()) - - metadataSource MetadataSource - metadataId String - metadataOriginalQuery String - - mName String - mShortDescription String - mDescription String - mLogo String - mBanner String - mWebsite String - - games Game[] - - @@unique([metadataSource, metadataId, metadataOriginalQuery], name: "metadataKey") -} - -model Publisher { - id String @id @default(uuid()) - - metadataSource MetadataSource - metadataId String - metadataOriginalQuery String - - mName String - mShortDescription String - mDescription String - mLogo String - mBanner String - mWebsite String - - games Game[] - - @@unique([metadataSource, metadataId, metadataOriginalQuery], name: "metadataKey") -} diff --git a/src-tauri/src/downloads/download_commands.rs b/src-tauri/src/downloads/download_commands.rs index 044a067..d5ef686 100644 --- a/src-tauri/src/downloads/download_commands.rs +++ b/src-tauri/src/downloads/download_commands.rs @@ -19,21 +19,6 @@ pub fn download_game( .map_err(|_| "An error occurred while communicating with the download manager.".to_string()) } -#[tauri::command] -pub fn get_current_game_download_progress( - state: tauri::State<'_, Mutex>, -) -> Result { - match state - .lock() - .unwrap() - .download_manager - .get_current_game_download_progress() - { - Some(progress) => Ok(progress), - None => Err("Game does not exist".to_string()), - } -} - #[tauri::command] pub fn cancel_game_download(state: tauri::State<'_, Mutex>, game_id: String) { info!("Cancelling game download {}", game_id); @@ -54,6 +39,19 @@ pub fn resume_game_downloads(state: tauri::State<'_, Mutex>) { state.lock().unwrap().download_manager.resume_downloads() } +#[tauri::command] +pub fn move_game_in_queue( + state: tauri::State<'_, Mutex>, + old_index: usize, + new_index: usize, +) { + state + .lock() + .unwrap() + .download_manager + .rearrange(old_index, new_index) +} + #[tauri::command] pub fn get_current_write_speed(state: tauri::State<'_, Mutex>) {} diff --git a/src-tauri/src/downloads/download_manager.rs b/src-tauri/src/downloads/download_manager.rs index e70d53d..79c1006 100644 --- a/src-tauri/src/downloads/download_manager.rs +++ b/src-tauri/src/downloads/download_manager.rs @@ -132,19 +132,23 @@ impl DownloadManager { let current_index = get_index_from_id(&mut queue, id).unwrap(); let to_move = queue.remove(current_index).unwrap(); queue.insert(new_index, to_move); + self.command_sender.send(DownloadManagerSignal::Update); } pub fn rearrange(&self, current_index: usize, new_index: usize) { let mut queue = self.edit(); let to_move = queue.remove(current_index).unwrap(); queue.insert(new_index, to_move); + self.command_sender.send(DownloadManagerSignal::Update); } pub fn remove_from_queue(&self, index: usize) { self.edit().remove(index); + self.command_sender.send(DownloadManagerSignal::Update); } pub fn remove_from_queue_string(&self, id: String) { let mut queue = self.edit(); let current_index = get_index_from_id(&mut queue, id).unwrap(); queue.remove(current_index); + self.command_sender.send(DownloadManagerSignal::Update); } pub fn pause_downloads(&self) { self.command_sender diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 0d9a505..8785007 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -134,7 +134,7 @@ pub fn run() { fetch_game_verion_options, // Downloads download_game, - get_current_game_download_progress, + move_game_in_queue, cancel_game_download, pause_game_downloads, resume_game_downloads, diff --git a/src-tauri/src/library.rs b/src-tauri/src/library.rs index 9b38c5d..139b04c 100644 --- a/src-tauri/src/library.rs +++ b/src-tauri/src/library.rs @@ -17,7 +17,7 @@ use crate::remote::RemoteAccessError; use crate::{auth::generate_authorization_header, AppState, DB}; #[derive(serde::Serialize)] -struct FetchGameStruct { +pub struct FetchGameStruct { game: Game, status: DatabaseGameStatus, } @@ -67,7 +67,7 @@ pub struct GameVersionOption { // total_size: usize, } -fn fetch_library_logic(app: AppHandle) -> Result { +fn fetch_library_logic(app: AppHandle) -> Result, RemoteAccessError> { let base_url = DB.fetch_base_url(); let library_url = base_url.join("/api/v1/client/user/library")?; @@ -102,15 +102,18 @@ fn fetch_library_logic(app: AppHandle) -> Result { drop(handle); - Ok(json!(games.clone()).to_string()) + Ok(games) } #[tauri::command] -pub fn fetch_library(app: AppHandle) -> Result { +pub fn fetch_library(app: AppHandle) -> Result, String> { fetch_library_logic(app).map_err(|e| e.to_string()) } -fn fetch_game_logic(id: String, app: tauri::AppHandle) -> Result { +fn fetch_game_logic( + id: String, + app: tauri::AppHandle, +) -> Result { let state = app.state::>(); let mut state_handle = state.lock().unwrap(); @@ -128,7 +131,7 @@ fn fetch_game_logic(id: String, app: tauri::AppHandle) -> Result Result Result { +pub fn fetch_game(id: String, app: tauri::AppHandle) -> Result { let result = fetch_game_logic(id, app); if result.is_err() { diff --git a/types.ts b/types.ts index 3a6e3f4..5702594 100644 --- a/types.ts +++ b/types.ts @@ -1,4 +1,3 @@ -import type { User } from "@prisma/client"; import type { Component } from "vue"; export type NavigationItem = { @@ -12,11 +11,31 @@ export type QuickActionNav = { notifications?: number; action: () => Promise; }; + +export type User = { + id: string; + username: string; + admin: boolean; + displayName: string; + profilePicture: string; +}; + export type AppState = { status: AppStatus; user?: User; }; +export type Game = { + id: string; + mName: string; + mShortDescription: string; + mDescription: string; + mIconId: string; + mBannerId: string; + mCoverId: string; + mImageLibrary: string[]; +}; + export enum AppStatus { NotConfigured = "NotConfigured", SignedOut = "SignedOut", diff --git a/yarn.lock b/yarn.lock index af475d7..a4fa8b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1075,47 +1075,6 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73" integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw== -"@prisma/client@5.20.0": - version "5.20.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.20.0.tgz#4fc9f2b2341c9c997c139df4445688dd6b39663b" - integrity sha512-CLv55ZuMuUawMsxoqxGtLT3bEZoa2W8L3Qnp6rDIFWy+ZBrUcOFKdoeGPSnbBqxc3SkdxJrF+D1veN/WNynZYA== - -"@prisma/debug@5.20.0": - version "5.20.0" - resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.20.0.tgz#c6d1cf6e3c6e9dba150347f13ca200b1d66cc9fc" - integrity sha512-oCx79MJ4HSujokA8S1g0xgZUGybD4SyIOydoHMngFYiwEwYDQ5tBQkK5XoEHuwOYDKUOKRn/J0MEymckc4IgsQ== - -"@prisma/engines-version@5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284": - version "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284.tgz#9a53b13cdcfd706ae54198111000f33c63655c39" - integrity sha512-Lg8AS5lpi0auZe2Mn4gjuCg081UZf88k3cn0RCwHgR+6cyHHpttPZBElJTHf83ZGsRNAmVCZCfUGA57WB4u4JA== - -"@prisma/engines@5.20.0": - version "5.20.0" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.20.0.tgz#86fe407e55219d33d03ebc26dc829a422faed545" - integrity sha512-DtqkP+hcZvPEbj8t8dK5df2b7d3B8GNauKqaddRRqQBBlgkbdhJkxhoJTrOowlS3vaRt2iMCkU0+CSNn0KhqAQ== - dependencies: - "@prisma/debug" "5.20.0" - "@prisma/engines-version" "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284" - "@prisma/fetch-engine" "5.20.0" - "@prisma/get-platform" "5.20.0" - -"@prisma/fetch-engine@5.20.0": - version "5.20.0" - resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.20.0.tgz#b917880fb08f654981f14ca49923031b39683586" - integrity sha512-JVcaPXC940wOGpCOwuqQRTz6I9SaBK0c1BAyC1pcz9xBi+dzFgUu3G/p9GV1FhFs9OKpfSpIhQfUJE9y00zhqw== - dependencies: - "@prisma/debug" "5.20.0" - "@prisma/engines-version" "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284" - "@prisma/get-platform" "5.20.0" - -"@prisma/get-platform@5.20.0": - version "5.20.0" - resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.20.0.tgz#c1a53a8d8af67f2b4a6b97dd4d25b1c603236804" - integrity sha512-8/+CehTZZNzJlvuryRgc77hZCWrUDYd/PmlZ7p2yNXtmf2Una4BWnTbak3us6WVdqoz5wmptk6IhsXdG2v5fmA== - dependencies: - "@prisma/debug" "5.20.0" - "@rollup/plugin-alias@^5.1.0": version "5.1.1" resolved "https://registry.yarnpkg.com/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz#53601d88cda8b1577aa130b4a6e452283605bf26" @@ -2816,7 +2775,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@2.3.3, fsevents@~2.3.2, fsevents@~2.3.3: +fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -4345,15 +4304,6 @@ pretty-bytes@^6.1.1: resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-6.1.1.tgz#38cd6bb46f47afbf667c202cfc754bffd2016a3b" integrity sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ== -prisma@^5.20.0: - version "5.20.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.20.0.tgz#f2ab266a0d59383506886e7acbff0dbf322f4c7e" - integrity sha512-6obb3ucKgAnsGS9x9gLOe8qa51XxvJ3vLQtmyf52CTey1Qcez3A6W6ROH5HIz5Q5bW+0VpmZb8WBohieMFGpig== - dependencies: - "@prisma/engines" "5.20.0" - optionalDependencies: - fsevents "2.3.3" - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -4847,6 +4797,11 @@ smob@^1.0.0: resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab" integrity sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig== +sortablejs@1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.14.0.tgz#6d2e17ccbdb25f464734df621d4f35d4ab35b3d8" + integrity sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w== + source-map-js@^1.0.1, source-map-js@^1.2.0, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" @@ -5553,6 +5508,13 @@ vue@^3.5.5, vue@latest: "@vue/server-renderer" "3.5.11" "@vue/shared" "3.5.11" +vuedraggable@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-4.1.0.tgz#edece68adb8a4d9e06accff9dfc9040e66852270" + integrity sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww== + dependencies: + sortablejs "1.14.0" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"