From 613c9032a994d6618f43c5f28df1460c2bd63cf3 Mon Sep 17 00:00:00 2001 From: Tine Jozelj Date: Thu, 21 Dec 2023 23:25:08 +0100 Subject: [PATCH] feat: settings refactor and initial mod listing --- data/dev.mnts.ModManager.gschema.xml.in | 4 +- data/resources/meson.build | 1 - data/resources/resources.gresource.xml | 3 +- data/resources/ui/components/mods_list.blp | 135 --------- .../ui/windows/main/pages/games_and_mods.blp | 25 +- .../ui/windows/main/pages/welcome.blp | 26 +- src/api/base.rs | 9 + src/api/games.rs | 20 +- src/api/mod.rs | 3 + src/api/mods.rs | 275 ++++++++++++++++++ src/application.rs | 6 - src/components/mod.rs | 2 - src/components/mods_list.rs | 64 ---- src/main.rs | 1 - src/settings.rs | 106 ++++++- src/windows/add_new_game/add_new_game.rs | 20 +- src/windows/main/main.rs | 11 +- src/windows/main/pages/games_and_mods.rs | 44 ++- 18 files changed, 490 insertions(+), 265 deletions(-) delete mode 100644 data/resources/ui/components/mods_list.blp create mode 100644 src/api/mods.rs delete mode 100644 src/components/mod.rs delete mode 100644 src/components/mods_list.rs diff --git a/data/dev.mnts.ModManager.gschema.xml.in b/data/dev.mnts.ModManager.gschema.xml.in index cb3182f..18d0220 100644 --- a/data/dev.mnts.ModManager.gschema.xml.in +++ b/data/dev.mnts.ModManager.gschema.xml.in @@ -13,9 +13,9 @@ false Window maximized state - + [] - Games + List of games. (Slug, Path) \ No newline at end of file diff --git a/data/resources/meson.build b/data/resources/meson.build index 7cef381..436dec4 100644 --- a/data/resources/meson.build +++ b/data/resources/meson.build @@ -5,7 +5,6 @@ blueprints = custom_target('blueprints', 'ui/windows/main/pages/welcome.blp', 'ui/windows/main/pages/games_and_mods.blp', 'ui/windows/add_new_game/add_new_game.blp', - 'ui/components/mods_list.blp', ), output: '.', command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'], diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml index 14b3811..ddb11bc 100644 --- a/data/resources/resources.gresource.xml +++ b/data/resources/resources.gresource.xml @@ -6,7 +6,6 @@ ui/windows/main/pages/welcome.ui ui/windows/main/pages/games_and_mods.ui ui/windows/add_new_game/add_new_game.ui - ui/components/mods_list.ui style.css - + \ No newline at end of file diff --git a/data/resources/ui/components/mods_list.blp b/data/resources/ui/components/mods_list.blp deleted file mode 100644 index 01a2988..0000000 --- a/data/resources/ui/components/mods_list.blp +++ /dev/null @@ -1,135 +0,0 @@ -using Gtk 4.0; -using Adw 1; - -template $ModsList : Adw.NavigationPage { - title: _("Main"); - - Adw.ToolbarView { - [top] - Adw.HeaderBar header_bar { - show-back-button: true; - } - - content: Box { - orientation: vertical; - valign: center; - halign: center; - - Image { - name: "logo"; - icon-name: "re.sonny.Workbench"; - pixel-size: 196; - margin-bottom: 30; - - styles [ - "icon-dropshadow" - ] - } - - Label { - label: _("Welcome to Mod Manager"); - margin-bottom: 30; - - styles [ - "title-1" - ] - } - - Box subtitle { - orientation: vertical; - halign: center; - margin-bottom: 30; - - Label { - label: "Learn and prototype with\nGNOME technologies"; - justify: center; - } - } - - Box { - orientation: vertical; - homogeneous: true; - halign: center; - - Box { - margin-bottom: 6; - - Image { - icon-name: "update-symbolic"; - margin-end: 12; - icon-size: normal; - } - - Label { - label: _("Edit Style or UI to update the Preview"); - } - } - - Box { - margin-bottom: 6; - - Image { - icon-name: "media-playback-start-symbolic"; - margin-end: 12; - icon-size: normal; - } - - Label { - label: _("Hit"); - } - - ShortcutsShortcut { - accelerator: "Return"; - margin-start: 12; - } - - Label { - label: _("to format and run Code"); - } - } - - Box { - margin-bottom: 6; - - Image { - icon-name: "media-floppy-symbolic"; - margin-end: 12; - icon-size: normal; - } - - Label { - label: _("Changes are automatically saved and restored"); - } - } - - Box { - margin-bottom: 6; - - Image { - icon-name: "library-symbolic"; - margin-end: 12; - icon-size: normal; - } - - Label { - label: _("Browse the Library for demos and examples"); - } - } - - Box { - margin-bottom: 6; - - Image { - icon-name: "user-bookmarks-symbolic"; - margin-end: 12; - icon-size: normal; - } - - Label { - label: _("Checkout the Bookmarks menu to learn and get help"); - } - } - } -}; -} -} \ No newline at end of file diff --git a/data/resources/ui/windows/main/pages/games_and_mods.blp b/data/resources/ui/windows/main/pages/games_and_mods.blp index 346eb9b..06924d6 100644 --- a/data/resources/ui/windows/main/pages/games_and_mods.blp +++ b/data/resources/ui/windows/main/pages/games_and_mods.blp @@ -12,7 +12,11 @@ template $GamesAndMods: Adw.Bin { Adw.HeaderBar { [end] Button add_new_game { - label: "Add game"; + icon-name: "list-add-symbolic"; + } + + Button remove_all_games { + icon-name: "list-remove-symbolic"; } } @@ -33,13 +37,24 @@ template $GamesAndMods: Adw.Bin { } } - content: Box { - Label { + content: Adw.Clamp { + orientation: vertical; + + Label title { label: "Mods"; + styles ["title-1"] } - Button remove_all_games { - label: "Remove all games"; + + Adw.Carousel { } + Adw.CarouselIndicatorDots {} + + ScrolledWindow { + vexpand: true; + ListBox mods_list { + } + } + }; } }; diff --git a/data/resources/ui/windows/main/pages/welcome.blp b/data/resources/ui/windows/main/pages/welcome.blp index 77e9305..fce90fa 100644 --- a/data/resources/ui/windows/main/pages/welcome.blp +++ b/data/resources/ui/windows/main/pages/welcome.blp @@ -7,21 +7,17 @@ template $Welcome: Adw.Bin { Adw.HeaderBar { } - content: Box { - orientation: vertical; - halign: center; - valign: center; - - Label { - label: "No games added yet!"; - justify: center; - wrap: true; - styles ["title-1"] - margin-bottom: 30; - } - Button add_new_game { - label: "Add new game"; - styles ["suggested-action", "pill"] + content: Adw.Clamp { + Adw.StatusPage { + title: "No games added yet."; + description: "Click the button below to add a new game."; + + icon-name: "start-here-symbolic"; + + Button add_new_game { + label: "Add new game"; + styles ["suggested-action", "pill"] + } } }; } diff --git a/src/api/base.rs b/src/api/base.rs index 31894a3..246953b 100644 --- a/src/api/base.rs +++ b/src/api/base.rs @@ -1,5 +1,14 @@ +use crate::settings::Game; + pub const API_URL: &str = "https://api.curseforge.com"; +pub fn get_game_id(game: Game) -> i32 { + match game { + Game::TheSims4(_) => 78062, + _ => panic!("Game not supported"), + } +} + pub fn get_curse_forge_client() -> Result { let mut api_key_header = reqwest::header::HeaderValue::from_str(crate::config::API_KEY).unwrap(); diff --git a/src/api/games.rs b/src/api/games.rs index e614a93..73856b5 100644 --- a/src/api/games.rs +++ b/src/api/games.rs @@ -3,11 +3,16 @@ use serde::Deserialize; use crate::api::*; #[derive(Deserialize, Debug)] -struct Response { +struct GetGamesResponse { data: Vec, pagination: Pagination, } +#[derive(Deserialize, Debug)] +struct GetGameResponse { + data: Game, +} + #[derive(Deserialize, Debug)] struct Game { id: u32, @@ -40,7 +45,18 @@ pub fn get_games() -> Vec { .get(&format!("{}/v1/games", base::API_URL)) .send() .unwrap(); - let json: Response = response.json().unwrap(); + let json: GetGamesResponse = response.json().unwrap(); return json.data.iter().map(|game| game.name.clone()).collect(); } + +pub fn get_game(id: &i32) -> Game { + let client = base::get_curse_forge_client().unwrap(); + let response = client + .get(&format!("{}/v1/games/{}", base::API_URL, id)) + .send() + .unwrap(); + let json: GetGameResponse = response.json().unwrap(); + + return json.data; +} diff --git a/src/api/mod.rs b/src/api/mod.rs index 22936d9..049ea3c 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -3,3 +3,6 @@ pub use base::*; pub mod games; pub use games::*; + +pub mod mods; +pub use mods::*; diff --git a/src/api/mods.rs b/src/api/mods.rs new file mode 100644 index 0000000..3b81e08 --- /dev/null +++ b/src/api/mods.rs @@ -0,0 +1,275 @@ +use serde::Deserialize; + +use super::{get_curse_forge_client, API_URL}; + +/* +{ + "data": [ + { + "id": 0, + "gameId": 0, + "name": "string", + "slug": "string", + "links": { + "websiteUrl": "string", + "wikiUrl": "string", + "issuesUrl": "string", + "sourceUrl": "string" + }, + "summary": "string", + "status": 1, + "downloadCount": 0, + "isFeatured": true, + "primaryCategoryId": 0, + "categories": [ + { + "id": 0, + "gameId": 0, + "name": "string", + "slug": "string", + "url": "string", + "iconUrl": "string", + "dateModified": "2019-08-24T14:15:22Z", + "isClass": true, + "classId": 0, + "parentCategoryId": 0, + "displayIndex": 0 + } + ], + "classId": 0, + "authors": [ + { + "id": 0, + "name": "string", + "url": "string" + } + ], + "logo": { + "id": 0, + "modId": 0, + "title": "string", + "description": "string", + "thumbnailUrl": "string", + "url": "string" + }, + "screenshots": [ + { + "id": 0, + "modId": 0, + "title": "string", + "description": "string", + "thumbnailUrl": "string", + "url": "string" + } + ], + "mainFileId": 0, + "latestFiles": [ + { + "id": 0, + "gameId": 0, + "modId": 0, + "isAvailable": true, + "displayName": "string", + "fileName": "string", + "releaseType": 1, + "fileStatus": 1, + "hashes": [ + { + "value": "string", + "algo": 1 + } + ], + "fileDate": "2019-08-24T14:15:22Z", + "fileLength": 0, + "downloadCount": 0, + "fileSizeOnDisk": 0, + "downloadUrl": "string", + "gameVersions": [ + "string" + ], + "sortableGameVersions": [ + { + "gameVersionName": "string", + "gameVersionPadded": "string", + "gameVersion": "string", + "gameVersionReleaseDate": "2019-08-24T14:15:22Z", + "gameVersionTypeId": 0 + } + ], + "dependencies": [ + { + "modId": 0, + "relationType": 1 + } + ], + "exposeAsAlternative": true, + "parentProjectFileId": 0, + "alternateFileId": 0, + "isServerPack": true, + "serverPackFileId": 0, + "isEarlyAccessContent": true, + "earlyAccessEndDate": "2019-08-24T14:15:22Z", + "fileFingerprint": 0, + "modules": [ + { + "name": "string", + "fingerprint": 0 + } + ] + } + ], + "latestFilesIndexes": [ + { + "gameVersion": "string", + "fileId": 0, + "filename": "string", + "releaseType": 1, + "gameVersionTypeId": 0, + "modLoader": 0 + } + ], + "latestEarlyAccessFilesIndexes": [ + { + "gameVersion": "string", + "fileId": 0, + "filename": "string", + "releaseType": 1, + "gameVersionTypeId": 0, + "modLoader": 0 + } + ], + "dateCreated": "2019-08-24T14:15:22Z", + "dateModified": "2019-08-24T14:15:22Z", + "dateReleased": "2019-08-24T14:15:22Z", + "allowModDistribution": true, + "gamePopularityRank": 0, + "isAvailable": true, + "thumbsUpCount": 0 + } + ], + "pagination": { + "index": 0, + "pageSize": 0, + "resultCount": 0, + "totalCount": 0 + } +} +*/ +#[derive(Debug, Deserialize)] +struct Hash { + value: String, + algo: i32, +} + +#[derive(Debug, Deserialize)] +struct SortableGameVersion { + gameVersionName: String, + gameVersionPadded: String, + gameVersion: String, + gameVersionReleaseDate: String, + gameVersionTypeId: i32, +} + +#[derive(Debug, Deserialize)] +struct Dependency { + modId: i32, + relationType: i32, +} + +#[derive(Debug, Deserialize)] +struct Module { + name: String, + fingerprint: i32, +} + +#[derive(Debug, Deserialize)] +pub struct Mod { + pub name: String, + //pub modId: i32, + //pub gameSlug: String, + //pub gameId: i32, + pub summary: String, + //pub defaultFileId: i32, + //pub downloadCount: i32, + //pub latestFiles: Vec, + //pub latestFilesIndexes: Vec, + //pub latestEarlyAccessFilesIndexes: Vec, + //pub dateCreated: String, + //pub dateModified: String, + //pub dateReleased: String, + //pub allowModDistribution: bool, + //pub gamePopularityRank: i32, + //pub isAvailable: bool, + //pub thumbsUpCount: i32, +} + +#[derive(Debug, Deserialize)] +struct LatestFile { + fileId: i32, + displayName: String, + fileName: String, + fileDate: String, + fileLength: i32, + releaseType: i32, + fileStatus: i32, + downloadUrl: String, + gameVersions: Vec, + sortableGameVersions: Vec, + dependencies: Vec, + exposeAsAlternative: bool, + parentProjectFileId: i32, + alternateFileId: i32, + isServerPack: bool, + serverPackFileId: i32, + isEarlyAccessContent: bool, + earlyAccessEndDate: String, + fileFingerprint: i32, + modules: Vec, +} + +#[derive(Debug, Deserialize)] +struct LatestFileIndex { + gameVersion: String, + fileId: i32, + filename: String, + releaseType: i32, + gameVersionTypeId: i32, + modLoader: i32, +} + +#[derive(Debug, Deserialize)] +struct LatestEarlyAccessFileIndex { + gameVersion: String, + fileId: i32, + filename: String, + releaseType: i32, + gameVersionTypeId: i32, + modLoader: i32, +} + +#[derive(Debug, Deserialize)] +struct GetModsResponse { + data: Vec, + pagination: Pagination, +} + +#[derive(Debug, Deserialize)] +struct Pagination { + index: i32, + pageSize: i32, + resultCount: i32, + totalCount: i32, +} + +pub fn get_mods(game_id: &i32) -> Vec { + let client = get_curse_forge_client().unwrap(); + + let response = client + .get(&format!("{}/v1/mods/search", API_URL)) + .query(&[("gameId", game_id)]) + .send() + .unwrap(); + let json: GetModsResponse = response.json().unwrap(); + + return json.data; +} diff --git a/src/application.rs b/src/application.rs index 59ce71f..df6c57c 100644 --- a/src/application.rs +++ b/src/application.rs @@ -25,16 +25,10 @@ use tracing::{debug, info}; use crate::config::VERSION; use crate::config::{APP_ID, PKGDATADIR, PROFILE}; -use crate::settings::ModManagerSettings; use crate::windows::main::ModManagerWindowMain; -use crate::windows::main::Welcome; mod imp { - use games_and_mods::GamesAndMods; - - use crate::windows::games_and_mods; - use super::*; #[derive(Debug, Default)] diff --git a/src/components/mod.rs b/src/components/mod.rs deleted file mode 100644 index 1732d08..0000000 --- a/src/components/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod mods_list; -pub use mods_list::*; diff --git a/src/components/mods_list.rs b/src/components/mods_list.rs deleted file mode 100644 index 005bf3b..0000000 --- a/src/components/mods_list.rs +++ /dev/null @@ -1,64 +0,0 @@ -/* welcome.rs - * - * Copyright 2023 Tine - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that 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 . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -use adw::subclass::prelude::*; -use gtk::{gio, glib}; -use gtk::{glib::clone, prelude::*}; - -mod imp { - use super::*; - - #[derive(Debug, Default, gtk::CompositeTemplate)] - #[template(resource = "/dev/mnts/ModManager/ui/components/mods_list.ui")] - pub struct ModsList {} - - #[glib::object_subclass] - impl ObjectSubclass for ModsList { - const NAME: &'static str = "ModsList"; - type Type = super::ModsList; - type ParentType = adw::NavigationPage; - - fn class_init(klass: &mut Self::Class) { - klass.bind_template(); - } - - fn instance_init(obj: &glib::subclass::InitializingObject) { - obj.init_template(); - } - } - - impl ObjectImpl for ModsList { - fn constructed(&self) {} - } - impl WidgetImpl for ModsList {} - impl NavigationPageImpl for ModsList {} -} - -glib::wrapper! { - pub struct ModsList(ObjectSubclass) - @extends gtk::Widget, gtk::Buildable, adw::NavigationPage, - @implements gio::ActionGroup, gio::ActionMap; -} - -impl ModsList { - pub fn new() -> Self { - glib::Object::builder().build() - } -} diff --git a/src/main.rs b/src/main.rs index 65c9847..6abb781 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,6 @@ along with this program. If not, see . mod api; mod application; -mod components; mod config; mod settings; mod windows; diff --git a/src/settings.rs b/src/settings.rs index 00d46f0..23a2864 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,15 +1,115 @@ use gio::glib; use gsettings_macro::gen_settings; use gtk::gio; -use std::collections::HashMap; +use tracing::{debug, info}; use crate::config::APP_ID; #[gen_settings(file = "./data/dev.mnts.ModManager.gschema.xml.in")] -pub struct ModManagerSettings; +#[gen_settings_define( + key_name = "games", + arg_type = "Vec<(String, String)>", + ret_type = "Vec<(String, String)>" +)] +pub struct Settings; -impl Default for ModManagerSettings { +impl Default for Settings { fn default() -> Self { Self::new(APP_ID) } } + +#[derive(Debug, Clone)] +pub enum Game { + TheSims4(String), +} +impl Game { + pub fn from_slug(slug: String, path: String) -> Self { + match slug.as_str() { + "sims4" => Game::TheSims4(path), + _ => panic!("Game not supported"), + } + } + + pub fn from_name(name: String, path: String) -> Self { + match name.as_str() { + "The Sims 4" => Game::TheSims4(path), + _ => panic!("Game not supported"), + } + } + + pub fn to_path(&self) -> String { + match self { + Game::TheSims4(path) => path.to_string(), + } + } + + pub fn to_slug(&self) -> String { + match self { + Game::TheSims4(_) => "sims4".to_string(), + } + } + + pub fn to_name(&self) -> String { + match self { + Game::TheSims4(_) => "The Sims 4".to_string(), + } + } +} + +#[derive(Debug, Clone)] +pub struct ModManagerSettings { + settings: Settings, +} + +impl ModManagerSettings { + pub fn default() -> Self { + let settings = Settings::default(); + Self { settings } + } + + pub fn get_supported_games(&self) -> Vec { + info!("Getting supported games"); + + return [Game::TheSims4("".to_string())].to_vec(); + } + + pub fn get_managed_games(&self) -> Vec { + info!("Getting managed games"); + + let mut games_vec: Vec = Vec::new(); + + for (slug, path) in self.settings.games() { + info!("Found game {:?} at path {:?}", slug, path); + games_vec.push(Game::from_slug(slug, path)); + } + + return games_vec; + } + + pub fn add_managed_game(&self, game: Game) { + info!("Adding game {} {}", game.to_slug(), game.to_name()); + + let mut games_vec: Vec<(String, String)> = Vec::new(); + + for (slug, path) in self.settings.games() { + games_vec.push((slug, path)); + } + + games_vec.push((game.to_slug(), game.to_path())); + + self.settings.set_games(games_vec); + } + + pub fn remove_managed_games(&self) { + info!("Removing all managed games"); + + self.settings.set_games([].to_vec()); + } + + pub fn on_managed_games_changed(&self, callback: impl Fn() + 'static) { + self.settings.connect_games_changed(move |_| { + callback(); + }); + } +} diff --git a/src/windows/add_new_game/add_new_game.rs b/src/windows/add_new_game/add_new_game.rs index e035ca7..12cfb7a 100644 --- a/src/windows/add_new_game/add_new_game.rs +++ b/src/windows/add_new_game/add_new_game.rs @@ -25,7 +25,7 @@ use gtk::prelude::*; use gtk::{gio, glib}; use crate::api::*; -use crate::settings::ModManagerSettings; +use crate::settings::{Game, ModManagerSettings}; mod imp { use super::*; @@ -83,9 +83,12 @@ impl ModManagerWindowAddNewGame { } pub fn setup(&self) { - let games = games::get_games(); - let games_strs: Vec<&str> = games.iter().map(|s| s.as_str()).collect(); - let games_list = >k::StringList::new(&games_strs); + let settings = ModManagerSettings::default(); + + let supported_games = settings.get_supported_games(); + let games_strs: Vec = supported_games.iter().map(|s| s.to_name()).collect(); + let games_list = + >k::StringList::new(&games_strs.iter().map(|s| s.as_str()).collect::>()); let obj = self.imp(); @@ -94,18 +97,13 @@ impl ModManagerWindowAddNewGame { let instance = self; obj.complete_button - .connect_clicked(clone!(@strong instance, @strong games_list => move |_| { + .connect_clicked(clone!(@strong instance, @strong games_list, @strong settings => move |_| { //let selected_game = games_dropdown.selected_item(); - let settings = ModManagerSettings::default(); let game_selected = games_list.string(instance.imp().games_dropdown.selected()).unwrap().to_string(); println!("complete button clicked, selected game: {:?}", &game_selected); - let mut selected = settings.games().to_vec(); - selected.push(game_selected); - - settings.set_strv("games", selected); - + settings.add_managed_game(Game::from_name(game_selected, "".to_string())); //if let Some(selected_game) = selected_game { instance.hide() diff --git a/src/windows/main/main.rs b/src/windows/main/main.rs index 89b3406..471757a 100644 --- a/src/windows/main/main.rs +++ b/src/windows/main/main.rs @@ -21,15 +21,14 @@ use gtk::{gio, glib}; use tracing::{debug, info}; use crate::config::PROFILE; -use crate::settings::ModManagerSettings; use crate::windows::GamesAndMods; use super::Welcome; +use crate::settings::ModManagerSettings; +use gtk::glib::clone; mod imp { - use gtk::glib::clone; - use super::*; #[derive(Debug, Default, gtk::CompositeTemplate)] @@ -62,10 +61,10 @@ mod imp { } let settings = ModManagerSettings::default(); - settings.connect_games_changed(clone!(@strong obj, @strong settings => move |_| { + settings.on_managed_games_changed(clone!(@strong obj, @strong settings => move || { info!("Games changed, deciding on initial page."); - let page: gtk::Widget = if settings.games().len() > 0 { + let page: gtk::Widget = if settings.get_managed_games().len() > 0 { GamesAndMods::new().upcast() } else { Welcome::new().upcast() @@ -74,7 +73,7 @@ mod imp { obj.set_property("content", page); })); - let page: gtk::Widget = if settings.games().len() > 0 { + let page: gtk::Widget = if settings.get_managed_games().len() > 0 { GamesAndMods::new().upcast() } else { Welcome::new().upcast() diff --git a/src/windows/main/pages/games_and_mods.rs b/src/windows/main/pages/games_and_mods.rs index 18c0d23..133b98b 100644 --- a/src/windows/main/pages/games_and_mods.rs +++ b/src/windows/main/pages/games_and_mods.rs @@ -25,7 +25,11 @@ mod imp { use gtk::glib::clone; use tracing::info; - use crate::{api::games, settings::ModManagerSettings, windows::ModManagerWindowAddNewGame}; + use crate::{ + api::{games, get_game_id, get_mods}, + settings::{Game, ModManagerSettings}, + windows::ModManagerWindowAddNewGame, + }; use super::*; @@ -40,6 +44,9 @@ mod imp { #[template_child] pub games_list: TemplateChild, + + #[template_child] + pub mods_list: TemplateChild, } #[glib::object_subclass] @@ -64,7 +71,7 @@ mod imp { self.remove_all_games.connect_clicked(|_| { let settings = ModManagerSettings::default(); - settings.set_games(&[]); + settings.remove_managed_games(); println!("Remove all games button clicked"); }); @@ -74,23 +81,40 @@ mod imp { let settings = ModManagerSettings::default(); - for game in settings.games() { - info!("Adding game {} to list", game); + for game in settings.get_managed_games() { + info!("Adding game {:?} to list", game); let row = adw::ActionRow::new(); - row.set_title(&game); + row.set_title(&game.to_name()); obj.imp().games_list.append(&row); } - settings.connect_games_changed(clone!(@weak obj, @strong settings => move |_| { + settings.on_managed_games_changed(clone!(@weak obj, @strong settings => move || { info!("Games changed, modifying list"); - obj.imp().games_list.remove_all(); - for game in settings.games() { - info!("Adding game {} to list", game); + for game in settings.get_managed_games() { + info!("Adding game {:?} to list", game); let row = adw::ActionRow::new(); - row.set_title(&game); + row.set_title(&game.to_name()); obj.imp().games_list.append(&row); } })); + + let mods = get_mods(&get_game_id(Game::TheSims4("".to_string()))) + .iter() + .for_each(|mod_| { + let card = gtk::Box::new(gtk::Orientation::Vertical, 10); + card.set_css_classes(&["card"]); + + let title = gtk::Label::new(Some(&mod_.name)); + title.set_css_classes(&["heading"]); + + let description = gtk::Label::new(Some(&mod_.summary)); + description.set_css_classes(&["body"]); + + card.append(&title); + card.append(&description); + + obj.imp().mods_list.append(&card); + }); } } impl WidgetImpl for GamesAndMods {}