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:
Observer KRypt0n_ 2022-07-02 12:18:44 +02:00
parent 3be54b22d2
commit 178c45ae48
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
9 changed files with 173 additions and 49 deletions

View file

@ -7,9 +7,7 @@ Adw.ApplicationWindow window {
styles ["devel"]
content: Gtk.Box {
orientation: vertical;
content: Adw.ToastOverlay toast_overlay {
Adw.Leaflet leaflet {
can-navigate-back: true;
can-unfold: false;
@ -40,7 +38,7 @@ Adw.ApplicationWindow window {
}
}
Adw.PreferencesGroup {
Adw.PreferencesGroup launch_game_group {
vexpand: true;
valign: center;
@ -69,9 +67,32 @@ Adw.ApplicationWindow window {
}
}
}
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;
}
Adw.ToastOverlay toast_overlay {}
Gtk.Button {
label: "Pause";
}
}
}
}
}
}
};

View file

@ -15,8 +15,16 @@ Gtk.Box preferences {
}
}
Adw.Flap {
Adw.StatusPage status_page {
icon-name: "image-loading-symbolic";
title: "Loading data";
vexpand: true;
}
Adw.Flap flap {
vexpand: true;
visible: false;
flap: Gtk.StackSidebar {
width-request: 200;

View file

@ -4,7 +4,7 @@ use libadwaita::{self as adw, prelude::*};
pub mod ui;
pub mod lib;
use ui::MainApp;
use ui::*;
fn main() {
gtk::init().expect("GTK initialization failed");

View file

@ -3,11 +3,20 @@ use libadwaita::{self as adw, prelude::*};
use std::io::Error;
use super::{get_object, add_action};
use super::get_object;
use super::preferences::PreferencesStack;
use super::ToastError;
use crate::lib::game;
pub enum AppState {
Launch,
Progress {
title: String,
progress: f64
}
}
#[derive(Clone)]
pub struct App {
pub window: adw::ApplicationWindow,
@ -17,6 +26,10 @@ pub struct App {
pub open_preferences: gtk::Button,
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
}
@ -25,16 +38,23 @@ impl App {
// Create builder from UI file
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
let result = Self {
window: get_object(&builder, "window")?,
window: window.clone(),
leaflet: get_object(&builder, "leaflet")?,
launch_game: get_object(&builder, "launch_game")?,
launch_game_debug: get_object(&builder, "launch_game_debug")?,
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
@ -73,37 +93,6 @@ impl App {
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> {
self.preferences_stack.update()?;
@ -111,4 +100,26 @@ impl App {
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())
}
}

View file

@ -3,8 +3,14 @@ use libadwaita::{self as adw, prelude::*};
mod main;
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
pub fn get_object<T: IsA<gtk::glib::Object>>(builder: &gtk::Builder, name: &str) -> Result<T, String> {

View file

@ -103,9 +103,11 @@ impl Page {
}
/// 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()?;
status_page.set_description(Some("Loading preferences..."));
// Update Wine sync
self.sync_combo.set_selected(config.game.wine.sync.into());

View file

@ -32,13 +32,15 @@ impl Page {
}
/// 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 game = Game::new(config.game.path);
self.game_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()? {
VersionDiff::Latest(version) => {
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)? {
Patch::NotAvailable => {
self.patch_version.set_label("not available");

View file

@ -4,6 +4,7 @@ use libadwaita::{self as adw, prelude::*};
use std::io::Error;
use crate::ui::get_object;
use crate::ui::ToastError;
mod general_page;
mod enhanced_page;
@ -15,9 +16,15 @@ pub mod pages {
#[derive(Clone)]
pub struct PreferencesStack {
pub window: adw::ApplicationWindow,
pub toast_overlay: adw::ToastOverlay,
pub preferences: gtk::Box,
pub preferences_go_back: gtk::Button,
pub status_page: adw::StatusPage,
pub flap: adw::Flap,
pub stack: gtk::Stack,
pub general_page: pages::GeneralPage,
@ -25,13 +32,21 @@ pub struct 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 result = Self {
window,
toast_overlay,
preferences: get_object(&builder, "preferences")?,
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")?,
general_page: pages::GeneralPage::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
pub fn update(&self) -> Result<(), Error> {
self.general_page.update()?;
self.enhanced_page.update()?;
self.status_page.set_visible(true);
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(())
}
}
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
View 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);
}
}