diff --git a/.idea/runConfigurations/Build.xml b/.idea/runConfigurations/Build.xml new file mode 100644 index 0000000..bf50f68 --- /dev/null +++ b/.idea/runConfigurations/Build.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Clippy.xml b/.idea/runConfigurations/Clippy.xml new file mode 100644 index 0000000..f257bb9 --- /dev/null +++ b/.idea/runConfigurations/Clippy.xml @@ -0,0 +1,19 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Clippy_Pedantic.xml b/.idea/runConfigurations/Clippy_Pedantic.xml new file mode 100644 index 0000000..25015e0 --- /dev/null +++ b/.idea/runConfigurations/Clippy_Pedantic.xml @@ -0,0 +1,19 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Install.xml b/.idea/runConfigurations/Install.xml new file mode 100644 index 0000000..ed9d0f4 --- /dev/null +++ b/.idea/runConfigurations/Install.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/Run.xml b/.idea/runConfigurations/Run.xml new file mode 100644 index 0000000..998f402 --- /dev/null +++ b/.idea/runConfigurations/Run.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index fe3c95e..d1889a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "epic_asset_manager" -version = "3.8.4" +version = "3.8.5" authors = ["Milan Stastny "] edition = "2021" license-file = "LICENSE" @@ -10,18 +10,19 @@ keywords = ["unreal", "engine", "gamedev", "assets", "epic"] categories = ["gui"] [dependencies] -adw = { package = "libadwaita", version = "0.3" } +adw = { package = "libadwaita", version = "0.5.3" } anyhow = "1.0" -byte-unit = "4.0" +async-channel = "2.2" +byte-unit = "5.1" chrono = "0.4" -diesel = { version = "2.0.0", features = ["sqlite", "r2d2"] } -diesel_migrations = { version = "2.0.0", features = ["sqlite"] } -egs-api = "0.6" -env_logger = "0.10.0" +diesel = { version = "2", features = ["sqlite", "r2d2"] } +diesel_migrations = { version = "2", features = ["sqlite"] } +egs-api = "0.7" +env_logger = "0.11" fs2 = "0.4.3" -gtk4 = { version = "0.6", features = ["v4_8"] } +gtk4 = { version = "0.7.3", features = ["v4_8"] } gtk-macros = "0.3" -html2pango = "0.5" +html2pango = "0.6" lazy_static = "1.4" libsqlite3-sys = { version = "0.25.2", features = ["bundled"] } log = "0.4" @@ -42,10 +43,10 @@ zip = "0.6" winres = "0.1" [target.'cfg(target_os = "windows")'.dependencies] -open = "4" +open = "5.0.0" [target.'cfg(target_os = "linux")'.dependencies] -ashpd = "0.4" +ashpd = "0.6.8" gettext-rs = { version = "0.7", features = ["gettext-system"] } ghregistry = "^0.2" -secret-service = { version = "3.0", features = ["crypto-rust"]} +secret-service = { version = "3.0", features = ["crypto-rust"] } diff --git a/build-aux/io.github.achetagames.epic_asset_manager.Devel.json b/build-aux/io.github.achetagames.epic_asset_manager.Devel.json index c991c86..209928d 100644 --- a/build-aux/io.github.achetagames.epic_asset_manager.Devel.json +++ b/build-aux/io.github.achetagames.epic_asset_manager.Devel.json @@ -16,7 +16,7 @@ "--talk-name=org.freedesktop.secrets", "--talk-name=org.freedesktop.Flatpak", "--device=dri", - "--env=RUST_LOG=epic_asset_manager=trace", + "--env=RUST_LOG=debug,epic_asset_manager=trace,egs-api=trace", "--env=RUST_BACKTRACE=full" ], "build-options": { @@ -49,4 +49,3 @@ } ] } - diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..4400caf --- /dev/null +++ b/build.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +if [ "$1" = "clean" ]; then + rm -rf .~/.cargo/bin/fenv/ .flatpak-builder/ _build/ + ~/.cargo/bin/fenv gen build-aux/io.github.achetagames.epic_asset_manager.Devel.json + ~/.cargo/bin/fenv exec -- meson --prefix=/app -Dprofile=development _build + exit 0 +fi + +if [ "$1" = "build" ]; then + ~/.cargo/bin/fenv exec -- ninja -C _build + exit 0 +fi + +if [ "$1" = "install" ]; then + ~/.cargo/bin/fenv exec -- ninja -C _build install + exit 0 +fi + +if [ "$1" = "dist" ]; then + meson dist -C _build + exit 0 +fi + +~/.cargo/bin/fenv exec -- ninja -C _build install +~/.cargo/bin/fenv run diff --git a/data/io.github.achetagames.epic_asset_manager.metainfo.xml.in.in b/data/io.github.achetagames.epic_asset_manager.metainfo.xml.in.in index edf9f8f..e3a3a62 100644 --- a/data/io.github.achetagames.epic_asset_manager.metainfo.xml.in.in +++ b/data/io.github.achetagames.epic_asset_manager.metainfo.xml.in.in @@ -8,15 +8,15 @@ Manage your Epic assets https://github.com/AchetaGames/Epic-Asset-Manager/raw/main/data/icons/io.github.achetagames.epic_asset_manager.png -

An unofficial client to install Unreal Engine, download and manage purchased assets, projects, plugins and games from the Epic Games Store

-

Features:

- +

An unofficial client to install Unreal Engine, download and manage purchased assets, projects, plugins and games from the Epic Games Store

+

Features:

+
Development @@ -27,11 +27,11 @@ FileTools - unreal - engine - gamedev - assets - epic + unreal + engine + gamedev + assets + epic @@ -64,391 +64,409 @@ https://ko-fi.com/achetagames - - -

Update release

-
    -
  • Gracefully handle corrupted chunk
  • -
  • Update dependencies
  • -
  • Fix actions
  • -
-
-
- - -

Bug fixing

-
    -
  • Handle malformed uproject properly
  • -
  • Fix dependencies and remove git2 dependency
  • -
-
-
- - -

Engine Install fix

-
    -
  • Fix Engine version parsing
  • -
-
-
- - -

Post release fixes

-
    -
  • Fix inability to launch the engine
  • -
  • Remove unnecessary conversion
  • -
  • Cleanup dependencies
  • -
-
-
- - -

GTK update

-
    -
  • Fix engine naming for previews
  • -
  • Update gtk and gtk-rs
  • -
-
-
- - -

Fix OpenDir Panic

-
    -
  • Handle directory open gracefully
  • -
  • Update description
  • -
-
-
- - -

Fix Epic login issue

-
    -
  • Fix Epic login issue, closes #213
  • -
  • Add exit conditions to logs reading threads
  • -
-
-
- - -

Fix EULA validation

-
    -
  • Remove hardcoded account ID
  • -
  • Add more output to EULA verification
  • -
-
-
- - -

Threading fixes

-
    -
  • Add some thread exit conditions
  • -
-
-
- - -

Official Engine Download

-
    -
  • Add official engine download
  • -
  • Add Marketplace button
  • -
  • Add separator between side panels
  • -
  • Rework the Engine install UI
  • -
  • Update the API library
  • -
-
-
- - -

Crash fixes

-
    -
  • Fix cash thumbnail extension
  • -
  • Switch to Texture for image loading, fixes #152, updates #192
  • -
-
-
- - -

Additional Fixes

-
    -
  • Fetch new assets first
  • -
  • Add more details to confirmation
  • -
  • Reverse into directory for space check
  • -
  • Show loading for download size
  • -
-
-
- - -

Minor improvements

-
    -
  • Add timer to refresh
  • -
  • Download chunks to vault
  • -
  • Runtime log level modification
  • -
-
-
- - -

Glibc patch

-
    -
  • Force the GLIBC env variable
  • -
-
-
- - -

GTK bump

-
    -
  • Remove unnecessary variable
  • -
-
-
- - -

Logs Overview

-
    -
  • Log list for Projects and Engines
  • -
  • Open button to Engine and Project
  • -
  • Further improvements of the Secrets fallback
  • -
-
-
- - -

Pause And Cancel

-
    -
  • Local Assets Actions
  • -
  • Show confirmation on engine install
  • -
  • Add cancel and pause buttons to downloads
  • -
-
-
- - -

Secret Fallback

-
    -
  • Add secret service fallback
  • -
-
-
- - -

Library Category rework

-
    -
  • Complete Categories rewrite
  • -
  • Remember the sidebar state on startup
  • -
  • Add sidebar expanded setting
  • -
  • Add sidebar category setting
  • -
-
-
- - -

Category fixes

-
    -
  • Use existing icon for "All" category
  • -
  • Rework category filtering and add some subcategories by default to all
  • -
  • Hide Images if there are no images to show Scale images properly
  • -
  • Add warning message to Engine and Games
  • -
-
-
- - -

Refresh fixes

-
    -
  • Add confirmation on project and engine actions
  • -
  • Clean invalid engines and projects on refresh
  • -
-
-
- - -

Refresh button

-
    -
  • Add refresh button and optimize Engine and Project loading
  • -
  • Update the about dialog
  • -
  • Move the Install Engine button
  • -
-
-
- - -

Dark mode changes

-
    -
  • Add force dark back so the app can be dark while rest of the system is light
  • -
  • Remove Dark Theme button
  • -
  • Do not have engine tab open by default
  • -
-
-
- - -

Further fixes

-
    -
  • Save the manifest to the correct path
  • -
  • Unselect item on details closed
  • -
  • Do not have project selected on start
  • -
  • Close the download manager when you click open directory button
  • -
  • Fix download URL case
  • -
-
-
- - -

Minor fixes

-
    -
  • Update asset item after asset is finished downloading
  • -
  • Create copy of duplicate file for safety
  • -
  • Properly handle failed auth to ghcr
  • -
-
-
- - -

Asset management release

-
    -
  • Add to project functionality
  • -
  • Add open vault directory on already downloaded assets
  • -
  • Add create project functionality
  • -
  • Account for None filter
  • -
  • Add additional details from download manifest
  • -
  • Update to stable gnome 42
  • -
  • Refactor the download manager
  • -
  • Download respects the target download directory
  • -
  • Add progress bar to asset loading
  • -
  • Properly display the initial sorting choice
  • -
  • Fix login issue
  • -
  • Add logout button to the menu
  • -
  • Add target directory selection
  • -
  • Launch the engine properly from inside the flatpak
  • -
  • Add donation link
  • -
  • Load dark mode properly
  • -
  • Add Actions button
  • -
  • Open preferences on a correct page if GitHub token is not set up
  • -
  • Save user details in DB
  • -
-
-
- - -

Dark mode Fix

-
-
- - -

Crash fix

-
    -
  • Remove non-existent property
  • -
-
-
- - -

Fix release

-
    -
  • Fix panic on creating json manifest
  • -
  • Fix build due to libadwaita change
  • -
  • Opening project with engine binary containing space fails.
  • -
  • Fix the dependency to reflect the required ghregistry version
  • -
  • If secret service is not available do not panic but display reasonable messages
  • -
-
-
- - -

Engine install fixes

-
    -
  • Check for disk space before engine install, fixed #126
  • -
  • Fix engine not launching when there is space in the path, fixed #128
  • -
  • Report broken download to the user, fixed #123
  • -
  • Recursively scan for projects, fixed #83
  • -
-
-
- - -

A polish release fixing minor annoyances

-
    -
  • Display available engine details
  • -
  • Display if asset downloaded
  • -
  • Display Category information in assets
  • -
  • Display message instead of GUID on unmatched project
  • -
  • Respect the default_view setting
  • -
  • Add Asset counter
  • -
  • Add visual indication of categories
  • -
  • Windows build
  • -
-
-
- - -

Add notifications and implement them in couple places

-
-
- - -

Added Dark Mode

-
-
- - -

Fix crashes on XFCE

-
-
- - -

Change ghregistry from github to crates.io

-
-
- - -

Install Engine from Docker

-
    -
  • Fix the previous button enabled on empty images
  • -
-
-
- - -

Asset Sorting

-
    -
  • FIX: Correctly quit the application on exit
  • -
-
-
- - -

UI Improvements

-
    -
  • Use different(random) CDNs for download
  • -
-
-
- - -

Add favorites functionality

-
    -
  • Better code organisation
  • -
  • Add database
  • -
-
-
- - -

Add Engine and Project sections

-
    -
  • FIX: Redownload chunk if the download fails
  • -
  • FIX: assets not loading after the initial login
  • -
  • Discover engines and check if they can be updated
  • -
  • Load engines from configured directories
  • -
  • Load projects and display them
  • -
  • Launch a project if able
  • -
  • Remember last used engine
  • -
  • Remove the Unreal logo from the icon
  • -
-
-
+ + +

Fix asset downloading

+
    +
  • Update egs-api to the fixed version
  • +
  • Fix tokio changes
  • +
  • update env-logger
  • +
  • Update byte-unit
  • +
  • Add manual download instructions
  • +
  • Update crates and fix code
  • +
  • Add configuration files
  • +
  • Add more debug messages
  • +
  • Fix deprecations and clippy
  • +
  • Update dependencies
  • +
  • Update actions to latest gnome image
  • +
+
+
+ + +

Update release

+
    +
  • Gracefully handle corrupted chunk
  • +
  • Update dependencies
  • +
  • Fix actions
  • +
+
+
+ + +

Bug fixing

+
    +
  • Handle malformed uproject properly
  • +
  • Fix dependencies and remove git2 dependency
  • +
+
+
+ + +

Engine Install fix

+
    +
  • Fix Engine version parsing
  • +
+
+
+ + +

Post release fixes

+
    +
  • Fix inability to launch the engine
  • +
  • Remove unnecessary conversion
  • +
  • Cleanup dependencies
  • +
+
+
+ + +

GTK update

+
    +
  • Fix engine naming for previews
  • +
  • Update gtk and gtk-rs
  • +
+
+
+ + +

Fix OpenDir Panic

+
    +
  • Handle directory open gracefully
  • +
  • Update description
  • +
+
+
+ + +

Fix Epic login issue

+
    +
  • Fix Epic login issue, closes #213
  • +
  • Add exit conditions to logs reading threads
  • +
+
+
+ + +

Fix EULA validation

+
    +
  • Remove hardcoded account ID
  • +
  • Add more output to EULA verification
  • +
+
+
+ + +

Threading fixes

+
    +
  • Add some thread exit conditions
  • +
+
+
+ + +

Official Engine Download

+
    +
  • Add official engine download
  • +
  • Add Marketplace button
  • +
  • Add separator between side panels
  • +
  • Rework the Engine install UI
  • +
  • Update the API library
  • +
+
+
+ + +

Crash fixes

+
    +
  • Fix cash thumbnail extension
  • +
  • Switch to Texture for image loading, fixes #152, updates #192
  • +
+
+
+ + +

Additional Fixes

+
    +
  • Fetch new assets first
  • +
  • Add more details to confirmation
  • +
  • Reverse into directory for space check
  • +
  • Show loading for download size
  • +
+
+
+ + +

Minor improvements

+
    +
  • Add timer to refresh
  • +
  • Download chunks to vault
  • +
  • Runtime log level modification
  • +
+
+
+ + +

Glibc patch

+
    +
  • Force the GLIBC env variable
  • +
+
+
+ + +

GTK bump

+
    +
  • Remove unnecessary variable
  • +
+
+
+ + +

Logs Overview

+
    +
  • Log list for Projects and Engines
  • +
  • Open button to Engine and Project
  • +
  • Further improvements of the Secrets fallback
  • +
+
+
+ + +

Pause And Cancel

+
    +
  • Local Assets Actions
  • +
  • Show confirmation on engine install
  • +
  • Add cancel and pause buttons to downloads
  • +
+
+
+ + +

Secret Fallback

+
    +
  • Add secret service fallback
  • +
+
+
+ + +

Library Category rework

+
    +
  • Complete Categories rewrite
  • +
  • Remember the sidebar state on startup
  • +
  • Add sidebar expanded setting
  • +
  • Add sidebar category setting
  • +
+
+
+ + +

Category fixes

+
    +
  • Use existing icon for "All" category
  • +
  • Rework category filtering and add some subcategories by default to all
  • +
  • Hide Images if there are no images to show Scale images properly
  • +
  • Add warning message to Engine and Games
  • +
+
+
+ + +

Refresh fixes

+
    +
  • Add confirmation on project and engine actions
  • +
  • Clean invalid engines and projects on refresh
  • +
+
+
+ + +

Refresh button

+
    +
  • Add refresh button and optimize Engine and Project loading
  • +
  • Update the about dialog
  • +
  • Move the Install Engine button
  • +
+
+
+ + +

Dark mode changes

+
    +
  • Add force dark back so the app can be dark while rest of the system is light
  • +
  • Remove Dark Theme button
  • +
  • Do not have engine tab open by default
  • +
+
+
+ + +

Further fixes

+
    +
  • Save the manifest to the correct path
  • +
  • Unselect item on details closed
  • +
  • Do not have project selected on start
  • +
  • Close the download manager when you click open directory button
  • +
  • Fix download URL case
  • +
+
+
+ + +

Minor fixes

+
    +
  • Update asset item after asset is finished downloading
  • +
  • Create copy of duplicate file for safety
  • +
  • Properly handle failed auth to ghcr
  • +
+
+
+ + +

Asset management release

+
    +
  • Add to project functionality
  • +
  • Add open vault directory on already downloaded assets
  • +
  • Add create project functionality
  • +
  • Account for None filter
  • +
  • Add additional details from download manifest
  • +
  • Update to stable gnome 42
  • +
  • Refactor the download manager
  • +
  • Download respects the target download directory
  • +
  • Add progress bar to asset loading
  • +
  • Properly display the initial sorting choice
  • +
  • Fix login issue
  • +
  • Add logout button to the menu
  • +
  • Add target directory selection
  • +
  • Launch the engine properly from inside the flatpak
  • +
  • Add donation link
  • +
  • Load dark mode properly
  • +
  • Add Actions button
  • +
  • Open preferences on a correct page if GitHub token is not set up
  • +
  • Save user details in DB
  • +
+
+
+ + +

Dark mode Fix

+
+
+ + +

Crash fix

+
    +
  • Remove non-existent property
  • +
+
+
+ + +

Fix release

+
    +
  • Fix panic on creating json manifest
  • +
  • Fix build due to libadwaita change
  • +
  • Opening project with engine binary containing space fails.
  • +
  • Fix the dependency to reflect the required ghregistry version
  • +
  • If secret service is not available do not panic but display reasonable messages
  • +
+
+
+ + +

Engine install fixes

+
    +
  • Check for disk space before engine install, fixed #126
  • +
  • Fix engine not launching when there is space in the path, fixed #128
  • +
  • Report broken download to the user, fixed #123
  • +
  • Recursively scan for projects, fixed #83
  • +
+
+
+ + +

A polish release fixing minor annoyances

+
    +
  • Display available engine details
  • +
  • Display if asset downloaded
  • +
  • Display Category information in assets
  • +
  • Display message instead of GUID on unmatched project
  • +
  • Respect the default_view setting
  • +
  • Add Asset counter
  • +
  • Add visual indication of categories
  • +
  • Windows build
  • +
+
+
+ + +

Add notifications and implement them in couple places

+
+
+ + +

Added Dark Mode

+
+
+ + +

Fix crashes on XFCE

+
+
+ + +

Change ghregistry from github to crates.io

+
+
+ + +

Install Engine from Docker

+
    +
  • Fix the previous button enabled on empty images
  • +
+
+
+ + +

Asset Sorting

+
    +
  • FIX: Correctly quit the application on exit
  • +
+
+
+ + +

UI Improvements

+
    +
  • Use different(random) CDNs for download
  • +
+
+
+ + +

Add favorites functionality

+
    +
  • Better code organisation
  • +
  • Add database
  • +
+
+
+ + +

Add Engine and Project sections

+
    +
  • FIX: Redownload chunk if the download fails
  • +
  • FIX: assets not loading after the initial login
  • +
  • Discover engines and check if they can be updated
  • +
  • Load engines from configured directories
  • +
  • Load projects and display them
  • +
  • Launch a project if able
  • +
  • Remember last used engine
  • +
  • Remove the Unreal logo from the icon
  • +
+
+

Initial asset load fix

diff --git a/data/resources/ui/logged_in/engines/epic_download.ui b/data/resources/ui/logged_in/engines/epic_download.ui index 5237553..a91bab7 100644 --- a/data/resources/ui/logged_in/engines/epic_download.ui +++ b/data/resources/ui/logged_in/engines/epic_download.ui @@ -104,33 +104,57 @@ Invalid - 5 + vertical - - emblem-important-symbolic - Valid + + 5 + + + emblem-important-symbolic + Valid + + + + + 0 + Please sign the EULA to continue + + + + + epic_download.browser + https://www.unrealengine.com/en-US/eulacheck/unreal + 1 + help-browser-symbolic + + + + + epic_download.revalidate_eula + Revalidate + 1 + view-refresh-symbolic + + - - 0 - Please sign the EULA to continue - - - - - epic_download.browser - https://www.unrealengine.com/en-US/eulacheck/unreal - 1 - help-browser-symbolic - - - - - epic_download.revalidate_eula - Revalidate - 1 - view-refresh-symbolic + + 5 + + + 0 + Or download manually + + + + + epic_download.download + https://www.unrealengine.com/linux + 1 + help-browser-symbolic + + diff --git a/meson.build b/meson.build index b4a7f1f..0021002 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('epic_asset_manager', 'rust', - version: '3.8.4', + version: '3.8.5', license: 'MIT', meson_version: '>= 0.59') diff --git a/src/application.rs b/src/application.rs index 9251998..54cd1a8 100644 --- a/src/application.rs +++ b/src/application.rs @@ -195,7 +195,7 @@ impl EpicAssetManager { let is_dark_mode = self_.settings.boolean("dark-mode"); let simple_action = - gio::SimpleAction::new_stateful("dark-mode", None, is_dark_mode.to_variant()); + gio::SimpleAction::new_stateful("dark-mode", None, &is_dark_mode.to_variant()); simple_action.connect_activate(clone!(@weak self as app => move |action, _| { app.toggle_dark_mode(action); })); @@ -225,7 +225,7 @@ impl EpicAssetManager { let state = action.state().unwrap(); let action_state: bool = state.get().unwrap(); let is_dark_mode = !action_state; - action.set_state(is_dark_mode.to_variant()); + action.set_state(&is_dark_mode.to_variant()); if let Err(err) = self_.settings.set_boolean("dark-mode", is_dark_mode) { error!("Failed to switch dark mode: {} ", err); } @@ -243,7 +243,7 @@ impl EpicAssetManager { let provider = gtk4::CssProvider::new(); provider.load_from_resource("/io/github/achetagames/epic_asset_manager/style.css"); if let Some(display) = gdk::Display::default() { - gtk4::StyleContext::add_provider_for_display( + gtk4::style_context_add_provider_for_display( &display, &provider, gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION, diff --git a/src/models/asset_data.rs b/src/models/asset_data.rs index 04111c7..6b24120 100644 --- a/src/models/asset_data.rs +++ b/src/models/asset_data.rs @@ -347,7 +347,7 @@ impl AssetData { pub fn downloaded_locations(directories: &glib::StrV, asset_id: &str) -> Vec { let mut result: Vec = Vec::new(); for directory in directories { - let mut path = std::path::PathBuf::from(directory.to_str()); + let mut path = std::path::PathBuf::from(directory.as_str()); path.push(asset_id); path.push("data"); if path.exists() { diff --git a/src/models/category_data.rs b/src/models/category_data.rs index 9f040fa..d40c47c 100644 --- a/src/models/category_data.rs +++ b/src/models/category_data.rs @@ -94,10 +94,10 @@ glib::wrapper! { impl CategoryData { pub fn new(name: &str, filter: &str, path: &str, leaf: bool) -> CategoryData { glib::Object::builder() - .property("name", &name) - .property("filter", &filter) - .property("path", &path) - .property("leaf", &leaf) + .property("name", name) + .property("filter", filter) + .property("path", path) + .property("leaf", leaf) .build() } diff --git a/src/models/engine_data.rs b/src/models/engine_data.rs index f076b02..f0cd2e5 100644 --- a/src/models/engine_data.rs +++ b/src/models/engine_data.rs @@ -1,4 +1,3 @@ -use glib::clone; use glib::ObjectExt; use gtk4::{glib, prelude::*, subclass::prelude::*}; use serde::{Deserialize, Serialize}; @@ -97,8 +96,8 @@ mod imp { updatable: RefCell, has_branch: RefCell, pub ueversion: RefCell>, - pub sender: glib::Sender, - pub receiver: RefCell>>, + pub sender: async_channel::Sender, + pub receiver: RefCell>>, pub model: OnceCell, pub position: OnceCell, } @@ -110,7 +109,7 @@ mod imp { type Type = super::EngineData; fn new() -> Self { - let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); + let (sender, receiver) = async_channel::unbounded(); Self { guid: RefCell::new(None), path: RefCell::new(None), @@ -229,8 +228,8 @@ impl EngineData { let self_ = data.imp(); self_.position.set(model.n_items()).unwrap(); self_.model.set(model.clone()).unwrap(); - data.set_property("path", &path); - data.set_property("guid", &guid); + data.set_property("path", path); + data.set_property("guid", guid); self_.ueversion.replace(Some(version.clone())); data.set_property("version", version.format()); if let Some(path) = data.path() { @@ -259,13 +258,12 @@ impl EngineData { pub fn setup_messaging(&self) { let self_ = self.imp(); let receiver = self_.receiver.borrow_mut().take().unwrap(); - receiver.attach( - None, - clone!(@weak self as engine => @default-panic, move |msg| { - engine.update(msg); - glib::Continue(true) - }), - ); + let engine = self.clone(); + glib::spawn_future_local(async move { + while let Ok(response) = receiver.recv().await { + engine.update(response); + } + }); } pub fn update(&self, msg: Msg) { @@ -282,7 +280,7 @@ impl EngineData { } #[allow(clippy::missing_const_for_fn)] - fn needs_repo_update(_path: &str, _sender: &Option>) -> bool { + fn needs_repo_update(_path: &str, _sender: &Option>) -> bool { // #[cfg(target_os = "linux")] // This is disabled due to issues with git2 crate and constant need to rebuild if git lib gets updated // { diff --git a/src/models/log_data.rs b/src/models/log_data.rs index dcb3dd9..5f2b699 100644 --- a/src/models/log_data.rs +++ b/src/models/log_data.rs @@ -96,8 +96,8 @@ glib::wrapper! { impl LogData { pub fn new(path: &str, name: &str, crash: bool) -> LogData { let data: Self = glib::Object::new::(); - data.set_property("path", &path); - data.set_property("name", &name); + data.set_property("path", path); + data.set_property("name", name); data.set_property("crash", crash); data } diff --git a/src/models/mod.rs b/src/models/mod.rs index 60743a1..48b40bb 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -9,7 +9,7 @@ pub mod project_data; use crate::config::APP_ID; use egs_api::EpicGames; use gtk4::gio; -use gtk4::glib::{MainContext, Receiver, Sender, UserDirectory, PRIORITY_DEFAULT}; +use gtk4::glib::{MainContext, Priority, Receiver, Sender, UserDirectory}; use gtk4::prelude::*; use log::{debug, error, info, warn}; use std::cell::RefCell; @@ -38,7 +38,7 @@ impl Default for Model { impl Model { pub fn new() -> Self { - let (sender, receiver) = MainContext::channel(PRIORITY_DEFAULT); + let (sender, receiver) = MainContext::channel(Priority::default()); let mut obj = Self { epic_games: RefCell::new(EpicGames::new()), #[cfg(target_os = "linux")] @@ -184,9 +184,9 @@ impl Model { let mut ud = egs_api::api::types::account::UserData::new(); for item in items { let Ok(label) = item.get_label() else { - debug!("No label skipping"); - continue; - }; + debug!("No label skipping"); + continue; + }; debug!("Loading: {}", label); if let Ok(attributes) = item.get_attributes() { match label.as_str() { diff --git a/src/models/plugin_data.rs b/src/models/plugin_data.rs index 0c33dfd..d591143 100644 --- a/src/models/plugin_data.rs +++ b/src/models/plugin_data.rs @@ -1,5 +1,4 @@ use glib::ObjectExt; -use gtk4::glib::clone; use gtk4::{self, glib, subclass::prelude::*}; use log::debug; use serde::{Deserialize, Serialize}; @@ -118,8 +117,8 @@ mod imp { path: RefCell>, name: RefCell>, pub uplugin: RefCell>, - pub sender: glib::Sender, - pub receiver: RefCell>>, + pub sender: async_channel::Sender, + pub receiver: RefCell>>, } // Basic declaration of our type for the GObject type system @@ -130,7 +129,7 @@ mod imp { type ParentType = glib::Object; fn new() -> Self { - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = async_channel::unbounded(); Self { guid: RefCell::new(None), path: RefCell::new(None), @@ -216,8 +215,8 @@ glib::wrapper! { impl PluginData { pub fn new(path: &str, name: &str) -> PluginData { let data: Self = glib::Object::new(); - data.set_property("path", &path); - data.set_property("name", &name); + data.set_property("path", path); + data.set_property("name", name); data } @@ -252,16 +251,15 @@ impl PluginData { pub fn setup_messaging(&self) { let self_ = self.imp(); let receiver = self_.receiver.borrow_mut().take().unwrap(); - receiver.attach( - None, - clone!(@weak self as project => @default-panic, move |msg| { - project.update(&msg); - glib::Continue(true) - }), - ); + let project = self.clone(); + glib::spawn_future_local(async move { + while let Ok(response) = receiver.recv().await { + project.update(response); + } + }); } - pub fn update(&self, _msg: &Msg) { + pub fn update(&self, _msg: Msg) { debug!("Update for {:?}", self.name()); } } diff --git a/src/models/project_data.rs b/src/models/project_data.rs index 9065de8..c0cd74c 100644 --- a/src/models/project_data.rs +++ b/src/models/project_data.rs @@ -42,7 +42,7 @@ mod imp { use super::*; use glib::ToValue; use gtk4::gdk::Texture; - use gtk4::glib::{ParamSpec, ParamSpecObject, ParamSpecString}; + use gtk4::glib::{ParamSpec, ParamSpecObject, ParamSpecString, Priority}; use std::cell::RefCell; // The actual data structure that stores our values. This is not accessible @@ -66,7 +66,7 @@ mod imp { type ParentType = glib::Object; fn new() -> Self { - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); Self { guid: RefCell::new(None), path: RefCell::new(None), @@ -162,8 +162,8 @@ impl ProjectData { pub fn new(path: &str, name: &str) -> ProjectData { let data: Self = glib::Object::new::(); let self_ = data.imp(); - data.set_property("path", &path); - data.set_property("name", &name); + data.set_property("path", path); + data.set_property("name", name); let mut uproject = Self::read_uproject(path); uproject.engine_association = uproject .engine_association @@ -225,7 +225,7 @@ impl ProjectData { None, clone!(@weak self as project => @default-panic, move |msg| { project.update(msg); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } diff --git a/src/tools/epic_web.rs b/src/tools/epic_web.rs index 730b9d2..37b93c5 100644 --- a/src/tools/epic_web.rs +++ b/src/tools/epic_web.rs @@ -137,7 +137,7 @@ impl EpicWeb { pub fn validate_eula(&self, id: &str) -> bool { let mut map = HashMap::new(); - let query= vec!["{ Eula { hasAccountAccepted(id: \"unreal_engine\", locale: \"en\", accountId: \"", id, "\"){ accepted key locale version } }}"]; + let query= ["{ Eula { hasAccountAccepted(id: \"unreal_engine\", locale: \"en\", accountId: \"", id, "\"){ accepted key locale version } }}"]; map.insert("query", query.join("")); match self .client @@ -155,9 +155,9 @@ impl EpicWeb { Ok(eula) => { return match eula.data.eula.has_account_accepted { None => { - eula.errors.map_or((), |errors| for error in errors { - error!("Failed to query EULA status: {} with response: {}", error.message, error.service_response); - }); + let _ = eula.errors.map_or((), |errors| for error in errors { + error!("Failed to query EULA status: {} with response: {}", error.message, error.service_response); + }); false } Some(accepted) => accepted.accepted, diff --git a/src/ui/authentication.rs b/src/ui/authentication.rs index db37080..398eac4 100644 --- a/src/ui/authentication.rs +++ b/src/ui/authentication.rs @@ -4,7 +4,7 @@ use gtk4::prelude::SettingsExt; use gtk4::subclass::prelude::ObjectSubclassIsExt; use log::debug; use std::thread; -use tokio::runtime::Runtime; +use tokio::runtime::Builder; impl EpicAssetManagerWindow { pub fn login(&self, sid: String) { @@ -16,7 +16,9 @@ impl EpicAssetManagerWindow { let mut eg = self_.model.borrow().epic_games.borrow().clone(); thread::spawn(move || { let start = std::time::Instant::now(); - if Runtime::new() + if Builder::new_current_thread() + .enable_all() + .build() .unwrap() .block_on(eg.auth_code(None, Some(s))) { @@ -88,7 +90,12 @@ impl EpicAssetManagerWindow { let mut eg = self_.model.borrow().epic_games.borrow().clone(); thread::spawn(move || { let start = std::time::Instant::now(); - if Runtime::new().unwrap().block_on(eg.login()) { + if Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(eg.login()) + { sender .send(crate::ui::messages::Msg::LoginOk(eg.user_details())) .unwrap(); @@ -113,7 +120,11 @@ impl EpicAssetManagerWindow { let mut eg = self_.model.borrow().epic_games.borrow().clone(); thread::spawn(move || { - Runtime::new().unwrap().block_on(eg.logout()); + Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(eg.logout()); sender.send(crate::ui::messages::Msg::Logout).unwrap(); }); } diff --git a/src/ui/widgets/download_manager/asset.rs b/src/ui/widgets/download_manager/asset.rs index b934192..e631657 100644 --- a/src/ui/widgets/download_manager/asset.rs +++ b/src/ui/widgets/download_manager/asset.rs @@ -1,10 +1,9 @@ use crate::tools::asset_info::Search; use crate::ui::widgets::download_manager::Msg::CancelChunk; use crate::ui::widgets::download_manager::{Msg, PostDownloadAction, ThreadMessages}; -use egs_api::api::types::chunk::Chunk; use glib::clone; use gtk4::glib; -use gtk4::glib::Sender; +use gtk4::glib::{Priority, Sender}; use gtk4::subclass::prelude::*; use gtk4::{self, prelude::*}; use log::{debug, error, info, warn}; @@ -13,10 +12,12 @@ use reqwest::Url; use sha1::digest::core_api::CoreWrapper; use sha1::{Digest, Sha1, Sha1Core}; use std::ffi::OsString; +use std::fmt::Write; use std::fs::File; -use std::io::{Read, Write}; +use std::io::Read; use std::path::{Path, PathBuf}; use std::str::FromStr; +use tokio::runtime::Builder; #[derive(Default, Debug, Clone)] pub struct DownloadedFile { @@ -36,7 +37,7 @@ pub trait Asset { _release_id: String, _asset: egs_api::api::types::asset_info::AssetInfo, _target: &Option, - _actions: Option>, + _actions: Option>, ) { unimplemented!() } @@ -77,12 +78,12 @@ pub trait Asset { unimplemented!() } - fn redownload_chunk(&self, _link: &reqwest::Url, _p: PathBuf, _g: &str) { + fn redownload_chunk(&self, _link: &Url, _p: PathBuf, _g: &str) { unimplemented!() } /// Download Chunks - fn download_chunk(&self, _link: reqwest::Url, _p: PathBuf, _g: String) { + fn download_chunk(&self, _link: Url, _p: PathBuf, _g: String) { unimplemented!() } @@ -156,7 +157,7 @@ impl Asset for super::EpicDownloadManager { release_id: String, asset: egs_api::api::types::asset_info::AssetInfo, target: &Option, - actions: Option>, + actions: Option>, ) { debug!("Adding download: {:?}", asset.title); @@ -206,7 +207,7 @@ impl Asset for super::EpicDownloadManager { }), ); - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = glib::MainContext::channel(Priority::default()); receiver.attach( None, @@ -214,7 +215,7 @@ impl Asset for super::EpicDownloadManager { let self_ = download_manager.imp(); let sender = self_.sender.clone(); sender.send(super::Msg::StartAssetDownload(id, manifest)).unwrap(); - glib::Continue(true) + glib::ControlFlow::Continue }), ); @@ -242,19 +243,22 @@ impl Asset for super::EpicDownloadManager { } let start = std::time::Instant::now(); if let Some(release_info) = asset.release_info(&release_id) { - if let Some(manifest) = - tokio::runtime::Runtime::new() - .unwrap() - .block_on(eg.asset_manifest( - None, - None, - Some(asset.namespace), - Some(asset.id), - Some(release_info.app_id.unwrap_or_default()), - )) + if let Some(manifest) = Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(eg.asset_manifest( + None, + None, + Some(asset.namespace), + Some(asset.id), + Some(release_info.app_id.unwrap_or_default()), + )) { debug!("Got asset manifest: {:?}", manifest); - let d = tokio::runtime::Runtime::new() + let d = Builder::new_current_thread() + .enable_all() + .build() .unwrap() .block_on(eg.asset_download_manifests(manifest)); debug!("Got asset download manifests for {}", id); @@ -275,7 +279,9 @@ impl Asset for super::EpicDownloadManager { dm: &[egs_api::api::types::download_manifest::DownloadManifest], ) { let self_ = self.imp(); - let Some(item) = self.get_item(id) else { return }; + let Some(item) = self.get_item(id) else { + return; + }; if dm.is_empty() { item.set_property("status", "Failed to get download manifests".to_string()); return; @@ -351,6 +357,7 @@ impl Asset for super::EpicDownloadManager { let m = manifest.clone(); let full_path = target.clone().as_path().join(filename); + self_.download_pool.execute(move || { initiate_file_download(&r_id, &r_name, &f_name, &sender, m, &full_path); }); @@ -366,8 +373,11 @@ impl Asset for super::EpicDownloadManager { filename: String, manifest: egs_api::api::types::download_manifest::FileManifestList, ) { + info!("Downloading file {} for {}", filename, id); let self_ = self.imp(); - let Some(_item) = self.get_item(&id) else { return }; + let Some(_item) = self.get_item(&id) else { + return; + }; let vaults = self_.settings.strv("unreal-vault-directories"); let mut target = std::path::PathBuf::from(vaults.first().map_or_else( || { @@ -405,23 +415,24 @@ impl Asset for super::EpicDownloadManager { match chunks.get_mut(&chunk.guid) { None => { chunks.insert(chunk.guid.clone(), vec![full_filename.clone()]); + info!("Inserting file into chunk init {}", full_filename.clone()); let mut p = target.clone(); let g = chunk.guid.clone(); p.push(format!("{g}.chunk")); sender - .send(super::Msg::RedownloadChunk( - reqwest::Url::parse("unix:/").unwrap(), - p, - g, - )) + .send(Msg::RedownloadChunk(Url::parse("unix:/").unwrap(), p, g)) .unwrap(); } - Some(files) => files.push(full_filename.clone()), + Some(files) => { + files.push(full_filename.clone()); + info!("Inserting file into chunk {}", full_filename.clone()); + } } + info!("Chunks length: {}", chunks.len()); } } - fn redownload_chunk(&self, link: &reqwest::Url, p: PathBuf, g: &str) { + fn redownload_chunk(&self, link: &Url, p: PathBuf, g: &str) { let self_ = self.imp(); let sender = self_.sender.clone(); let mut chunks = self_.chunk_urls.borrow_mut(); @@ -429,11 +440,7 @@ impl Asset for super::EpicDownloadManager { None => { // Unable to get chunk urls sender - .send(super::Msg::PerformChunkDownload( - link.clone(), - p, - g.to_string(), - )) + .send(Msg::PerformChunkDownload(link.clone(), p, g.to_string())) .unwrap(); } Some(v) => { @@ -442,7 +449,7 @@ impl Asset for super::EpicDownloadManager { // No other URL available, redownloading //TODO: This has the potential to loop forever sender - .send(super::Msg::PerformChunkDownload( + .send(Msg::PerformChunkDownload( link.clone(), p.clone(), g.to_string(), @@ -451,26 +458,18 @@ impl Asset for super::EpicDownloadManager { }; let mut rng = rand::thread_rng(); let index = rng.gen_range(0..v.len()); - let new: Option<&reqwest::Url> = v.get(index); + let new: Option<&Url> = v.get(index); match new { None => { // Unable to get random URL, retrying the same one sender - .send(super::Msg::PerformChunkDownload( - link.clone(), - p, - g.to_string(), - )) + .send(Msg::PerformChunkDownload(link.clone(), p, g.to_string())) .unwrap(); } Some(u) => { // Using new url to redownload the chunk sender - .send(super::Msg::PerformChunkDownload( - u.clone(), - p, - g.to_string(), - )) + .send(Msg::PerformChunkDownload(u.clone(), p, g.to_string())) .unwrap(); } } @@ -479,12 +478,12 @@ impl Asset for super::EpicDownloadManager { } /// Download Chunks - fn download_chunk(&self, link: reqwest::Url, p: PathBuf, g: String) { + fn download_chunk(&self, link: Url, p: PathBuf, g: String) { let self_ = self.imp(); if !link.has_host() { return; } - let (send, recv) = std::sync::mpsc::channel::(); + let (send, recv) = std::sync::mpsc::channel::(); self.add_thread_sender(g.clone(), send); let sender = self_.sender.clone(); self_.download_pool.execute(move || { @@ -509,11 +508,7 @@ impl Asset for super::EpicDownloadManager { Err(e) => { error!("Failed to start chunk download, trying again later: {}", e); sender - .send(super::Msg::RedownloadChunk( - link.clone(), - p.clone(), - g.clone(), - )) + .send(Msg::RedownloadChunk(link.clone(), p.clone(), g.clone())) .unwrap(); return; } @@ -534,13 +529,9 @@ impl Asset for super::EpicDownloadManager { } if size > 0 { downloaded += size as u128; - file.write_all(&buffer[0..size]).unwrap(); + std::io::Write::write_all(&mut file, &buffer[0..size]).unwrap(); sender - .send(super::Msg::ChunkDownloadProgress( - g.clone(), - size as u128, - false, - )) + .send(Msg::ChunkDownloadProgress(g.clone(), size as u128, false)) .unwrap(); } else { break; @@ -553,11 +544,7 @@ impl Asset for super::EpicDownloadManager { } } sender - .send(super::Msg::ChunkDownloadProgress( - g.clone(), - downloaded, - true, - )) + .send(Msg::ChunkDownloadProgress(g.clone(), downloaded, true)) .unwrap(); }); } @@ -602,8 +589,8 @@ impl Asset for super::EpicDownloadManager { for file in files { if let Some(f) = self_.downloaded_files.borrow_mut().get_mut(file) { let Some(item) = self.get_item(&f.asset) else { - break; - }; + break; + }; item.add_downloaded_size(progress); self.emit_by_name::<()>("tick", &[]); break; @@ -628,7 +615,9 @@ impl Asset for super::EpicDownloadManager { filename: String, ) { let self_ = self.imp(); - let Some(item) = self.get_item(&asset_id) else { return; }; + let Some(item) = self.get_item(&asset_id) else { + return; + }; let mut targets: Vec<(String, bool)> = Vec::new(); { @@ -647,10 +636,7 @@ impl Asset for super::EpicDownloadManager { item.add_downloaded_size(progress); self.emit_by_name::<()>("tick", &[]); - self_ - .sender - .send(super::Msg::FileExtracted(asset_id)) - .unwrap(); + self_.sender.send(Msg::FileExtracted(asset_id)).unwrap(); } fn pause_asset_download(&self, asset: String) { @@ -766,16 +752,12 @@ fn process_thread_message(link: &Url, p: &Path, g: &str, sender: &Sender, m match m { ThreadMessages::Cancel => { sender - .send(super::Msg::CancelChunk( - link.clone(), - p.to_path_buf(), - g.to_string(), - )) + .send(CancelChunk(link.clone(), p.to_path_buf(), g.to_string())) .unwrap(); } ThreadMessages::Pause => { sender - .send(super::Msg::PauseChunk( + .send(Msg::PauseChunk( link.clone(), p.to_path_buf(), g.to_string(), @@ -816,9 +798,7 @@ fn save_asset_manifest( match File::create(tar.join("manifest.json")) { Ok(mut json_manifest_file) => match serde_json::to_string(&manifest) { Ok(json) => { - json_manifest_file - .write_all(json.as_bytes().as_ref()) - .unwrap(); + std::io::Write::write_all(&mut json_manifest_file, json.as_bytes()).unwrap(); } Err(e) => { error!("Unable to save json manifest: {}", e); @@ -830,7 +810,7 @@ fn save_asset_manifest( } match File::create(tar.join("manifest")) { Ok(mut manifest_file) => { - manifest_file.write_all(&manifest.to_vec()).unwrap(); + std::io::Write::write_all(&mut manifest_file, &manifest.to_vec()).unwrap(); } Err(e) => { error!("Unable to save binary Manifest: {:?}", e); @@ -842,10 +822,11 @@ fn initiate_file_download( r_id: &str, r_name: &str, f_name: &str, - sender: &Sender, + sender: &Sender, m: egs_api::api::types::download_manifest::FileManifestList, full_path: &Path, ) { + debug!("Initiating file download: {}", f_name); if let Ok(w) = crate::RUNNING.read() { if !*w { return; @@ -866,10 +847,13 @@ fn initiate_file_download( } let hash = hasher.finalize(); if m.file_hash - .eq(&hash.iter().map(|b| format!("{b:02x}")).collect::()) + .eq(&hash.iter().fold(String::new(), |mut output, b| { + write!(output, "{b:02x}").unwrap(); + output + })) { sender - .send(super::Msg::FileAlreadyDownloaded( + .send(Msg::FileAlreadyDownloaded( r_id.to_string(), m.size(), full_path.to_str().unwrap().to_string(), @@ -879,7 +863,7 @@ fn initiate_file_download( } else { warn!("Hashes do not match, downloading again: {:?}", full_path); sender - .send(super::Msg::PerformAssetDownload( + .send(Msg::PerformAssetDownload( r_id.to_string(), r_name.to_string(), f_name.to_string(), @@ -891,7 +875,7 @@ fn initiate_file_download( // File does not exist perform download Err(_) => { sender - .send(super::Msg::PerformAssetDownload( + .send(Msg::PerformAssetDownload( r_id.to_string(), r_name.to_string(), f_name.to_string(), @@ -929,7 +913,7 @@ impl AssetPriv for super::EpicDownloadManager { cache_path.as_path(), )) { Ok(t) => sender - .send(super::Msg::ProcessItemThumbnail(id.clone(), t)) + .send(Msg::ProcessItemThumbnail(id.clone(), t)) .unwrap(), Err(e) => { error!("Unable to load file to texture: {}", e); @@ -1015,14 +999,14 @@ impl AssetPriv for super::EpicDownloadManager { extract_chunks(finished.chunks, &temp.clone(), &mut target).finalize(); if finished .hash - .eq(&hash.iter().map(|b| format!("{b:02x}")).collect::()) + .eq(&hash.iter().fold(String::new(), |mut output, b| { + write!(output, "{b:02x}").unwrap(); + output + })) { copy_files(&vault.clone(), targets, &finished.name); sender - .send(super::Msg::FinalizeFileDownload( - file_c.to_string(), - f_c.clone(), - )) + .send(Msg::FinalizeFileDownload(file_c.to_string(), f_c.clone())) .unwrap(); } else { error!("Failed to validate hash on: {:?}", vault); @@ -1068,11 +1052,11 @@ fn extract_chunks( }; hasher .update(&ch.data[chunk.offset as usize..(chunk.offset + chunk.size) as usize]); - target - .write_all( - &ch.data[chunk.offset as usize..(chunk.offset + chunk.size) as usize], - ) - .unwrap(); + std::io::Write::write_all( + target, + &ch.data[chunk.offset as usize..(chunk.offset + chunk.size) as usize], + ) + .unwrap(); } Err(e) => { error!("Error opening the chunk file: {:?}", e); diff --git a/src/ui/widgets/download_manager/docker.rs b/src/ui/widgets/download_manager/docker.rs index 3353bf1..3615197 100644 --- a/src/ui/widgets/download_manager/docker.rs +++ b/src/ui/widgets/download_manager/docker.rs @@ -78,8 +78,8 @@ impl Docker for crate::ui::widgets::download_manager::EpicDownloadManager { fn perform_docker_blob_downloads(&self, version: &str, size: u64, digests: Vec<(String, u64)>) { let self_ = self.imp(); let Some(item) = self.get_item(version) else { - return; - }; + return; + }; item.set_property("status", "waiting for download slot".to_string()); item.set_total_size(u128::from(size)); item.set_total_files(digests.len() as u64); @@ -114,7 +114,9 @@ impl Docker for crate::ui::widgets::download_manager::EpicDownloadManager { let client = dclient.clone(); let sender = self_.sender.clone(); let pool = self_.download_pool.clone(); - let Some(target) = self.docker_target_directory() else { return }; + let Some(target) = self.docker_target_directory() else { + return; + }; debug!("Going to download to {:?}", target); let (send, recv) = std::sync::mpsc::channel::(); self.add_thread_sender(ver.clone(), send); @@ -173,7 +175,9 @@ impl Docker for crate::ui::widgets::download_manager::EpicDownloadManager { } #[cfg(target_os = "linux")] fn cancel_docker_digest(&self, _version: &str, digest: (String, u64)) { - let Some(mut target) = self.docker_target_directory() else { return }; + let Some(mut target) = self.docker_target_directory() else { + return; + }; target.push(digest.0); if let Err(e) = std::fs::remove_file(target) { warn!("Unable to remove docker file {:?}", e); @@ -283,7 +287,7 @@ impl Docker for crate::ui::widgets::download_manager::EpicDownloadManager { } return None; } - Some(p) => PathBuf::from(p.to_str()), + Some(p) => PathBuf::from(p.as_str()), }; target.push("docker"); Some(target) @@ -292,8 +296,8 @@ impl Docker for crate::ui::widgets::download_manager::EpicDownloadManager { #[cfg(target_os = "linux")] fn docker_download_progress(&self, version: &str, progress: u64) { let Some(item) = self.get_item(version) else { - return; - }; + return; + }; item.add_downloaded_size(u128::from(progress)); self.emit_by_name::<()>("tick", &[]); @@ -317,7 +321,9 @@ impl Docker for crate::ui::widgets::download_manager::EpicDownloadManager { let self_ = self.imp(); if let Some(digests) = self_.docker_digests.borrow_mut().get_mut(version) { let mut to_extract: Vec = Vec::new(); - let Some(target) = self.docker_target_directory() else { return }; + let Some(target) = self.docker_target_directory() else { + return; + }; for d in digests { match d.1 { DownloadStatus::Init => { @@ -345,7 +351,7 @@ impl Docker for crate::ui::widgets::download_manager::EpicDownloadManager { .map_or_else( || PathBuf::from(&version), |p| { - let mut path = PathBuf::from(p.to_str()); + let mut path = PathBuf::from(p.as_str()); path.push(version); path }, @@ -386,9 +392,11 @@ impl Docker for crate::ui::widgets::download_manager::EpicDownloadManager { let self_ = self.imp(); if let Some(digests) = self_.docker_digests.borrow_mut().get_mut(version) { let Some(item) = self.get_item(version) else { - return; - }; - let Some(target) = self.docker_target_directory() else { return }; + return; + }; + let Some(target) = self.docker_target_directory() else { + return; + }; let mut remaining = 0; for d in digests { match d.1 { diff --git a/src/ui/widgets/download_manager/download_item.rs b/src/ui/widgets/download_manager/download_item.rs index 43b9fef..23d6ec1 100644 --- a/src/ui/widgets/download_manager/download_item.rs +++ b/src/ui/widgets/download_manager/download_item.rs @@ -316,9 +316,9 @@ impl EpicDownloadItem { pub fn setup_timer(&self) { glib::timeout_add_seconds_local( 1, - clone!(@weak self as obj => @default-return glib::Continue(false), move || { + clone!(@weak self as obj => @default-return glib::ControlFlow::Break, move || { obj.speed_update(); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } @@ -338,7 +338,7 @@ impl EpicDownloadItem { let start = queue.front().unwrap().0; let end = queue.back().unwrap().0; let mut pop_counter = 0; - for (t, s) in queue.iter() { + for (t, s) in &*queue { if end - *t > chrono::Duration::seconds(1) { pop_counter += 1; } @@ -355,8 +355,10 @@ impl EpicDownloadItem { None } } { - let byte = byte_unit::Byte::from_bytes(speed).get_appropriate_unit(false); - self.set_property("speed", format!("{}/s", byte.format(1))); + let byte = byte_unit::Byte::from_u128(speed) + .unwrap_or_default() + .get_appropriate_unit(byte_unit::UnitType::Decimal); + self.set_property("speed", format!("{byte:.2}/s")); }; } @@ -418,10 +420,10 @@ impl EpicDownloadItem { get_action!(self_.actions, @pause).set_enabled(false); glib::timeout_add_seconds_local( 2, - clone!(@weak self as obj => @default-return glib::Continue(false), move || { + clone!(@weak self as obj => @default-return glib::ControlFlow::Break, move || { let self_ = obj.imp(); get_action!(self_.actions, @pause).set_enabled(true); - glib::Continue(false) + glib::ControlFlow::Break }), ); if let Some(dm) = self_.download_manager.get() { @@ -571,9 +573,9 @@ impl EpicDownloadItem { fn remove_from_parent_with_timer(&self, timer: u32) { glib::timeout_add_seconds_local( timer, - clone!(@weak self as obj => @default-return glib::Continue(false), move || { + clone!(@weak self as obj => @default-return glib::ControlFlow::Break, move || { obj.emit_by_name::<()>("finished", &[]); - glib::Continue(false) + glib::ControlFlow::Break }), ); } diff --git a/src/ui/widgets/download_manager/epic_file.rs b/src/ui/widgets/download_manager/epic_file.rs index f099ee0..d68945f 100644 --- a/src/ui/widgets/download_manager/epic_file.rs +++ b/src/ui/widgets/download_manager/epic_file.rs @@ -3,8 +3,8 @@ use crate::ui::widgets::logged_in::engines::epic_download::Blob; use crate::ui::widgets::logged_in::refresh::Refresh; use glib::clone; use gtk4::glib; -use gtk4::glib::Sender; -use gtk4::glib::{MainContext, ObjectExt, PRIORITY_DEFAULT}; +use gtk4::glib::{MainContext, ObjectExt}; +use gtk4::glib::{Priority, Sender}; use gtk4::prelude::WidgetExt; use gtk4::subclass::prelude::ObjectSubclassIsExt; use gtk4::{self, prelude::*}; @@ -79,7 +79,7 @@ impl EpicFile for crate::ui::widgets::download_manager::EpicDownloadManager { item.set_property("status", "waiting for download slot".to_string()); item.set_total_size(u128::from(size)); item.set_total_files(1); - let (send, recv) = std::sync::mpsc::channel::(); + let (send, recv) = std::sync::mpsc::channel::(); self.add_thread_sender(version.to_string(), send); let sender = self_.sender.clone(); let link = Url::parse(url).expect("Valid URL"); @@ -108,7 +108,7 @@ impl EpicFile for crate::ui::widgets::download_manager::EpicDownloadManager { } return None; } - Some(p) => PathBuf::from(p.to_str()), + Some(p) => PathBuf::from(p.as_str()), }; Some(target) } @@ -120,8 +120,7 @@ impl EpicFile for crate::ui::widgets::download_manager::EpicDownloadManager { let mut items = self_.download_items.borrow_mut(); let item = match items.get_mut(version) { None => { - let item = - crate::ui::widgets::download_manager::download_item::EpicDownloadItem::new(); + let item = download_item::EpicDownloadItem::new(); debug!("Adding item to the list under: {}", version); items.insert(version.to_string(), item.clone()); item @@ -174,7 +173,7 @@ impl EpicFile for crate::ui::widgets::download_manager::EpicDownloadManager { fn start_version_file_download(&self, version: &str) { let self_ = self.imp(); - let (sender, receiver) = MainContext::channel(PRIORITY_DEFAULT); + let (sender, receiver) = MainContext::channel(Priority::default()); let vers = version.to_string(); receiver.attach( @@ -185,7 +184,7 @@ impl EpicFile for crate::ui::widgets::download_manager::EpicDownloadManager { if let Some(ver) = filter_versions(v, &vers) { s.send(Msg::EpicDownloadStart(ver.name, ver.url, ver.size)).unwrap(); } - glib::Continue(false) + glib::ControlFlow::Break }), ); if let Some(window) = self_.window.get() { @@ -207,11 +206,11 @@ impl EpicFile for crate::ui::widgets::download_manager::EpicDownloadManager { .expect("Invalid Target directory"); p.push("epic"); p.push(version); - if let Err(e) = std::fs::remove_file(&p) { + if let Err(e) = fs::remove_file(&p) { error!("Unable to remove downloaded file: {}", e); }; if let Some(parent) = p.parent() { - if let Err(e) = std::fs::remove_dir(parent) { + if let Err(e) = fs::remove_dir(parent) { error!("Unable to remove epic download directory: {}", e); }; } @@ -251,9 +250,8 @@ impl EpicFile for crate::ui::widgets::download_manager::EpicDownloadManager { .expect("Invalid Target directory"); p.push("epic"); p.push(version); - if let Err(e) = std::fs::remove_file(p) { + if let Err(e) = fs::remove_file(p) { warn!("Unable to remove file {:?}", e); - } else { }; } @@ -294,18 +292,18 @@ impl EpicFile for crate::ui::widgets::download_manager::EpicDownloadManager { } if p.exists() { if let Some(item) = self.get_item(version) { - let metadata = std::fs::metadata(p.as_path()).expect("unable to read metadata"); + let metadata = fs::metadata(p.as_path()).expect("unable to read metadata"); item.add_downloaded_size(item.total_size() - item.downloaded_size()); if u128::from(metadata.size()) == item.total_size() { - let file = fs::File::open(&p).unwrap(); + let file = File::open(&p).unwrap(); if target.exists() { warn!("Target already exists."); } - let archive = zip::ZipArchive::new(file).unwrap(); + let archive = ZipArchive::new(file).unwrap(); item.set_total_files(archive.len() as u64); let sender = self_.sender.clone(); let ver = version.to_string(); - let (send, recv) = std::sync::mpsc::channel::(); + let (send, recv) = std::sync::mpsc::channel::(); self.add_thread_sender(version.to_string(), send); self_.file_pool.execute(move || { extract(&target, archive, &sender, ver, &recv); @@ -344,8 +342,7 @@ fn extract( }; file_target.push(&outpath); if file_target.exists() { - let metadata = - std::fs::metadata(file_target.as_path()).expect("unable to read metadata"); + let metadata = fs::metadata(file_target.as_path()).expect("unable to read metadata"); if metadata.size() == file.size() { sender.send(Msg::EpicFileExtracted(ver.clone())).unwrap(); continue; @@ -359,7 +356,7 @@ fn extract( fs::create_dir_all(p).unwrap(); } } - let mut outfile = fs::File::create(&file_target).unwrap(); + let mut outfile = File::create(&file_target).unwrap(); let mut buffer: [u8; 1024] = [0; 1024]; loop { @@ -377,10 +374,7 @@ fn extract( if size > 0 { outfile.write_all(&buffer[0..size]).unwrap(); sender - .send(super::Msg::EpicFileExtractionProgress( - ver.clone(), - size as u64, - )) + .send(Msg::EpicFileExtractionProgress(ver.clone(), size as u64)) .unwrap(); } else { break; @@ -437,11 +431,11 @@ fn run( ); fs::create_dir_all(p.parent().unwrap()).unwrap(); let mut client = if p.exists() { - let metadata = std::fs::metadata(p.as_path()).expect("unable to read metadata"); + let metadata = fs::metadata(p.as_path()).expect("unable to read metadata"); if metadata.size() == size { debug!("Already downloaded {}", p.to_str().unwrap_or_default()); sender - .send(super::Msg::EpicDownloadProgress(ver.clone(), size)) + .send(Msg::EpicDownloadProgress(ver.clone(), size)) .unwrap(); sender.send(Msg::EpicFileFinished(ver)).unwrap(); return; @@ -493,7 +487,7 @@ fn run( if size > 0 { file.write_all(&buffer[0..size]).unwrap(); sender - .send(super::Msg::EpicDownloadProgress(ver.clone(), size as u64)) + .send(Msg::EpicDownloadProgress(ver.clone(), size as u64)) .unwrap(); } else { break; diff --git a/src/ui/widgets/download_manager/mod.rs b/src/ui/widgets/download_manager/mod.rs index b2adce0..b74821c 100644 --- a/src/ui/widgets/download_manager/mod.rs +++ b/src/ui/widgets/download_manager/mod.rs @@ -82,7 +82,7 @@ pub mod imp { use super::*; use crate::window::EpicAssetManagerWindow; use gtk4::gio; - use gtk4::glib::{ParamSpec, ParamSpecBoolean}; + use gtk4::glib::{ParamSpec, ParamSpecBoolean, Priority}; use once_cell::sync::OnceCell; use std::cell::RefCell; use std::collections::HashMap; @@ -123,7 +123,7 @@ pub mod imp { type ParentType = gtk4::Box; fn new() -> Self { - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); Self { actions: gio::SimpleActionGroup::new(), settings: gio::Settings::new(crate::config::APP_ID), @@ -255,7 +255,7 @@ impl EpicDownloadManager { None, clone!(@weak self as download_manager => @default-panic, move |msg| { download_manager.update(msg); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } @@ -264,7 +264,9 @@ impl EpicDownloadManager { let self_ = self.imp(); match msg { Msg::ProcessItemThumbnail(id, image) => { - let Some(item) = self.get_item(&id) else { return }; + let Some(item) = self.get_item(&id) else { + return; + }; item.set_property("thumbnail", Some(image)); } Msg::StartAssetDownload(id, manifest) => { @@ -289,7 +291,9 @@ impl EpicDownloadManager { self.file_already_extracted(id, progress, fullname, filename); } Msg::FileExtracted(id) => { - let Some(item) = self.get_item(&id) else { return }; + let Some(item) = self.get_item(&id) else { + return; + }; item.file_processed(); self.emit_by_name::<()>("tick", &[]); } diff --git a/src/ui/widgets/logged_in/engines/docker_download.rs b/src/ui/widgets/logged_in/engines/docker_download.rs index cb4f301..97a47e1 100644 --- a/src/ui/widgets/logged_in/engines/docker_download.rs +++ b/src/ui/widgets/logged_in/engines/docker_download.rs @@ -20,7 +20,7 @@ pub enum Msg { pub mod imp { use super::*; use crate::window::EpicAssetManagerWindow; - use gtk4::glib::{ParamSpec, ParamSpecString}; + use gtk4::glib::{ParamSpec, ParamSpecString, Priority}; use once_cell::sync::OnceCell; use std::cell::RefCell; @@ -54,7 +54,7 @@ pub mod imp { type ParentType = gtk4::Box; fn new() -> Self { - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); Self { details: TemplateChild::default(), details_revealer: TemplateChild::default(), @@ -208,7 +208,7 @@ impl DockerEngineDownload { 2, clone!(@weak self as obj => @default-panic, move || { obj.show_details(); - glib::Continue(false) + glib::ControlFlow::Break }), ); } @@ -229,7 +229,7 @@ impl DockerEngineDownload { None, clone!(@weak self as docker => @default-panic, move |msg| { docker.update(msg); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } @@ -325,9 +325,9 @@ impl DockerEngineDownload { .use_markup(true) .label("Please configure github token in Preferences") .build(); - label.connect_activate_link(clone!(@weak self as details => @default-return gtk4::Inhibit(true), move |_, uri| { + label.connect_activate_link(clone!(@weak self as details => @default-return glib::Propagation::Stop, move |_, uri| { details.open_preferences(uri); - gtk4::Inhibit(true) + glib::Propagation::Stop })); self_.details.append(&label); @@ -449,13 +449,13 @@ impl DockerEngineDownload { self.updated_docker_versions(&ver); } Msg::ManifestSize(size) => { - let byte = - byte_unit::Byte::from_bytes(u128::from(size)).get_appropriate_unit(false); + let byte = byte_unit::Byte::from_u64(size) + .get_appropriate_unit(byte_unit::UnitType::Decimal); self_.settings.strv("unreal-engine-directories").get(0).map_or_else(|| if let Some(w) = self_.window.get() { w.add_notification("missing engine config", "Unable to install engine missing Unreal Engine Directories configuration", gtk4::MessageType::Error); get_action!(self_.actions, @install).set_enabled(false); }, |p| { - let mut path = std::path::Path::new(p.to_str()); + let mut path = std::path::Path::new(p.as_str()); while !path.exists() { path = match path.parent() { None => break, @@ -474,7 +474,7 @@ impl DockerEngineDownload { get_action!(self_.actions, @install).set_enabled(true); } }); - self.set_property("download-size", Some(byte.format(1))); + self.set_property("download-size", Some(format!("{byte:.2}"))); } Msg::Error(_error) => { if let Some(w) = self_.window.get() { diff --git a/src/ui/widgets/logged_in/engines/engine.rs b/src/ui/widgets/logged_in/engines/engine.rs index 1941d0a..a0851c3 100644 --- a/src/ui/widgets/logged_in/engines/engine.rs +++ b/src/ui/widgets/logged_in/engines/engine.rs @@ -190,10 +190,10 @@ impl EpicEngine { } self_.data.replace(Some(data.clone())); - self.set_property("path", &data.path()); - self.set_property("guid", &data.guid()); - self.set_property("version", &data.version()); - self.set_property("tooltip-text", &data.path()); + self.set_property("path", data.path()); + self.set_property("guid", data.guid()); + self.set_property("version", data.version()); + self.set_property("tooltip-text", data.path()); self_.handler.replace(Some(data.connect_local( "finished", false, @@ -205,8 +205,8 @@ impl EpicEngine { } fn finished(&self, data: &crate::models::engine_data::EngineData) { - self.set_property("branch", &data.branch()); - self.set_property("has-branch", &data.has_branch()); - self.set_property("needs-update", &data.needs_update()); + self.set_property("branch", data.branch()); + self.set_property("has-branch", data.has_branch()); + self.set_property("needs-update", data.needs_update()); } } diff --git a/src/ui/widgets/logged_in/engines/engine_detail.rs b/src/ui/widgets/logged_in/engines/engine_detail.rs index 158bc32..f41f4fa 100644 --- a/src/ui/widgets/logged_in/engines/engine_detail.rs +++ b/src/ui/widgets/logged_in/engines/engine_detail.rs @@ -204,7 +204,7 @@ impl EpicEngineDetails { 2, clone!(@weak self as obj => @default-panic, move || { obj.show_details(); - glib::Continue(false) + glib::ControlFlow::Break }), ); } diff --git a/src/ui/widgets/logged_in/engines/engines_side.rs b/src/ui/widgets/logged_in/engines/engines_side.rs index 12085db..9fcf8fa 100644 --- a/src/ui/widgets/logged_in/engines/engines_side.rs +++ b/src/ui/widgets/logged_in/engines/engines_side.rs @@ -183,7 +183,7 @@ impl EpicEnginesSide { pub fn set_data(&self, data: &crate::models::engine_data::EngineData) { let self_ = self.imp(); if let Some(title) = &data.version() { - self.set_property("title", &format!("{title}")); + self.set_property("title", format!("{title}")); } self_.details.set_data(data); self_.stack.set_visible_child_name("details"); diff --git a/src/ui/widgets/logged_in/engines/epic_download.rs b/src/ui/widgets/logged_in/engines/epic_download.rs index ad76434..53fba1e 100644 --- a/src/ui/widgets/logged_in/engines/epic_download.rs +++ b/src/ui/widgets/logged_in/engines/epic_download.rs @@ -1,7 +1,7 @@ use crate::gio::glib::Sender; use crate::tools::epic_web::EpicWeb; use crate::ui::widgets::download_manager::epic_file::EpicFile; -use gtk4::glib::{clone, MainContext, PRIORITY_DEFAULT}; +use gtk4::glib::{clone, MainContext, Priority}; use gtk4::subclass::prelude::*; use gtk4::{self, gio, prelude::*}; use gtk4::{glib, CompositeTemplate}; @@ -11,6 +11,7 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::thread; +use tokio::runtime::Builder; use version_compare::Cmp; #[derive(Debug, Clone)] @@ -37,6 +38,7 @@ pub struct Blob { pub mod imp { use super::*; use crate::window::EpicAssetManagerWindow; + use gtk4::glib::Priority; use once_cell::sync::OnceCell; use std::cell::RefCell; use std::collections::HashMap; @@ -78,7 +80,7 @@ pub mod imp { type ParentType = gtk4::Box; fn new() -> Self { - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); Self { details: TemplateChild::default(), details_revealer: TemplateChild::default(), @@ -174,7 +176,7 @@ impl EpicEngineDownload { 2, clone!(@weak self as obj => @default-panic, move || { obj.show_details(); - glib::Continue(false) + glib::ControlFlow::Break }), ); } @@ -195,7 +197,7 @@ impl EpicEngineDownload { None, clone!(@weak self as docker => @default-panic, move |msg| { docker.update(msg); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } @@ -214,9 +216,9 @@ impl EpicEngineDownload { if let Some(selected) = self_.version_selector.active_id() { if let Some(versions) = &*self_.engine_versions.borrow() { if let Some(version) = versions.get(selected.as_str()) { - let byte = byte_unit::Byte::from_bytes(u128::from(version.size)) - .get_appropriate_unit(false); - self_.size_value.set_label(&byte.format(1)); + let byte = byte_unit::Byte::from_u64(version.size) + .get_appropriate_unit(byte_unit::UnitType::Decimal); + self_.size_value.set_label(&format!("{byte:.2}")); } } } @@ -250,6 +252,14 @@ impl EpicEngineDownload { details.open_eula_browser(); }) ); + + action!( + actions, + "download", + clone!(@weak self as details => move |_, _| { + details.open_download_browser(); + }) + ); get_action!(self_.actions, @install).set_enabled(false); } @@ -275,18 +285,48 @@ impl EpicEngineDownload { if let Some(window) = self_.window.get() { let win_ = window.imp(); let mut eg = win_.model.borrow().epic_games.borrow().clone(); - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); + + receiver.attach( + None, + clone!(@weak self as sidebar => @default-panic, move |code: String| { + open_browser(&code, "https%3A%2F%2Fwww.unrealengine.com%2Feulacheck%2Funreal"); + glib::ControlFlow::Break + }), + ); + + thread::spawn(move || { + if let Some(token) = Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(eg.game_token()) + { + sender.send(token.code).unwrap(); + } + }); + } + } + + pub fn open_download_browser(&self) { + let self_ = self.imp(); + if let Some(window) = self_.window.get() { + let win_ = window.imp(); + let mut eg = win_.model.borrow().epic_games.borrow().clone(); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); receiver.attach( None, clone!(@weak self as sidebar => @default-panic, move |code: String| { - open_browser(&code); - glib::Continue(false) + open_browser(&code, "https%3A%2F%2Fwww.unrealengine.com%2Flinux"); + glib::ControlFlow::Break }), ); thread::spawn(move || { - if let Some(token) = tokio::runtime::Runtime::new() + if let Some(token) = Builder::new_current_thread() + .enable_all() + .build() .unwrap() .block_on(eg.game_token()) { @@ -304,7 +344,7 @@ impl EpicEngineDownload { self_.size_row.set_visible(true); self_.versions_row.set_visible(true); self_.eula_stack.set_visible_child_name("valid"); - let (sender, receiver) = MainContext::channel(PRIORITY_DEFAULT); + let (sender, receiver) = MainContext::channel(Priority::default()); receiver.attach( None, @@ -312,7 +352,7 @@ impl EpicEngineDownload { let self_ = ed.imp(); let s = self_.sender.clone(); s.send(Msg::Versions(v)).unwrap(); - glib::Continue(false) + glib::ControlFlow::Break }), ); self.get_versions(sender); @@ -379,7 +419,9 @@ impl EpicEngineDownload { return; }; thread::spawn(move || { - if let Some(token) = tokio::runtime::Runtime::new() + if let Some(token) = Builder::new_current_thread() + .enable_all() + .build() .unwrap() .block_on(eg.game_token()) { @@ -397,7 +439,9 @@ impl EpicEngineDownload { let win_ = window.imp(); let mut eg = win_.model.borrow().epic_games.borrow().clone(); thread::spawn(move || { - if let Some(token) = tokio::runtime::Runtime::new() + if let Some(token) = Builder::new_current_thread() + .enable_all() + .build() .unwrap() .block_on(eg.game_token()) { @@ -414,11 +458,21 @@ impl EpicEngineDownload { } } -fn open_browser(code: &str) { +fn open_browser(code: &str, redirect: &str) { #[cfg(target_os = "linux")] - if gio::AppInfo::launch_default_for_uri(&format!("https://www.epicgames.com/id/exchange?exchangeCode={code}&redirectUrl=https%3A%2F%2Fwww.unrealengine.com%2Feulacheck%2Funreal"), None::<&gio::AppLaunchContext>).is_err() { - error!("Please go to https://www.epicgames.com/id/exchange?exchangeCode={code}&redirectUrl=https%3A%2F%2Fwww.unrealengine.com%2Feulacheck%2Funreal"); + if gio::AppInfo::launch_default_for_uri( + &format!( + "https://www.epicgames.com/id/exchange?exchangeCode={code}&redirectUrl={redirect}" + ), + None::<&gio::AppLaunchContext>, + ) + .is_err() + { + error!("Please go to https://www.epicgames.com/id/exchange?exchangeCode={code}&redirectUrl={redirect}"); } #[cfg(target_os = "windows")] - open::that(format!("https://www.epicgames.com/id/exchange?exchangeCode={}&redirectUrl=https%3A%2F%2Fwww.unrealengine.com%2Feulacheck%2Funreal", code)); + open::that(format!( + "https://www.epicgames.com/id/exchange?exchangeCode={}&redirectUrl={redirect}", + code + )); } diff --git a/src/ui/widgets/logged_in/engines/mod.rs b/src/ui/widgets/logged_in/engines/mod.rs index 33fe330..6ee94c7 100644 --- a/src/ui/widgets/logged_in/engines/mod.rs +++ b/src/ui/widgets/logged_in/engines/mod.rs @@ -63,7 +63,7 @@ impl UnrealEngine { pub mod imp { use std::cell::RefCell; - use gtk4::glib::{ParamSpec, ParamSpecBoolean, ParamSpecString}; + use gtk4::glib::{ParamSpec, ParamSpecBoolean, ParamSpecString, Priority}; use once_cell::sync::OnceCell; use threadpool::ThreadPool; @@ -97,15 +97,13 @@ pub mod imp { type ParentType = gtk4::Box; fn new() -> Self { - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); Self { window: OnceCell::new(), download_manager: OnceCell::new(), engine_grid: TemplateChild::default(), side: TemplateChild::default(), - grid_model: gtk4::gio::ListStore::new( - crate::models::engine_data::EngineData::static_type(), - ), + grid_model: gtk4::gio::ListStore::new::(), expanded: RefCell::new(false), selected: RefCell::new(None), actions: gtk4::gio::SimpleActionGroup::new(), @@ -196,7 +194,7 @@ impl EpicEnginesBox { None, clone!(@weak self as engines => @default-panic, move |msg| { engines.update(msg); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } @@ -238,9 +236,9 @@ impl EpicEnginesBox { let child = list_item.child().unwrap().downcast::().unwrap(); child.set_data(&data); - child.set_property("branch", &data.branch()); - child.set_property("has-branch", &data.has_branch()); - child.set_property("needs-update", &data.needs_update()); + child.set_property("branch", data.branch()); + child.set_property("has-branch", data.has_branch()); + child.set_property("needs-update", data.needs_update()); }); let sorter = gtk4::CustomSorter::new(move |obj1, obj2| { @@ -307,7 +305,7 @@ impl EpicEnginesBox { 15 * 60 + (rand::random::() % 5) * 60, clone!(@weak self as obj => @default-panic, move || { obj.run_refresh(); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } @@ -525,7 +523,7 @@ impl EpicEnginesBox { if let Ok(keys) = ini.keys("Installations") { for item in keys { - if let Ok(path) = ini.value("Installations", item.to_str()) { + if let Ok(path) = ini.value("Installations", item.as_str()) { let guid: String = item .to_string() .chars() diff --git a/src/ui/widgets/logged_in/library/actions/mod.rs b/src/ui/widgets/logged_in/library/actions/mod.rs index b49f477..193c77a 100644 --- a/src/ui/widgets/logged_in/library/actions/mod.rs +++ b/src/ui/widgets/logged_in/library/actions/mod.rs @@ -9,7 +9,7 @@ use crate::tools::or::Or; use crate::ui::widgets::download_manager::asset::Asset; use adw::prelude::ExpanderRowExt; use egs_api::api::types::asset_info::AssetInfo; -use gtk4::glib::clone; +use gtk4::glib::{clone, Priority}; use gtk4::subclass::prelude::*; use gtk4::{self, gio, prelude::*, SizeGroupMode}; use gtk4::{glib, CompositeTemplate}; @@ -447,15 +447,17 @@ impl EpicAssetActions { self_.download_details.set_manifest(&manifest); self_.create_asset_project.set_manifest(&manifest); self_.size_label.borrow().set_label(&format!( - "{}", - byte_unit::Byte::from_bytes(manifest.total_download_size()) - .get_appropriate_unit(false) + "{:.2}", + byte_unit::Byte::from_u128(manifest.total_download_size()) + .unwrap_or_default() + .get_appropriate_unit(byte_unit::UnitType::Decimal) )); self_.disk_size_label.borrow().set_label(&format!( - "{}", - byte_unit::Byte::from_bytes(manifest.total_size()) - .get_appropriate_unit(false) + "{:.2}", + byte_unit::Byte::from_u128(manifest.total_size()) + .unwrap_or_default() + .get_appropriate_unit(byte_unit::UnitType::Decimal) )); } } @@ -517,13 +519,13 @@ impl EpicAssetActions { let (sender, receiver) = glib::MainContext::channel::<( String, Vec, - )>(gtk4::glib::PRIORITY_DEFAULT); + )>(Priority::default()); receiver.attach( None, clone!(@weak self as asset_actions => @default-panic, move |(id, manifest)| { asset_actions.process_download_manifest(&id, manifest); - glib::Continue(true) + glib::ControlFlow::Continue }), ); diff --git a/src/ui/widgets/logged_in/library/asset.rs b/src/ui/widgets/logged_in/library/asset.rs index 18c51c4..8481ca0 100644 --- a/src/ui/widgets/logged_in/library/asset.rs +++ b/src/ui/widgets/logged_in/library/asset.rs @@ -157,16 +157,16 @@ impl EpicAsset { } } self_.data.replace(Some(data.clone())); - self.set_property("label", &data.name()); - self.set_property("thumbnail", &data.image()); - self.set_property("favorite", &data.favorite()); - self.set_property("downloaded", &data.downloaded()); + self.set_property("label", data.name()); + self.set_property("thumbnail", data.image()); + self.set_property("favorite", data.favorite()); + self.set_property("downloaded", data.downloaded()); self_.handler.replace(Some(data.connect_local( "refreshed", false, clone!(@weak self as asset, @weak data => @default-return None, move |_| { - asset.set_property("favorite", &data.favorite()); - asset.set_property("downloaded", &data.downloaded()); + asset.set_property("favorite", data.favorite()); + asset.set_property("downloaded", data.downloaded()); None }), ))); diff --git a/src/ui/widgets/logged_in/library/asset_detail.rs b/src/ui/widgets/logged_in/library/asset_detail.rs index e6847b1..d1b2f13 100644 --- a/src/ui/widgets/logged_in/library/asset_detail.rs +++ b/src/ui/widgets/logged_in/library/asset_detail.rs @@ -210,7 +210,7 @@ impl EpicAssetDetails { 2, clone!(@weak self as obj => @default-panic, move || { obj.hide_confirmation(); - glib::Continue(false) + glib::ControlFlow::Break }), ); } @@ -289,9 +289,9 @@ impl EpicAssetDetails { ); self_.warning_message.connect_activate_link( - clone!(@weak self as details => @default-return gtk4::Inhibit(true), move |_, uri| { + clone!(@weak self as details => @default-return glib::Propagation::Stop, move |_, uri| { details.process_uri(uri); - gtk4::Inhibit(true) + glib::Propagation::Stop }), ); } diff --git a/src/ui/widgets/logged_in/library/image_stack.rs b/src/ui/widgets/logged_in/library/image_stack.rs index 0e00c2a..c8fba0a 100644 --- a/src/ui/widgets/logged_in/library/image_stack.rs +++ b/src/ui/widgets/logged_in/library/image_stack.rs @@ -1,5 +1,5 @@ use adw::gdk::Texture; -use gtk4::glib::{clone, MainContext, Receiver, Sender, PRIORITY_DEFAULT}; +use gtk4::glib::{clone, MainContext, Receiver, Sender}; use gtk4::subclass::prelude::*; use gtk4::{self, gio, prelude::*}; use gtk4::{glib, CompositeTemplate}; @@ -14,6 +14,7 @@ pub mod imp { use super::*; use crate::ui::widgets::download_manager::EpicDownloadManager; use gtk4::gio; + use gtk4::glib::Priority; use once_cell::sync::OnceCell; use std::cell::RefCell; use threadpool::ThreadPool; @@ -41,7 +42,7 @@ pub mod imp { type ParentType = gtk4::Box; fn new() -> Self { - let (sender, receiver) = MainContext::channel(PRIORITY_DEFAULT); + let (sender, receiver) = MainContext::channel(Priority::default()); Self { image_load_pool: ThreadPool::with_name("Image Load Pool".to_string(), 5), stack: TemplateChild::default(), @@ -156,7 +157,7 @@ impl EpicImageOverlay { None, clone!(@weak self as img => @default-panic, move |msg| { img.update(msg); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } diff --git a/src/ui/widgets/logged_in/library/mod.rs b/src/ui/widgets/logged_in/library/mod.rs index 752e782..29a16d7 100644 --- a/src/ui/widgets/logged_in/library/mod.rs +++ b/src/ui/widgets/logged_in/library/mod.rs @@ -11,6 +11,7 @@ use std::fs; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; +use tokio::runtime::Builder; mod actions; mod asset; @@ -29,7 +30,6 @@ pub mod imp { use once_cell::sync::OnceCell; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; - use std::sync::Arc; use threadpool::ThreadPool; #[derive(Debug, CompositeTemplate)] @@ -68,7 +68,7 @@ pub mod imp { pub asset_product_names: RefCell>, pub asset_load_pool: ThreadPool, pub image_load_pool: ThreadPool, - pub assets_pending: Arc>>, + pub assets_pending: std::sync::RwLock>, pub categories: RefCell>, pub settings: gio::Settings, loading: RefCell, @@ -108,13 +108,13 @@ pub mod imp { gio::ListModel::NONE.cloned(), gtk4::Sorter::NONE.cloned(), ), - grid_model: gio::ListStore::new(crate::models::asset_data::AssetData::static_type()), + grid_model: gio::ListStore::new::(), loaded_assets: RefCell::new(HashMap::new()), loaded_data: RefCell::new(HashMap::new()), asset_product_names: RefCell::new(HashMap::new()), asset_load_pool: ThreadPool::with_name("Asset Load Pool".to_string(), 15), image_load_pool: ThreadPool::with_name("Image Load Pool".to_string(), 15), - assets_pending: Arc::new(std::sync::RwLock::new(vec![])), + assets_pending: std::sync::RwLock::new(vec![]), categories: RefCell::new(HashSet::new()), settings: gio::Settings::new(config::APP_ID), loading: RefCell::new(0), @@ -304,7 +304,7 @@ impl EpicLibraryBox { clone!(@weak self as obj => @default-panic, move || { debug!("Library timed refresh starting"); obj.run_refresh(); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } @@ -805,7 +805,9 @@ impl EpicLibraryBox { let sender = win_.model.borrow().sender.clone(); // Start loading assets from the API self_.asset_load_pool.execute(move || { - let mut assets = tokio::runtime::Runtime::new() + let mut assets = Builder::new_current_thread() + .enable_all() + .build() .unwrap() .block_on(eg.list_assets(None, None)); assets.sort_by(|a, b| { @@ -832,7 +834,11 @@ impl EpicLibraryBox { }); self.refresh_state_changed(); glib::idle_add_local(clone!(@weak self as library => @default-panic, move || { - glib::Continue(library.flush_loop()) + if library.flush_loop() { + glib::ControlFlow::Continue + } else { + glib::ControlFlow::Break + } })); } } @@ -874,7 +880,9 @@ impl EpicLibraryBox { return; } } - if let Some(asset) = tokio::runtime::Runtime::new() + if let Some(asset) = Builder::new_current_thread() + .enable_all() + .build() .unwrap() .block_on(eg.asset_info(epic_asset.clone())) { diff --git a/src/ui/widgets/logged_in/library/sidebar/button.rs b/src/ui/widgets/logged_in/library/sidebar/button.rs index 8f408c8..0364e67 100644 --- a/src/ui/widgets/logged_in/library/sidebar/button.rs +++ b/src/ui/widgets/logged_in/library/sidebar/button.rs @@ -47,7 +47,7 @@ pub mod imp { actions: gio::SimpleActionGroup::new(), category_button: TemplateChild::default(), separator: TemplateChild::default(), - categories: ListStore::new(CategoryData::static_type()), + categories: ListStore::new::(), } } diff --git a/src/ui/widgets/logged_in/library/sidebar/categories.rs b/src/ui/widgets/logged_in/library/sidebar/categories.rs index bffb7b4..2519477 100644 --- a/src/ui/widgets/logged_in/library/sidebar/categories.rs +++ b/src/ui/widgets/logged_in/library/sidebar/categories.rs @@ -50,7 +50,7 @@ pub mod imp { expanded: RefCell::new(false), actions: gio::SimpleActionGroup::new(), categories: TemplateChild::default(), - cats: ListStore::new(CategoryData::static_type()), + cats: ListStore::new::(), selection_model: SingleSelection::new(None::), categories_set: RefCell::new(HashSet::new()), previous: TemplateChild::default(), @@ -241,7 +241,7 @@ impl EpicSidebarCategories { .unwrap(); let child = list_item.child().unwrap().downcast::().unwrap(); - child.set_property("title", &data.name()); + child.set_property("title", data.name()); child.set_property("leaf", data.leaf()); }); let sorter = gtk4::CustomSorter::new(move |obj1, obj2| { diff --git a/src/ui/widgets/logged_in/library/sidebar/mod.rs b/src/ui/widgets/logged_in/library/sidebar/mod.rs index 8c71841..455ef15 100644 --- a/src/ui/widgets/logged_in/library/sidebar/mod.rs +++ b/src/ui/widgets/logged_in/library/sidebar/mod.rs @@ -1,11 +1,12 @@ use crate::ui::widgets::logged_in::library::sidebar::categories::EpicSidebarCategories; -use gtk4::glib::clone; +use gtk4::glib::{clone, Priority}; use gtk4::subclass::prelude::*; use gtk4::{self, gio, prelude::*}; use gtk4::{glib, CompositeTemplate}; use gtk_macros::action; use log::{error, warn}; use std::thread; +use tokio::runtime::Builder; pub mod button; pub mod categories; @@ -196,18 +197,20 @@ impl EpicSidebar { if let Some(window) = self_.window.get() { let win_ = window.imp(); let mut eg = win_.model.borrow().epic_games.borrow().clone(); - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); receiver.attach( None, clone!(@weak self as sidebar => @default-panic, move |code:String| { open_browser(&code); - glib::Continue(false) + glib::ControlFlow::Break }), ); thread::spawn(move || { - match tokio::runtime::Runtime::new() + match Builder::new_current_thread() + .enable_all() + .build() .unwrap() .block_on(eg.game_token()) { @@ -293,10 +296,10 @@ impl EpicSidebar { if let Err(e) = self_.settings.set_boolean("sidebar-expanded", new_value) { warn!("Unable to save sidebar state: {}", e); }; - self.set_property("expanded", &new_value); - self_.all_category.set_property("expanded", &new_value); - self_.unreal_category.set_property("expanded", &new_value); - self_.games_category.set_property("expanded", &new_value); + self.set_property("expanded", new_value); + self_.all_category.set_property("expanded", new_value); + self_.unreal_category.set_property("expanded", new_value); + self_.games_category.set_property("expanded", new_value); } pub fn filter_changed(&self) { diff --git a/src/ui/widgets/logged_in/logs.rs b/src/ui/widgets/logged_in/logs.rs index 734a40e..9701387 100644 --- a/src/ui/widgets/logged_in/logs.rs +++ b/src/ui/widgets/logged_in/logs.rs @@ -34,7 +34,7 @@ pub enum Msg { pub mod imp { use super::*; use gtk4::gio::ListStore; - use gtk4::glib::Object; + use gtk4::glib::{Object, Priority}; use once_cell::sync::OnceCell; use std::cell::RefCell; use threadpool::ThreadPool; @@ -48,7 +48,7 @@ pub mod imp { pub model: ListStore, pub sender: gtk4::glib::Sender, pub receiver: RefCell>>, - pub pending: std::sync::Arc>>, + pub pending: std::sync::RwLock>, pub load_pool: ThreadPool, } @@ -59,14 +59,14 @@ pub mod imp { type ParentType = gtk4::Box; fn new() -> Self { - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); Self { window: OnceCell::new(), logs: TemplateChild::default(), - model: gtk4::gio::ListStore::new(crate::models::log_data::LogData::static_type()), + model: gtk4::gio::ListStore::new::(), sender, receiver: RefCell::new(Some(receiver)), - pending: std::sync::Arc::new(std::sync::RwLock::default()), + pending: std::sync::RwLock::default(), load_pool: ThreadPool::with_name("Logs Load Pool".to_string(), 1), } } @@ -115,7 +115,7 @@ impl EpicLogs { None, clone!(@weak self as engine => @default-panic, move |msg| { engine.update(msg); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } @@ -286,7 +286,11 @@ impl EpicLogs { }); } glib::idle_add_local(clone!(@weak self as logs => @default-panic, move || { - glib::Continue(logs.flush_logs()) + if logs.flush_logs() { + glib::ControlFlow::Continue + } else { + glib::ControlFlow::Break + } })); } diff --git a/src/ui/widgets/logged_in/plugins.rs b/src/ui/widgets/logged_in/plugins.rs index a747935..7e87eb8 100644 --- a/src/ui/widgets/logged_in/plugins.rs +++ b/src/ui/widgets/logged_in/plugins.rs @@ -1,4 +1,4 @@ -use gtk4::{self, glib, prelude::*, subclass::prelude::*, CompositeTemplate}; +use gtk4::{self, glib, subclass::prelude::*, CompositeTemplate}; #[derive(Debug, Clone)] pub enum Msg { @@ -8,7 +8,7 @@ pub enum Msg { pub mod imp { use super::*; use gtk4::gio::ListStore; - use gtk4::glib::Object; + use gtk4::glib::{Object, Priority}; use once_cell::sync::OnceCell; use std::cell::RefCell; use threadpool::ThreadPool; @@ -20,7 +20,7 @@ pub mod imp { pub model: ListStore, pub sender: gtk4::glib::Sender, pub receiver: RefCell>>, - pub pending: std::sync::Arc>>, + pub pending: std::sync::RwLock>, pub load_pool: ThreadPool, } @@ -31,13 +31,13 @@ pub mod imp { type ParentType = gtk4::Box; fn new() -> Self { - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); Self { window: OnceCell::new(), - model: gtk4::gio::ListStore::new(crate::models::log_data::LogData::static_type()), + model: gtk4::gio::ListStore::new::(), sender, receiver: RefCell::new(Some(receiver)), - pending: std::sync::Arc::new(std::sync::RwLock::default()), + pending: std::sync::RwLock::default(), load_pool: ThreadPool::with_name("Logs Load Pool".to_string(), 1), } } diff --git a/src/ui/widgets/logged_in/projects/mod.rs b/src/ui/widgets/logged_in/projects/mod.rs index e9a46ab..d743e7f 100644 --- a/src/ui/widgets/logged_in/projects/mod.rs +++ b/src/ui/widgets/logged_in/projects/mod.rs @@ -15,7 +15,7 @@ pub enum Msg { pub mod imp { use super::*; - use gtk4::glib::{ParamSpec, ParamSpecBoolean, ParamSpecString}; + use gtk4::glib::{ParamSpec, ParamSpecBoolean, ParamSpecString, Priority}; use once_cell::sync::OnceCell; use std::cell::RefCell; use std::collections::BTreeMap; @@ -51,7 +51,7 @@ pub mod imp { type ParentType = gtk4::Box; fn new() -> Self { - let (sender, receiver) = gtk4::glib::MainContext::channel(gtk4::glib::PRIORITY_DEFAULT); + let (sender, receiver) = gtk4::glib::MainContext::channel(Priority::default()); Self { window: OnceCell::new(), download_manager: OnceCell::new(), @@ -59,9 +59,7 @@ pub mod imp { projects_grid: TemplateChild::default(), details: TemplateChild::default(), projects: RefCell::new(BTreeMap::new()), - grid_model: gtk4::gio::ListStore::new( - crate::models::project_data::ProjectData::static_type(), - ), + grid_model: gtk4::gio::ListStore::new::(), expanded: RefCell::new(false), selected: RefCell::new(None), selected_uproject: RefCell::new(None), @@ -151,7 +149,7 @@ impl EpicProjectsBox { None, clone!(@weak self as projects => @default-panic, move |msg| { projects.update(msg); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } @@ -236,7 +234,7 @@ impl EpicProjectsBox { clone!(@weak self as obj => @default-panic, move || { debug!("Starting timed projects refresh"); obj.run_refresh(); - glib::Continue(true) + glib::ControlFlow::Continue }), ); } diff --git a/src/ui/widgets/logged_in/projects/project.rs b/src/ui/widgets/logged_in/projects/project.rs index cda790e..da83fe6 100644 --- a/src/ui/widgets/logged_in/projects/project.rs +++ b/src/ui/widgets/logged_in/projects/project.rs @@ -151,8 +151,8 @@ impl EpicProject { } } self_.data.replace(Some(data.clone())); - self.set_property("name", &data.name()); - self.set_property("tooltip-text", &data.path()); + self.set_property("name", data.name()); + self.set_property("tooltip-text", data.path()); data.uproject().map_or_else( || { self.set_property("engine", ""); @@ -160,6 +160,7 @@ impl EpicProject { |uproject| match self.associated_engine(&uproject) { None => { let db = crate::models::database::connection(); + #[allow(clippy::collection_is_never_read)] let mut last_engine: Option = None; if let Ok(mut conn) = db.get() { let engines: Result = diff --git a/src/ui/widgets/logged_in/projects/project_detail.rs b/src/ui/widgets/logged_in/projects/project_detail.rs index 702dc3f..f78922f 100644 --- a/src/ui/widgets/logged_in/projects/project_detail.rs +++ b/src/ui/widgets/logged_in/projects/project_detail.rs @@ -230,7 +230,7 @@ impl UnrealProjectDetails { 2, clone!(@weak self as obj => @default-panic, move || { obj.show_details(); - glib::Continue(false) + glib::ControlFlow::Break }), ); } diff --git a/src/ui/widgets/preferences/mod.rs b/src/ui/widgets/preferences/mod.rs index 8767213..0a91617 100644 --- a/src/ui/widgets/preferences/mod.rs +++ b/src/ui/widgets/preferences/mod.rs @@ -342,9 +342,9 @@ impl PreferencesWindow { )])) { for item in items { let Ok(label) = item.get_label() else { - debug!("No label skipping"); - continue; - }; + debug!("No label skipping"); + continue; + }; debug!("Loading: {label}"); match label.as_str() { "eam_github_token" => { @@ -708,7 +708,9 @@ impl PreferencesWindow { { let mut rows = self_.directory_rows.borrow_mut(); if let Some(r) = rows.get_mut(&kind) { - let Some(current_position) = r.iter().position(|i| i.0 == dir) else { return }; + let Some(current_position) = r.iter().position(|i| i.0 == dir) else { + return; + }; let item = r.remove(current_position); let sibling = &r[current_position - 1]; @@ -732,7 +734,9 @@ impl PreferencesWindow { { let mut rows = self_.directory_rows.borrow_mut(); if let Some(r) = rows.get_mut(&kind) { - let Some(current_position) = r.iter().position(|i| i.0 == dir) else { return }; + let Some(current_position) = r.iter().position(|i| i.0 == dir) else { + return; + }; let item = r.remove(current_position); let total = r.len(); if current_position < total { @@ -767,7 +771,7 @@ impl PreferencesWindow { native.set_modal(true); native.set_transient_for(Some(self)); - for f in filters.iter() { + for f in filters { let filter = gtk4::FileFilter::new(); filter.add_mime_type(f); filter.set_name(Some(f)); diff --git a/src/window.rs b/src/window.rs index b54adbe..dce260e 100644 --- a/src/window.rs +++ b/src/window.rs @@ -7,7 +7,6 @@ use crate::ui::PreferencesWindow; use chrono::TimeZone; use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; use glib::clone; -use glib::signal::Inhibit; use gtk4::subclass::prelude::*; use gtk4::{self, prelude::*, ListBoxRow}; use gtk4::{gio, glib, CompositeTemplate}; @@ -158,11 +157,13 @@ pub mod imp { impl WindowImpl for EpicAssetManagerWindow { // save window state on delete event - fn close_request(&self) -> Inhibit { + fn close_request(&self) -> glib::Propagation { if let Err(err) = self.obj().save_window_size() { warn!("Failed to save window state, {}", &err); } - Inhibit(false) + + // Pass close request on to the parent + self.parent_close_request() } } @@ -246,7 +247,7 @@ impl EpicAssetManagerWindow { None, clone!(@weak self as window => @default-panic, move |msg| { window.update(msg); - glib::Continue(true) + glib::ControlFlow::Continue }), ); }