feat: fetch games and show in dropdown
This commit is contained in:
parent
7c911282b6
commit
f9f5330a49
14 changed files with 1028 additions and 108 deletions
11
.vscode/settings.json
vendored
11
.vscode/settings.json
vendored
|
@ -7,12 +7,15 @@
|
||||||
".flatpak/**": true,
|
".flatpak/**": true,
|
||||||
"_build/**": true
|
"_build/**": true
|
||||||
},
|
},
|
||||||
"mesonbuild.configureOnOpen": false,
|
|
||||||
"mesonbuild.buildFolder": "_build",
|
|
||||||
"mesonbuild.mesonPath": "${workspaceFolder}/.flatpak/meson.sh",
|
|
||||||
"rust-analyzer.server.path": "${workspaceFolder}/.flatpak/rust-analyzer.sh",
|
"rust-analyzer.server.path": "${workspaceFolder}/.flatpak/rust-analyzer.sh",
|
||||||
"rust-analyzer.runnables.command": "${workspaceFolder}/.flatpak/cargo.sh",
|
"rust-analyzer.runnables.command": "${workspaceFolder}/.flatpak/cargo.sh",
|
||||||
"rust-analyzer.files.excludeDirs": [
|
"rust-analyzer.files.excludeDirs": [
|
||||||
".flatpak"
|
".flatpak"
|
||||||
]
|
],
|
||||||
|
"rust-analyzer.linkedProjects": [
|
||||||
|
"./Cargo.toml"
|
||||||
|
],
|
||||||
|
"mesonbuild.configureOnOpen": false,
|
||||||
|
"mesonbuild.buildFolder": "_build",
|
||||||
|
"mesonbuild.mesonPath": "${workspaceFolder}/.flatpak/meson.sh"
|
||||||
}
|
}
|
925
Cargo.lock
generated
925
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -6,6 +6,8 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gettext-rs = { version = "0.7", features = ["gettext-system"] }
|
gettext-rs = { version = "0.7", features = ["gettext-system"] }
|
||||||
gtk = { version = "0.7", package = "gtk4" }
|
gtk = { version = "0.7", package = "gtk4" }
|
||||||
|
reqwest = { version = "0.11", features = ["json", "blocking"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
[dependencies.adw]
|
[dependencies.adw]
|
||||||
package = "libadwaita"
|
package = "libadwaita"
|
||||||
|
|
1
meson.options
Normal file
1
meson.options
Normal file
|
@ -0,0 +1 @@
|
||||||
|
option('api-key', type : 'string', description : 'CurseForge API Key')
|
14
src/api/base.rs
Normal file
14
src/api/base.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
pub const API_URL: &str = "https://api.curseforge.com";
|
||||||
|
|
||||||
|
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();
|
||||||
|
api_key_header.set_sensitive(true);
|
||||||
|
|
||||||
|
let mut headers = reqwest::header::HeaderMap::new();
|
||||||
|
headers.insert("x-api-key", api_key_header);
|
||||||
|
|
||||||
|
reqwest::blocking::Client::builder()
|
||||||
|
.user_agent(format!("dev.mnts.ModManager/{}", crate::config::VERSION))
|
||||||
|
.default_headers(headers)
|
||||||
|
.build()
|
||||||
|
}
|
44
src/api/games.rs
Normal file
44
src/api/games.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::api::*;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct Response {
|
||||||
|
data: Vec<Game>,
|
||||||
|
pagination: Pagination
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct Game {
|
||||||
|
id: u32,
|
||||||
|
name: String,
|
||||||
|
slug: String,
|
||||||
|
dateModified: String,
|
||||||
|
assets: Assets,
|
||||||
|
status: u32,
|
||||||
|
apiStatus: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct Assets {
|
||||||
|
iconUrl: Option<String>,
|
||||||
|
tileUrl: String,
|
||||||
|
coverUrl: Option<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct Pagination {
|
||||||
|
index: u32,
|
||||||
|
pageSize: u32,
|
||||||
|
resultCount: u32,
|
||||||
|
totalCount: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn get_games() -> Vec<String> {
|
||||||
|
let client = base::get_curse_forge_client().unwrap();
|
||||||
|
let response = client.get(&format!("{}/v1/games", base::API_URL)).send().unwrap();
|
||||||
|
let json: Response = response.json().unwrap();
|
||||||
|
|
||||||
|
return json.data.iter().map(|game| game.name.clone()).collect();
|
||||||
|
}
|
5
src/api/mod.rs
Normal file
5
src/api/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
mod base;
|
||||||
|
pub use base::*;
|
||||||
|
|
||||||
|
pub mod games;
|
||||||
|
pub use games::*;
|
|
@ -61,8 +61,11 @@ mod imp {
|
||||||
} else {
|
} else {
|
||||||
let window = ModManagerWindow::new(&*application);
|
let window = ModManagerWindow::new(&*application);
|
||||||
|
|
||||||
let welcome = &ModManagerWelcome::new().upcast::<adw::NavigationPage>();
|
let welcome = ModManagerWelcome::new();
|
||||||
window.set_page(welcome);
|
|
||||||
|
// TODO: Somehow we should handle this at some other point?
|
||||||
|
welcome.setup_dropdown();
|
||||||
|
window.set_page(&welcome.upcast::<adw::NavigationPage>());
|
||||||
|
|
||||||
window.upcast()
|
window.upcast()
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
pub static VERSION: &str = "0.1.0";
|
|
||||||
pub static GETTEXT_PACKAGE: &str = "mod-manager";
|
|
||||||
pub static LOCALEDIR: &str = "/app/share/locale";
|
|
||||||
pub static PKGDATADIR: &str = "/app/share/mod-manager";
|
|
|
@ -2,3 +2,5 @@ pub static VERSION: &str = @VERSION@;
|
||||||
pub static GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@;
|
pub static GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@;
|
||||||
pub static LOCALEDIR: &str = @LOCALEDIR@;
|
pub static LOCALEDIR: &str = @LOCALEDIR@;
|
||||||
pub static PKGDATADIR: &str = @PKGDATADIR@;
|
pub static PKGDATADIR: &str = @PKGDATADIR@;
|
||||||
|
|
||||||
|
pub static API_KEY: &str = @API_KEY@;
|
||||||
|
|
|
@ -19,6 +19,7 @@ mod application;
|
||||||
mod config;
|
mod config;
|
||||||
mod window;
|
mod window;
|
||||||
mod pages;
|
mod pages;
|
||||||
|
mod api;
|
||||||
|
|
||||||
use self::application::ModManagerApplication;
|
use self::application::ModManagerApplication;
|
||||||
use self::window::ModManagerWindow;
|
use self::window::ModManagerWindow;
|
||||||
|
|
|
@ -26,6 +26,7 @@ conf.set_quoted('VERSION', meson.project_version())
|
||||||
conf.set_quoted('GETTEXT_PACKAGE', 'mod-manager')
|
conf.set_quoted('GETTEXT_PACKAGE', 'mod-manager')
|
||||||
conf.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir'))
|
conf.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir'))
|
||||||
conf.set_quoted('PKGDATADIR', pkgdatadir)
|
conf.set_quoted('PKGDATADIR', pkgdatadir)
|
||||||
|
conf.set_quoted('API_KEY', '$2a$10$AtaQ/fkWxMoVHVhO.6PMoOHQq7ERdSdpmegqJ09.2Mgj5iTQP3r.2')
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
input: 'config.rs.in',
|
input: 'config.rs.in',
|
||||||
|
|
|
@ -3,109 +3,24 @@ using Adw 1;
|
||||||
|
|
||||||
template $ModManagerWelcome : Adw.NavigationPage {
|
template $ModManagerWelcome : Adw.NavigationPage {
|
||||||
|
|
||||||
|
Box {
|
||||||
|
orientation: vertical;
|
||||||
|
halign: center;
|
||||||
|
valign: center;
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
label: _("Welcome to Mod Manager");
|
label: _("Welcome to Mod Manager");
|
||||||
margin-bottom: 30;
|
margin-bottom: 30;
|
||||||
|
justify: center;
|
||||||
styles [
|
styles ["title-1"]
|
||||||
"title-1"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Box subtitle {
|
|
||||||
orientation: vertical;
|
|
||||||
halign: center;
|
|
||||||
margin-bottom: 30;
|
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
label: "Learn and prototype with\nGNOME technologies";
|
label: _("Start with picking the game you want to manage mods for");
|
||||||
|
margin-bottom: 30;
|
||||||
justify: center;
|
justify: center;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Box {
|
DropDown games_dropdown {}
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,12 +22,16 @@ use gtk::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use gtk::{gio, glib};
|
use gtk::{gio, glib};
|
||||||
|
|
||||||
|
use crate::api::*;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||||
#[template(resource = "/dev/mnts/ModManager/pages/welcome.ui")]
|
#[template(resource = "/dev/mnts/ModManager/pages/welcome.ui")]
|
||||||
pub struct ModManagerWelcome {
|
pub struct ModManagerWelcome {
|
||||||
|
#[template_child]
|
||||||
|
pub games_dropdown: TemplateChild<gtk::DropDown>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
@ -62,5 +66,13 @@ impl ModManagerWelcome {
|
||||||
glib::Object::builder()
|
glib::Object::builder()
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setup_dropdown(&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);
|
||||||
|
|
||||||
|
imp::ModManagerWelcome::from_obj(self).games_dropdown.set_property("model", games_list)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue