feat: fetch games and show in dropdown

This commit is contained in:
Tine Jozelj 2023-12-18 23:58:52 +01:00
parent 7c911282b6
commit f9f5330a49
Signed by: mentos1386
SSH key fingerprint: SHA256:MNtTsLbihYaWF8j1fkOHfkKNlnN1JQfxEU/rBU8nCGw
14 changed files with 1028 additions and 108 deletions

11
.vscode/settings.json vendored
View file

@ -7,12 +7,15 @@
".flatpak/**": 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.runnables.command": "${workspaceFolder}/.flatpak/cargo.sh",
"rust-analyzer.files.excludeDirs": [
".flatpak"
]
],
"rust-analyzer.linkedProjects": [
"./Cargo.toml"
],
"mesonbuild.configureOnOpen": false,
"mesonbuild.buildFolder": "_build",
"mesonbuild.mesonPath": "${workspaceFolder}/.flatpak/meson.sh"
}

925
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,8 @@ edition = "2021"
[dependencies]
gettext-rs = { version = "0.7", features = ["gettext-system"] }
gtk = { version = "0.7", package = "gtk4" }
reqwest = { version = "0.11", features = ["json", "blocking"] }
serde = { version = "1.0", features = ["derive"] }
[dependencies.adw]
package = "libadwaita"

1
meson.options Normal file
View file

@ -0,0 +1 @@
option('api-key', type : 'string', description : 'CurseForge API Key')

14
src/api/base.rs Normal file
View 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
View 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
View file

@ -0,0 +1,5 @@
mod base;
pub use base::*;
pub mod games;
pub use games::*;

View file

@ -61,8 +61,11 @@ mod imp {
} else {
let window = ModManagerWindow::new(&*application);
let welcome = &ModManagerWelcome::new().upcast::<adw::NavigationPage>();
window.set_page(welcome);
let welcome = ModManagerWelcome::new();
// TODO: Somehow we should handle this at some other point?
welcome.setup_dropdown();
window.set_page(&welcome.upcast::<adw::NavigationPage>());
window.upcast()
};

View file

@ -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";

View file

@ -2,3 +2,5 @@ pub static VERSION: &str = @VERSION@;
pub static GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@;
pub static LOCALEDIR: &str = @LOCALEDIR@;
pub static PKGDATADIR: &str = @PKGDATADIR@;
pub static API_KEY: &str = @API_KEY@;

View file

@ -19,6 +19,7 @@ mod application;
mod config;
mod window;
mod pages;
mod api;
use self::application::ModManagerApplication;
use self::window::ModManagerWindow;

View file

@ -26,6 +26,7 @@ conf.set_quoted('VERSION', meson.project_version())
conf.set_quoted('GETTEXT_PACKAGE', 'mod-manager')
conf.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir'))
conf.set_quoted('PKGDATADIR', pkgdatadir)
conf.set_quoted('API_KEY', '$2a$10$AtaQ/fkWxMoVHVhO.6PMoOHQq7ERdSdpmegqJ09.2Mgj5iTQP3r.2')
configure_file(
input: 'config.rs.in',

View file

@ -3,109 +3,24 @@ using Adw 1;
template $ModManagerWelcome : Adw.NavigationPage {
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;
valign: 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");
}
Label {
label: _("Welcome to Mod Manager");
margin-bottom: 30;
justify: center;
styles ["title-1"]
}
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");
}
Label {
label: _("Start with picking the game you want to manage mods for");
margin-bottom: 30;
justify: center;
}
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");
}
}
DropDown games_dropdown {}
}
}

View file

@ -22,12 +22,16 @@ use gtk::prelude::*;
use adw::subclass::prelude::*;
use gtk::{gio, glib};
use crate::api::*;
mod imp {
use super::*;
#[derive(Debug, Default, gtk::CompositeTemplate)]
#[template(resource = "/dev/mnts/ModManager/pages/welcome.ui")]
pub struct ModManagerWelcome {
#[template_child]
pub games_dropdown: TemplateChild<gtk::DropDown>
}
#[glib::object_subclass]
@ -62,5 +66,13 @@ impl ModManagerWelcome {
glib::Object::builder()
.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 = &gtk::StringList::new(&games_strs);
imp::ModManagerWelcome::from_obj(self).games_dropdown.set_property("model", games_list)
}
}