feat: settings refactor and initial mod listing
This commit is contained in:
parent
807f4b668c
commit
613c9032a9
18 changed files with 490 additions and 265 deletions
|
@ -13,9 +13,9 @@
|
|||
<default>false</default>
|
||||
<summary>Window maximized state</summary>
|
||||
</key>
|
||||
<key name="games" type="as">
|
||||
<key name="games" type="a(ss)">
|
||||
<default>[]</default>
|
||||
<summary>Games</summary>
|
||||
<summary>List of games. (Slug, Path)</summary>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
|
@ -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@'],
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
<file compressed="true">ui/windows/main/pages/welcome.ui</file>
|
||||
<file compressed="true">ui/windows/main/pages/games_and_mods.ui</file>
|
||||
<file compressed="true">ui/windows/add_new_game/add_new_game.ui</file>
|
||||
<file compressed="true">ui/components/mods_list.ui</file>
|
||||
<file compressed="true">style.css</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
</gresources>
|
|
@ -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: "<Control>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");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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"]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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<reqwest::blocking::Client, reqwest::Error> {
|
||||
let mut api_key_header =
|
||||
reqwest::header::HeaderValue::from_str(crate::config::API_KEY).unwrap();
|
||||
|
|
|
@ -3,11 +3,16 @@ use serde::Deserialize;
|
|||
use crate::api::*;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct Response {
|
||||
struct GetGamesResponse {
|
||||
data: Vec<Game>,
|
||||
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<String> {
|
|||
.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;
|
||||
}
|
||||
|
|
|
@ -3,3 +3,6 @@ pub use base::*;
|
|||
|
||||
pub mod games;
|
||||
pub use games::*;
|
||||
|
||||
pub mod mods;
|
||||
pub use mods::*;
|
||||
|
|
275
src/api/mods.rs
Normal file
275
src/api/mods.rs
Normal file
|
@ -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<LatestFile>,
|
||||
//pub latestFilesIndexes: Vec<LatestFileIndex>,
|
||||
//pub latestEarlyAccessFilesIndexes: Vec<LatestEarlyAccessFileIndex>,
|
||||
//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<String>,
|
||||
sortableGameVersions: Vec<SortableGameVersion>,
|
||||
dependencies: Vec<Dependency>,
|
||||
exposeAsAlternative: bool,
|
||||
parentProjectFileId: i32,
|
||||
alternateFileId: i32,
|
||||
isServerPack: bool,
|
||||
serverPackFileId: i32,
|
||||
isEarlyAccessContent: bool,
|
||||
earlyAccessEndDate: String,
|
||||
fileFingerprint: i32,
|
||||
modules: Vec<Module>,
|
||||
}
|
||||
|
||||
#[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<Mod>,
|
||||
pagination: Pagination,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Pagination {
|
||||
index: i32,
|
||||
pageSize: i32,
|
||||
resultCount: i32,
|
||||
totalCount: i32,
|
||||
}
|
||||
|
||||
pub fn get_mods(game_id: &i32) -> Vec<Mod> {
|
||||
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;
|
||||
}
|
|
@ -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)]
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
pub mod mods_list;
|
||||
pub use mods_list::*;
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for ModsList {
|
||||
fn constructed(&self) {}
|
||||
}
|
||||
impl WidgetImpl for ModsList {}
|
||||
impl NavigationPageImpl for ModsList {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct ModsList(ObjectSubclass<imp::ModsList>)
|
||||
@extends gtk::Widget, gtk::Buildable, adw::NavigationPage,
|
||||
@implements gio::ActionGroup, gio::ActionMap;
|
||||
}
|
||||
|
||||
impl ModsList {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::builder().build()
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
mod api;
|
||||
mod application;
|
||||
mod components;
|
||||
mod config;
|
||||
mod settings;
|
||||
mod windows;
|
||||
|
|
106
src/settings.rs
106
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<Game> {
|
||||
info!("Getting supported games");
|
||||
|
||||
return [Game::TheSims4("".to_string())].to_vec();
|
||||
}
|
||||
|
||||
pub fn get_managed_games(&self) -> Vec<Game> {
|
||||
info!("Getting managed games");
|
||||
|
||||
let mut games_vec: Vec<Game> = 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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String> = supported_games.iter().map(|s| s.to_name()).collect();
|
||||
let games_list =
|
||||
>k::StringList::new(&games_strs.iter().map(|s| s.as_str()).collect::<Vec<&str>>());
|
||||
|
||||
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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<gtk::ListBox>,
|
||||
|
||||
#[template_child]
|
||||
pub mods_list: TemplateChild<gtk::ListBox>,
|
||||
}
|
||||
|
||||
#[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 {}
|
||||
|
|
Loading…
Reference in a new issue