mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2025-02-18 16:21:50 +03:00
Preparations for loading page
- added `Adw.StatusPage` to the preferences - made preparations for progress bar and launcher states system - fixed toasts resizing window issue
This commit is contained in:
parent
3be54b22d2
commit
178c45ae48
9 changed files with 173 additions and 49 deletions
assets/ui
src
|
@ -7,9 +7,7 @@ Adw.ApplicationWindow window {
|
||||||
|
|
||||||
styles ["devel"]
|
styles ["devel"]
|
||||||
|
|
||||||
content: Gtk.Box {
|
content: Adw.ToastOverlay toast_overlay {
|
||||||
orientation: vertical;
|
|
||||||
|
|
||||||
Adw.Leaflet leaflet {
|
Adw.Leaflet leaflet {
|
||||||
can-navigate-back: true;
|
can-navigate-back: true;
|
||||||
can-unfold: false;
|
can-unfold: false;
|
||||||
|
@ -40,7 +38,7 @@ Adw.ApplicationWindow window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Adw.PreferencesGroup {
|
Adw.PreferencesGroup launch_game_group {
|
||||||
vexpand: true;
|
vexpand: true;
|
||||||
valign: center;
|
valign: center;
|
||||||
|
|
||||||
|
@ -69,9 +67,32 @@ Adw.ApplicationWindow window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Adw.ToastOverlay toast_overlay {}
|
Adw.PreferencesGroup progress_bar_group {
|
||||||
|
vexpand: true;
|
||||||
|
valign: center;
|
||||||
|
visible: false;
|
||||||
|
|
||||||
|
Gtk.Box {
|
||||||
|
halign: center;
|
||||||
|
margin-top: 64;
|
||||||
|
spacing: 20;
|
||||||
|
|
||||||
|
Gtk.ProgressBar progress_bar {
|
||||||
|
text: "Downloading: 37% (3.7 of 10 GB)\n";
|
||||||
|
show-text: true;
|
||||||
|
|
||||||
|
width-request: 260;
|
||||||
|
fraction: 0.37;
|
||||||
|
valign: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk.Button {
|
||||||
|
label: "Pause";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,8 +15,16 @@ Gtk.Box preferences {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Adw.Flap {
|
Adw.StatusPage status_page {
|
||||||
|
icon-name: "image-loading-symbolic";
|
||||||
|
title: "Loading data";
|
||||||
|
|
||||||
vexpand: true;
|
vexpand: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.Flap flap {
|
||||||
|
vexpand: true;
|
||||||
|
visible: false;
|
||||||
|
|
||||||
flap: Gtk.StackSidebar {
|
flap: Gtk.StackSidebar {
|
||||||
width-request: 200;
|
width-request: 200;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use libadwaita::{self as adw, prelude::*};
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod lib;
|
pub mod lib;
|
||||||
|
|
||||||
use ui::MainApp;
|
use ui::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
gtk::init().expect("GTK initialization failed");
|
gtk::init().expect("GTK initialization failed");
|
||||||
|
|
|
@ -3,11 +3,20 @@ use libadwaita::{self as adw, prelude::*};
|
||||||
|
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
|
|
||||||
use super::{get_object, add_action};
|
use super::get_object;
|
||||||
use super::preferences::PreferencesStack;
|
use super::preferences::PreferencesStack;
|
||||||
|
use super::ToastError;
|
||||||
|
|
||||||
use crate::lib::game;
|
use crate::lib::game;
|
||||||
|
|
||||||
|
pub enum AppState {
|
||||||
|
Launch,
|
||||||
|
Progress {
|
||||||
|
title: String,
|
||||||
|
progress: f64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct App {
|
pub struct App {
|
||||||
pub window: adw::ApplicationWindow,
|
pub window: adw::ApplicationWindow,
|
||||||
|
@ -17,6 +26,10 @@ pub struct App {
|
||||||
pub open_preferences: gtk::Button,
|
pub open_preferences: gtk::Button,
|
||||||
pub toast_overlay: adw::ToastOverlay,
|
pub toast_overlay: adw::ToastOverlay,
|
||||||
|
|
||||||
|
pub launch_game_group: adw::PreferencesGroup,
|
||||||
|
pub progress_bar_group: adw::PreferencesGroup,
|
||||||
|
pub progress_bar: gtk::ProgressBar,
|
||||||
|
|
||||||
pub preferences_stack: PreferencesStack
|
pub preferences_stack: PreferencesStack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,16 +38,23 @@ impl App {
|
||||||
// Create builder from UI file
|
// Create builder from UI file
|
||||||
let builder = gtk::Builder::from_string(include_str!("../../assets/ui/.dist/main.ui"));
|
let builder = gtk::Builder::from_string(include_str!("../../assets/ui/.dist/main.ui"));
|
||||||
|
|
||||||
|
let window = get_object::<adw::ApplicationWindow>(&builder, "window")?;
|
||||||
|
let toast_overlay = get_object::<adw::ToastOverlay>(&builder, "toast_overlay")?;
|
||||||
|
|
||||||
// Parse objects from builder
|
// Parse objects from builder
|
||||||
let result = Self {
|
let result = Self {
|
||||||
window: get_object(&builder, "window")?,
|
window: window.clone(),
|
||||||
leaflet: get_object(&builder, "leaflet")?,
|
leaflet: get_object(&builder, "leaflet")?,
|
||||||
launch_game: get_object(&builder, "launch_game")?,
|
launch_game: get_object(&builder, "launch_game")?,
|
||||||
launch_game_debug: get_object(&builder, "launch_game_debug")?,
|
launch_game_debug: get_object(&builder, "launch_game_debug")?,
|
||||||
open_preferences: get_object(&builder, "open_preferences")?,
|
open_preferences: get_object(&builder, "open_preferences")?,
|
||||||
toast_overlay: get_object(&builder, "toast_overlay")?,
|
toast_overlay: toast_overlay.clone(),
|
||||||
|
|
||||||
preferences_stack: PreferencesStack::new()?
|
launch_game_group: get_object(&builder, "launch_game_group")?,
|
||||||
|
progress_bar_group: get_object(&builder, "progress_bar_group")?,
|
||||||
|
progress_bar: get_object(&builder, "progress_bar")?,
|
||||||
|
|
||||||
|
preferences_stack: PreferencesStack::new(window, toast_overlay)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add preferences page to the leaflet
|
// Add preferences page to the leaflet
|
||||||
|
@ -73,37 +93,6 @@ impl App {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show toast with `toast` title and `See message` button
|
|
||||||
///
|
|
||||||
/// This button will show message dialog with error message
|
|
||||||
pub fn toast_error(&self, toast: &str, err: std::io::Error) {
|
|
||||||
let toast = adw::Toast::new(toast);
|
|
||||||
|
|
||||||
toast.set_button_label(Some("See message"));
|
|
||||||
toast.set_action_name(Some("see-message.see-message"));
|
|
||||||
|
|
||||||
let window_copy = self.window.clone();
|
|
||||||
|
|
||||||
// Show error message in a dialog window
|
|
||||||
add_action(&self.toast_overlay, "see-message", move || {
|
|
||||||
let dialog = gtk::MessageDialog::new(
|
|
||||||
Some(&window_copy),
|
|
||||||
gtk::DialogFlags::all(),
|
|
||||||
gtk::MessageType::Info,
|
|
||||||
gtk::ButtonsType::Close,
|
|
||||||
&err.to_string()
|
|
||||||
);
|
|
||||||
|
|
||||||
dialog.connect_response(move |dialog, _| {
|
|
||||||
dialog.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
dialog.show();
|
|
||||||
});
|
|
||||||
|
|
||||||
self.toast_overlay.add_toast(&toast);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open_preferences_page(&self) -> Result<(), Error> {
|
pub fn open_preferences_page(&self) -> Result<(), Error> {
|
||||||
self.preferences_stack.update()?;
|
self.preferences_stack.update()?;
|
||||||
|
|
||||||
|
@ -111,4 +100,26 @@ impl App {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_state(&self, state: AppState) {
|
||||||
|
match state {
|
||||||
|
AppState::Launch => {
|
||||||
|
self.launch_game_group.set_visible(true);
|
||||||
|
self.progress_bar_group.set_visible(false);
|
||||||
|
},
|
||||||
|
AppState::Progress { title, progress } => {
|
||||||
|
self.launch_game_group.set_visible(false);
|
||||||
|
self.progress_bar_group.set_visible(true);
|
||||||
|
|
||||||
|
self.progress_bar.set_text(Some(&title));
|
||||||
|
self.progress_bar.set_fraction(progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToastError for App {
|
||||||
|
fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) {
|
||||||
|
(self.window.clone(), self.toast_overlay.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,14 @@ use libadwaita::{self as adw, prelude::*};
|
||||||
|
|
||||||
mod main;
|
mod main;
|
||||||
mod preferences;
|
mod preferences;
|
||||||
|
mod toast_error;
|
||||||
|
|
||||||
pub use main::App as MainApp;
|
pub use main::{
|
||||||
|
App as MainApp,
|
||||||
|
AppState as MainAppState,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use toast_error::ToastError;
|
||||||
|
|
||||||
/// This function loads object from builder or panics if it doesn't exist
|
/// This function loads object from builder or panics if it doesn't exist
|
||||||
pub fn get_object<T: IsA<gtk::glib::Object>>(builder: >k::Builder, name: &str) -> Result<T, String> {
|
pub fn get_object<T: IsA<gtk::glib::Object>>(builder: >k::Builder, name: &str) -> Result<T, String> {
|
||||||
|
|
|
@ -103,9 +103,11 @@ impl Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method is being called by the `PreferencesStack::update`
|
/// This method is being called by the `PreferencesStack::update`
|
||||||
pub fn update(&self) -> Result<(), Error> {
|
pub fn update(&self, status_page: &adw::StatusPage) -> Result<(), Error> {
|
||||||
let config = config::get()?;
|
let config = config::get()?;
|
||||||
|
|
||||||
|
status_page.set_description(Some("Loading preferences..."));
|
||||||
|
|
||||||
// Update Wine sync
|
// Update Wine sync
|
||||||
self.sync_combo.set_selected(config.game.wine.sync.into());
|
self.sync_combo.set_selected(config.game.wine.sync.into());
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,15 @@ impl Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method is being called by the `PreferencesStack::update`
|
/// This method is being called by the `PreferencesStack::update`
|
||||||
pub fn update(&self) -> Result<(), Error> {
|
pub fn update(&self, status_page: &adw::StatusPage) -> Result<(), Error> {
|
||||||
let config = config::get()?;
|
let config = config::get()?;
|
||||||
let game = Game::new(config.game.path);
|
let game = Game::new(config.game.path);
|
||||||
|
|
||||||
self.game_version.set_tooltip_text(None);
|
self.game_version.set_tooltip_text(None);
|
||||||
self.patch_version.set_tooltip_text(None);
|
self.patch_version.set_tooltip_text(None);
|
||||||
|
|
||||||
|
status_page.set_description(Some("Updating game info..."));
|
||||||
|
|
||||||
match game.try_get_diff()? {
|
match game.try_get_diff()? {
|
||||||
VersionDiff::Latest(version) => {
|
VersionDiff::Latest(version) => {
|
||||||
self.game_version.set_label(&version.to_string());
|
self.game_version.set_label(&version.to_string());
|
||||||
|
@ -61,6 +63,8 @@ impl Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_page.set_description(Some("Updating patch info..."));
|
||||||
|
|
||||||
match Patch::try_fetch(config.patch.servers)? {
|
match Patch::try_fetch(config.patch.servers)? {
|
||||||
Patch::NotAvailable => {
|
Patch::NotAvailable => {
|
||||||
self.patch_version.set_label("not available");
|
self.patch_version.set_label("not available");
|
||||||
|
|
|
@ -4,6 +4,7 @@ use libadwaita::{self as adw, prelude::*};
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
|
|
||||||
use crate::ui::get_object;
|
use crate::ui::get_object;
|
||||||
|
use crate::ui::ToastError;
|
||||||
|
|
||||||
mod general_page;
|
mod general_page;
|
||||||
mod enhanced_page;
|
mod enhanced_page;
|
||||||
|
@ -15,9 +16,15 @@ pub mod pages {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PreferencesStack {
|
pub struct PreferencesStack {
|
||||||
|
pub window: adw::ApplicationWindow,
|
||||||
|
pub toast_overlay: adw::ToastOverlay,
|
||||||
|
|
||||||
pub preferences: gtk::Box,
|
pub preferences: gtk::Box,
|
||||||
pub preferences_go_back: gtk::Button,
|
pub preferences_go_back: gtk::Button,
|
||||||
|
|
||||||
|
pub status_page: adw::StatusPage,
|
||||||
|
pub flap: adw::Flap,
|
||||||
|
|
||||||
pub stack: gtk::Stack,
|
pub stack: gtk::Stack,
|
||||||
|
|
||||||
pub general_page: pages::GeneralPage,
|
pub general_page: pages::GeneralPage,
|
||||||
|
@ -25,13 +32,21 @@ pub struct PreferencesStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PreferencesStack {
|
impl PreferencesStack {
|
||||||
pub fn new() -> Result<Self, String> {
|
pub fn new(window: adw::ApplicationWindow, toast_overlay: adw::ToastOverlay) -> Result<Self, String> {
|
||||||
let builder = gtk::Builder::from_string(include_str!("../../../assets/ui/.dist/preferences.ui"));
|
let builder = gtk::Builder::from_string(include_str!("../../../assets/ui/.dist/preferences.ui"));
|
||||||
|
|
||||||
let result = Self {
|
let result = Self {
|
||||||
|
window,
|
||||||
|
toast_overlay,
|
||||||
|
|
||||||
preferences: get_object(&builder, "preferences")?,
|
preferences: get_object(&builder, "preferences")?,
|
||||||
preferences_go_back: get_object(&builder, "preferences_go_back")?,
|
preferences_go_back: get_object(&builder, "preferences_go_back")?,
|
||||||
|
|
||||||
|
status_page: get_object(&builder, "status_page")?,
|
||||||
|
flap: get_object(&builder, "flap")?,
|
||||||
|
|
||||||
stack: get_object(&builder, "stack")?,
|
stack: get_object(&builder, "stack")?,
|
||||||
|
|
||||||
general_page: pages::GeneralPage::new()?,
|
general_page: pages::GeneralPage::new()?,
|
||||||
enhanced_page: pages::EnhancedPage::new()?
|
enhanced_page: pages::EnhancedPage::new()?
|
||||||
};
|
};
|
||||||
|
@ -48,9 +63,24 @@ impl PreferencesStack {
|
||||||
///
|
///
|
||||||
/// TODO: do it asynchronously. The problem is that I somehow need to handle this function's error to display it as a toast
|
/// TODO: do it asynchronously. The problem is that I somehow need to handle this function's error to display it as a toast
|
||||||
pub fn update(&self) -> Result<(), Error> {
|
pub fn update(&self) -> Result<(), Error> {
|
||||||
self.general_page.update()?;
|
self.status_page.set_visible(true);
|
||||||
self.enhanced_page.update()?;
|
self.status_page.set_description(None);
|
||||||
|
self.flap.set_visible(false);
|
||||||
|
|
||||||
|
self.general_page.update(&self.status_page)?;
|
||||||
|
self.enhanced_page.update(&self.status_page)?;
|
||||||
|
|
||||||
|
self.status_page.set_visible(false);
|
||||||
|
self.flap.set_visible(true);
|
||||||
|
|
||||||
|
self.toast_error("Aboba amogus", Error::last_os_error());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToastError for PreferencesStack {
|
||||||
|
fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) {
|
||||||
|
(self.window.clone(), self.toast_overlay.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
42
src/ui/toast_error.rs
Normal file
42
src/ui/toast_error.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use gtk4::{self as gtk, prelude::*};
|
||||||
|
use libadwaita::{self as adw, prelude::*};
|
||||||
|
|
||||||
|
use std::io::Error;
|
||||||
|
|
||||||
|
use super::add_action;
|
||||||
|
|
||||||
|
pub trait ToastError {
|
||||||
|
fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay);
|
||||||
|
|
||||||
|
/// Show toast with `toast` title and `See message` button
|
||||||
|
///
|
||||||
|
/// This button will show message dialog with error message
|
||||||
|
fn toast_error(&self, toast: &str, err: Error) {
|
||||||
|
let toast = adw::Toast::new(toast);
|
||||||
|
|
||||||
|
toast.set_button_label(Some("See message"));
|
||||||
|
toast.set_action_name(Some("see-message.see-message"));
|
||||||
|
toast.set_timeout(0);
|
||||||
|
|
||||||
|
let (window, toast_overlay) = self.get_toast_widgets();
|
||||||
|
|
||||||
|
// Show error message in a dialog window
|
||||||
|
add_action(&toast_overlay, "see-message", move || {
|
||||||
|
let dialog = gtk::MessageDialog::new(
|
||||||
|
Some(&window),
|
||||||
|
gtk::DialogFlags::all(),
|
||||||
|
gtk::MessageType::Info,
|
||||||
|
gtk::ButtonsType::Close,
|
||||||
|
&err.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
dialog.connect_response(move |dialog, _| {
|
||||||
|
dialog.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
toast_overlay.add_toast(&toast);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue