Add better offline support

This commit is contained in:
Victor Fuentes 2022-11-29 02:11:29 -05:00
parent 9b9cb480fe
commit c310668a11
No known key found for this signature in database
GPG Key ID: 0A88B68D6A9ACAE0
11 changed files with 270 additions and 40 deletions

22
Cargo.lock generated
View File

@ -795,9 +795,9 @@ dependencies = [
[[package]] [[package]]
name = "gdk-pixbuf" name = "gdk-pixbuf"
version = "0.16.3" version = "0.16.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ba3e42776d1466938add08211734738d5c76e863a25b7a8064c4433a74a1a26" checksum = "d3094f2b8578136d1929cade4e0fff82f573521b579e96cfc24af2458431f176"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"gdk-pixbuf-sys", "gdk-pixbuf-sys",
@ -920,9 +920,9 @@ dependencies = [
[[package]] [[package]]
name = "glib" name = "glib"
version = "0.16.3" version = "0.16.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50feee2f1e73be50e6634c901bfced69a0937c5e4e4673067ade85e093fa9bd7" checksum = "d5204a4217749b385cefbfb7bf3a2fcde83e4ce6d0945f64440a1f5bd4010305"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"futures-channel", "futures-channel",
@ -1375,9 +1375,9 @@ dependencies = [
[[package]] [[package]]
name = "io-lifetimes" name = "io-lifetimes"
version = "1.0.2" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e394faa0efb47f9f227f1cd89978f854542b318a6f64fa695489c9c993056656" checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.42.0", "windows-sys 0.42.0",
@ -1391,9 +1391,9 @@ checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745"
[[package]] [[package]]
name = "is-terminal" name = "is-terminal"
version = "0.4.0" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae5bc6e2eb41c9def29a3e0f1306382807764b9b53112030eff57435667352d" checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
dependencies = [ dependencies = [
"hermit-abi 0.2.6", "hermit-abi 0.2.6",
"io-lifetimes", "io-lifetimes",
@ -1675,7 +1675,7 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]] [[package]]
name = "nix-data" name = "nix-data"
version = "0.0.2" version = "0.0.2"
source = "git+https://github.com/snowflakelinux/nix-data#42d0e42536627cdce50c522f161617b797f670be" source = "git+https://github.com/snowflakelinux/nix-data#4ddd91d514b6ce3286033398277d25a1a1a456dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"brotli", "brotli",
@ -2369,9 +2369,9 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.36.3" version = "0.36.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b1fbb4dfc4eb1d390c02df47760bb19a84bb80b301ecc947ab5406394d8223e" checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<g fill="#2e3436">
<path d="m 12 1 c -0.265625 0 -0.519531 0.105469 -0.707031 0.292969 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 l 1.292969 1.292969 h -7.585938 c -0.550781 0 -1 0.449219 -1 1 s 0.449219 1 1 1 h 7.585938 l -1.292969 1.292969 c -0.390625 0.390625 -0.390625 1.023437 0 1.414062 s 1.023437 0.390625 1.414062 0 l 3 -3 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 l -3 -3 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 z m -8 6 c -0.257812 0 -0.511719 0.097656 -0.707031 0.292969 l -3 3 c -0.3906252 0.390625 -0.3906252 1.023437 0 1.414062 l 3 3 c 0.1875 0.1875 0.441406 0.292969 0.707031 0.292969 s 0.519531 -0.105469 0.707031 -0.292969 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 l -1.292969 -1.292969 h 5.585938 v -2 h -5.585938 l 1.292969 -1.292969 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 c -0.195312 -0.195313 -0.449219 -0.292969 -0.707031 -0.292969 z m 0 0" fill-opacity="0.34902"/>
<path d="m 15 10 c 0.265625 0 0.519531 0.105469 0.707031 0.292969 c 0.390625 0.390625 0.390625 1.023437 0 1.414062 l -1.292969 1.292969 l 1.292969 1.292969 c 0.390625 0.390625 0.390625 1.023437 0 1.414062 s -1.023437 0.390625 -1.414062 0 l -1.292969 -1.292969 l -1.292969 1.292969 c -0.390625 0.390625 -1.023437 0.390625 -1.414062 0 s -0.390625 -1.023437 0 -1.414062 l 1.292969 -1.292969 l -1.292969 -1.292969 c -0.390625 -0.390625 -0.390625 -1.023437 0 -1.414062 c 0.1875 -0.1875 0.441406 -0.292969 0.707031 -0.292969 s 0.519531 0.105469 0.707031 0.292969 l 1.292969 1.292969 l 1.292969 -1.292969 c 0.1875 -0.1875 0.441406 -0.292969 0.707031 -0.292969 z m 0 0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 6.71875 2 c -0.191406 0.007812 -0.371094 0.035156 -0.5625 0.0625 c -1.523438 0.21875 -2.976562 1.023438 -3.96875 2.34375 c -1.980469 2.640625 -1.421875 6.425781 1.21875 8.40625 s 6.425781 1.421875 8.40625 -1.21875 c 0.121094 -0.171875 0.1875 -0.382812 0.1875 -0.59375 v -1 h -1 c -0.3125 0 -0.625 0.152344 -0.8125 0.40625 c -1.332031 1.777344 -3.816406 2.113281 -5.59375 0.78125 s -2.113281 -3.816406 -0.78125 -5.59375 s 3.816406 -2.113281 5.59375 -0.78125 c 0.429688 0.320312 0.769531 0.734375 1.03125 1.1875 h -1.4375 c -0.550781 0 -1 0.449219 -1 1 v 1 h 6 v -6 h -1 c -0.550781 0 -1 0.449219 -1 1 v 1.6875 c -0.382812 -0.578125 -0.847656 -1.082031 -1.40625 -1.5 c -1.15625 -0.867188 -2.53125 -1.253906 -3.875 -1.1875 z m 0 0" fill="#222222"/></svg>

After

Width:  |  Height:  |  Size: 889 B

View File

@ -1,13 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<gresources> <gresources>
<gresource prefix="/dev/vlinkz/NixSoftwareCenter/icons/scalable/emblems"> <gresource prefix="/dev/vlinkz/NixSoftwareCenter/icons/scalable/emblems">
<file preprocess="xml-stripblanks" alias="nsc-home-symbolic.svg">../icons/nsc-home-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-installed-symbolic.svg">../icons/nsc-installed-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-update-symbolic.svg">../icons/nsc-update-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-audio.svg">../icons/nsc-audio.svg</file> <file preprocess="xml-stripblanks" alias="nsc-audio.svg">../icons/nsc-audio.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-development.svg">../icons/nsc-development.svg</file> <file preprocess="xml-stripblanks" alias="nsc-development.svg">../icons/nsc-development.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-gaming.svg">../icons/nsc-gaming.svg</file> <file preprocess="xml-stripblanks" alias="nsc-gaming.svg">../icons/nsc-gaming.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-graphics.svg">../icons/nsc-graphics.svg</file> <file preprocess="xml-stripblanks" alias="nsc-graphics.svg">../icons/nsc-graphics.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-home-symbolic.svg">../icons/nsc-home-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-installed-symbolic.svg">../icons/nsc-installed-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-network-offline-symbolic.svg">../icons/nsc-network-offline-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-refresh-symbolic.svg">../icons/nsc-refresh-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-update-symbolic.svg">../icons/nsc-update-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-video.svg">../icons/nsc-video.svg</file> <file preprocess="xml-stripblanks" alias="nsc-video.svg">../icons/nsc-video.svg</file>
<file preprocess="xml-stripblanks" alias="nsc-web.svg">../icons/nsc-web.svg</file> <file preprocess="xml-stripblanks" alias="nsc-web.svg">../icons/nsc-web.svg</file>
</gresource> </gresource>

View File

@ -20,7 +20,7 @@ pkgs.stdenv.mkDerivation rec {
cargoDeps = pkgs.rustPlatform.fetchCargoTarball { cargoDeps = pkgs.rustPlatform.fetchCargoTarball {
inherit src; inherit src;
name = "${pname}-${version}"; name = "${pname}-${version}";
hash = "sha256-OmHjQkK1MGes9hbJ0LEGdP1wA8ohAJEon0ycoNppl0E="; hash = "sha256-6iFIyW2wH4EQn5C4+35N63wylL8DSU9YWbe8NUMMnDA=";
}; };
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [

View File

@ -1,2 +1,3 @@
pub mod packages; pub mod packages;
pub mod config; pub mod config;
pub mod util;

3
src/parse/util.rs Normal file
View File

@ -0,0 +1,3 @@
pub fn checkonline() -> bool {
reqwest::blocking::get("https://nmcheck.gnome.org/check_network_status.txt").is_ok()
}

View File

@ -24,6 +24,7 @@ use std::{
use log::*; use log::*;
use crate::parse::packages::PkgMaintainer; use crate::parse::packages::PkgMaintainer;
use crate::parse::util;
use crate::ui::installworker::InstallAsyncHandlerMsg; use crate::ui::installworker::InstallAsyncHandlerMsg;
use super::installworker::InstallAsyncHandler; use super::installworker::InstallAsyncHandler;
@ -63,6 +64,7 @@ pub struct PkgModel {
workqueue: HashSet<WorkPkg>, workqueue: HashSet<WorkPkg>,
visible: bool, visible: bool,
online: bool,
} }
#[derive(Debug, Hash, Eq, PartialEq, Clone)] #[derive(Debug, Hash, Eq, PartialEq, Clone)]
@ -156,6 +158,7 @@ pub enum PkgMsg {
NixShell, NixShell,
SetInstallType(InstallType), SetInstallType(InstallType),
AddToQueue(WorkPkg), AddToQueue(WorkPkg),
UpdateOnline(bool)
} }
#[derive(Debug)] #[derive(Debug)]
@ -169,6 +172,7 @@ pub struct PkgPageInit {
pub syspkgs: SystemPkgs, pub syspkgs: SystemPkgs,
pub userpkgs: UserPkgs, pub userpkgs: UserPkgs,
pub config: NixDataConfig, pub config: NixDataConfig,
pub online: bool
} }
#[relm4::component(pub)] #[relm4::component(pub)]
@ -353,6 +357,27 @@ impl Component for PkgModel {
// set_sensitive: false, // set_sensitive: false,
// } // }
// } // }
} else if !model.online {
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_spacing: 10,
set_halign: gtk::Align::End,
gtk::Button {
set_halign: gtk::Align::End,
set_valign: gtk::Align::Center,
add_css_class: "error",
set_label: "Offline",
set_can_target: false,
},
gtk::Button {
set_halign: gtk::Align::End,
set_valign: gtk::Align::Center,
set_icon_name: "nsc-refresh-symbolic",
connect_clicked[sender] => move |_| {
sender.output(AppMsg::CheckNetwork);
}
}
}
} else { } else {
adw::SplitButton { adw::SplitButton {
add_css_class: "suggested-action", add_css_class: "suggested-action",
@ -439,6 +464,27 @@ impl Component for PkgModel {
// set_sensitive: false, // set_sensitive: false,
// } // }
// } // }
} else if !model.online {
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_spacing: 10,
set_halign: gtk::Align::End,
gtk::Button {
set_halign: gtk::Align::End,
set_valign: gtk::Align::Center,
add_css_class: "error",
set_label: "Offline",
set_can_target: false,
},
gtk::Button {
set_halign: gtk::Align::End,
set_valign: gtk::Align::Center,
set_icon_name: "nsc-refresh-symbolic",
connect_clicked[sender] => move |_| {
sender.output(AppMsg::CheckNetwork);
}
}
}
} else { } else {
adw::SplitButton { adw::SplitButton {
add_css_class: "suggested-action", add_css_class: "suggested-action",
@ -965,6 +1011,7 @@ impl Component for PkgModel {
workqueue: HashSet::new(), workqueue: HashSet::new(),
launchable: None, launchable: None,
visible: false, visible: false,
online: initparams.online,
tracker: 0, tracker: 0,
}; };
@ -1285,6 +1332,12 @@ impl Component for PkgModel {
sender.output(AppMsg::FrontPage); sender.output(AppMsg::FrontPage);
} }
PkgMsg::InstallUser => { PkgMsg::InstallUser => {
let online = util::checkonline();
if !online {
sender.output(AppMsg::CheckNetwork);
self.online = false;
return;
}
let w = WorkPkg { let w = WorkPkg {
pkg: self.pkg.to_string(), pkg: self.pkg.to_string(),
pname: self.pname.to_string(), pname: self.pname.to_string(),
@ -1313,6 +1366,12 @@ impl Component for PkgModel {
} }
} }
PkgMsg::InstallSystem => { PkgMsg::InstallSystem => {
let online = util::checkonline();
if !online {
sender.output(AppMsg::CheckNetwork);
self.online = false;
return;
}
let w = WorkPkg { let w = WorkPkg {
pkg: self.pkg.to_string(), pkg: self.pkg.to_string(),
pname: self.pname.to_string(), pname: self.pname.to_string(),
@ -1531,6 +1590,9 @@ impl Component for PkgModel {
self.installworker.emit(InstallAsyncHandlerMsg::Process(work)); self.installworker.emit(InstallAsyncHandlerMsg::Process(work));
} }
} }
PkgMsg::UpdateOnline(online) => {
self.set_online(online);
}
} }
} }

View File

@ -1,4 +1,4 @@
use crate::{APPINFO, ui::unavailabledialog::UnavailableDialogModel}; use crate::{APPINFO, ui::unavailabledialog::UnavailableDialogModel, parse::util};
use super::{pkgpage::InstallType, window::*, updateworker::{UpdateAsyncHandler, UpdateAsyncHandlerMsg, UpdateAsyncHandlerInit}, rebuild::RebuildMsg}; use super::{pkgpage::InstallType, window::*, updateworker::{UpdateAsyncHandler, UpdateAsyncHandlerMsg, UpdateAsyncHandlerInit}, rebuild::RebuildMsg};
use adw::prelude::*; use adw::prelude::*;
@ -25,6 +25,7 @@ pub struct UpdatePageModel {
updatetracker: u8, updatetracker: u8,
#[tracker::no_eq] #[tracker::no_eq]
unavailabledialog: Controller<UnavailableDialogModel>, unavailabledialog: Controller<UnavailableDialogModel>,
online: bool,
} }
#[derive(Debug)] #[derive(Debug)]
@ -44,6 +45,7 @@ pub enum UpdatePageMsg {
UpdateAllRm(Vec<String>, Vec<String>), UpdateAllRm(Vec<String>, Vec<String>),
DoneWorking, DoneWorking,
FailedWorking, FailedWorking,
UpdateOnline(bool),
} }
#[derive(Debug)] #[derive(Debug)]
@ -58,6 +60,7 @@ pub struct UpdatePageInit {
pub systype: SystemPkgs, pub systype: SystemPkgs,
pub usertype: UserPkgs, pub usertype: UserPkgs,
pub config: NixDataConfig, pub config: NixDataConfig,
pub online: bool,
} }
#[relm4::component(pub)] #[relm4::component(pub)]
@ -72,7 +75,25 @@ impl SimpleComponent for UpdatePageModel {
#[track(model.changed(UpdatePageModel::updatetracker()))] #[track(model.changed(UpdatePageModel::updatetracker()))]
set_vadjustment: gtk::Adjustment::NONE, set_vadjustment: gtk::Adjustment::NONE,
adw::Clamp { adw::Clamp {
if model.channelupdate.is_some() || !model.updateuserlist.is_empty() || !model.updatesystemlist.is_empty() { #[name(mainstack)]
if !model.online {
adw::StatusPage {
set_icon_name: Some("nsc-network-offline-symbolic"),
set_title: "No internet connection",
set_description: Some("Please connect to the internet to update your system"),
gtk::Button {
add_css_class: "pill",
set_halign: gtk::Align::Center,
adw::ButtonContent {
set_icon_name: "nsc-refresh-symbolic",
set_label: "Refresh",
},
connect_clicked[sender] => move |_| {
sender.output(AppMsg::CheckNetwork);
}
}
}
} else if model.channelupdate.is_some() || !model.updateuserlist.is_empty() || !model.updatesystemlist.is_empty() {
gtk::Box { gtk::Box {
set_orientation: gtk::Orientation::Vertical, set_orientation: gtk::Orientation::Vertical,
set_valign: gtk::Align::Start, set_valign: gtk::Align::Start,
@ -218,6 +239,7 @@ impl SimpleComponent for UpdatePageModel {
systype: initparams.systype, systype: initparams.systype,
usertype: initparams.usertype, usertype: initparams.usertype,
unavailabledialog, unavailabledialog,
online: initparams.online,
tracker: 0, tracker: 0,
}; };
@ -225,6 +247,8 @@ impl SimpleComponent for UpdatePageModel {
let updatesystemlist = model.updatesystemlist.widget(); let updatesystemlist = model.updatesystemlist.widget();
let widgets = view_output!(); let widgets = view_output!();
widgets.mainstack.set_hhomogeneous(false);
widgets.mainstack.set_vhomogeneous(false);
ComponentParts { model, widgets } ComponentParts { model, widgets }
} }
@ -276,6 +300,12 @@ impl SimpleComponent for UpdatePageModel {
} }
}, },
UpdatePageMsg::UpdateSystem => { UpdatePageMsg::UpdateSystem => {
let online = util::checkonline();
if !online {
sender.output(AppMsg::CheckNetwork);
self.online = false;
return;
}
let systype = self.systype.clone(); let systype = self.systype.clone();
let systemconfig = self.config.systemconfig.clone(); let systemconfig = self.config.systemconfig.clone();
let workersender = self.updateworker.sender().clone(); let workersender = self.updateworker.sender().clone();
@ -308,6 +338,12 @@ impl SimpleComponent for UpdatePageModel {
warn!("unimplemented"); warn!("unimplemented");
} }
UpdatePageMsg::UpdateAllUser => { UpdatePageMsg::UpdateAllUser => {
let online = util::checkonline();
if !online {
sender.output(AppMsg::CheckNetwork);
self.online = false;
return;
}
REBUILD_BROKER.send(RebuildMsg::Show); REBUILD_BROKER.send(RebuildMsg::Show);
if self.usertype == UserPkgs::Profile { if self.usertype == UserPkgs::Profile {
let workersender = self.updateworker.sender().clone(); let workersender = self.updateworker.sender().clone();
@ -331,6 +367,12 @@ impl SimpleComponent for UpdatePageModel {
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateUserPkgsRemove(pkgs)); self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateUserPkgsRemove(pkgs));
} }
UpdatePageMsg::UpdateAll => { UpdatePageMsg::UpdateAll => {
let online = util::checkonline();
if !online {
sender.output(AppMsg::CheckNetwork);
self.online = false;
return;
}
info!("UpdatePageMsg::UpdateAll"); info!("UpdatePageMsg::UpdateAll");
let systype = self.systype.clone(); let systype = self.systype.clone();
let usertype = self.usertype.clone(); let usertype = self.usertype.clone();
@ -373,6 +415,9 @@ impl SimpleComponent for UpdatePageModel {
UpdatePageMsg::FailedWorking => { UpdatePageMsg::FailedWorking => {
REBUILD_BROKER.send(RebuildMsg::FinishError(None)); REBUILD_BROKER.send(RebuildMsg::FinishError(None));
} }
UpdatePageMsg::UpdateOnline(online) => {
self.set_online(online);
}
} }
} }
} }

View File

@ -2,9 +2,13 @@ use crate::{
config, config,
parse::{ parse::{
config::{editconfig, getconfig}, config::{editconfig, getconfig},
packages::{AppData, LicenseEnum, PkgMaintainer, Platform}, packages::{AppData, LicenseEnum, PkgMaintainer, Platform}, util,
},
ui::{
installedpage::InstalledItem, pkgpage::PkgPageInit, rebuild::RebuildMsg,
unavailabledialog::UnavailableDialogMsg, updatepage::UNAVAILABLE_BROKER,
welcome::WelcomeMsg,
}, },
ui::{installedpage::InstalledItem, pkgpage::PkgPageInit, welcome::WelcomeMsg, rebuild::RebuildMsg, updatepage::UNAVAILABLE_BROKER, unavailabledialog::UnavailableDialogMsg},
APPINFO, APPINFO,
}; };
use adw::prelude::*; use adw::prelude::*;
@ -29,10 +33,12 @@ use super::{
pkgpage::{self, InstallType, PkgInitModel, PkgModel, PkgMsg, WorkPkg}, pkgpage::{self, InstallType, PkgInitModel, PkgModel, PkgMsg, WorkPkg},
pkgtile::PkgTile, pkgtile::PkgTile,
preferencespage::{PreferencesPageModel, PreferencesPageMsg}, preferencespage::{PreferencesPageModel, PreferencesPageMsg},
rebuild::RebuildModel,
searchpage::{SearchItem, SearchPageModel, SearchPageMsg}, searchpage::{SearchItem, SearchPageModel, SearchPageMsg},
unavailabledialog::UnavailableItemModel,
updatepage::{UpdateItem, UpdatePageInit, UpdatePageModel, UpdatePageMsg, UpdateType}, updatepage::{UpdateItem, UpdatePageInit, UpdatePageModel, UpdatePageMsg, UpdateType},
welcome::WelcomeModel, welcome::WelcomeModel,
windowloading::{LoadErrorModel, LoadErrorMsg, WindowAsyncHandler, WindowAsyncHandlerMsg}, rebuild::RebuildModel, unavailabledialog::UnavailableItemModel, windowloading::{LoadErrorModel, LoadErrorMsg, WindowAsyncHandler, WindowAsyncHandlerMsg},
}; };
pub static REBUILD_BROKER: MessageBroker<RebuildModel> = MessageBroker::new(); pub static REBUILD_BROKER: MessageBroker<RebuildModel> = MessageBroker::new();
@ -113,6 +119,7 @@ pub struct AppModel {
installedpagebusy: Vec<(String, InstallType)>, installedpagebusy: Vec<(String, InstallType)>,
#[tracker::no_eq] #[tracker::no_eq]
rebuild: Controller<RebuildModel>, rebuild: Controller<RebuildModel>,
online: bool,
} }
#[derive(Debug)] #[derive(Debug)]
@ -120,6 +127,7 @@ pub enum AppMsg {
UpdateSysconfig(Option<String>), UpdateSysconfig(Option<String>),
UpdateFlake(Option<String>, Option<String>), UpdateFlake(Option<String>, Option<String>),
TryLoad, TryLoad,
UpdateDB,
LoadConfig(NixDataConfig), LoadConfig(NixDataConfig),
Close, Close,
LoadError(String, String), LoadError(String, String),
@ -153,6 +161,7 @@ pub enum AppMsg {
UpdateRecPkgs(Vec<String>), UpdateRecPkgs(Vec<String>),
SetDarkMode(bool), SetDarkMode(bool),
GetUnavailableItems(HashMap<String, String>, HashMap<String, String>, UpdateType), GetUnavailableItems(HashMap<String, String>, HashMap<String, String>, UpdateType),
CheckNetwork,
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -171,6 +180,7 @@ pub enum AppAsyncMsg {
UpdateRecPkgs(Vec<PkgTile>), UpdateRecPkgs(Vec<PkgTile>),
UpdateInstalledPkgs(HashSet<String>, HashMap<String, String>), UpdateInstalledPkgs(HashSet<String>, HashMap<String, String>),
LoadCategory(PkgCategory, Vec<CategoryTile>, Vec<CategoryTile>), LoadCategory(PkgCategory, Vec<CategoryTile>, Vec<CategoryTile>),
SetNetwork(bool)
} }
#[relm4::component(pub)] #[relm4::component(pub)]
@ -465,6 +475,8 @@ impl Component for AppModel {
debug!("userpkgtype: {:?}", userpkgtype); debug!("userpkgtype: {:?}", userpkgtype);
debug!("syspkgtype: {:?}", syspkgtype); debug!("syspkgtype: {:?}", syspkgtype);
let online = util::checkonline();
let windowloading = WindowAsyncHandler::builder() let windowloading = WindowAsyncHandler::builder()
.detach_worker(()) .detach_worker(())
.forward(sender.input_sender(), identity); .forward(sender.input_sender(), identity);
@ -476,6 +488,7 @@ impl Component for AppModel {
userpkgs: userpkgtype.clone(), userpkgs: userpkgtype.clone(),
syspkgs: syspkgtype.clone(), syspkgs: syspkgtype.clone(),
config: config.clone(), config: config.clone(),
online,
}) })
.forward(sender.input_sender(), identity); .forward(sender.input_sender(), identity);
let searchpage = SearchPageModel::builder() let searchpage = SearchPageModel::builder()
@ -493,6 +506,7 @@ impl Component for AppModel {
systype: syspkgtype.clone(), systype: syspkgtype.clone(),
usertype: userpkgtype.clone(), usertype: userpkgtype.clone(),
config: config.clone(), config: config.clone(),
online,
}) })
.forward(sender.input_sender(), identity); .forward(sender.input_sender(), identity);
let rebuild = RebuildModel::builder() let rebuild = RebuildModel::builder()
@ -532,6 +546,7 @@ impl Component for AppModel {
viewstack, viewstack,
installedpagebusy: vec![], installedpagebusy: vec![],
rebuild, rebuild,
online,
tracker: 0, tracker: 0,
}; };
@ -604,7 +619,12 @@ impl Component for AppModel {
} }
#[tokio::main] #[tokio::main]
async fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>, _root: &Self::Root) { async fn update(
&mut self,
msg: Self::Input,
sender: ComponentSender<Self>,
_root: &Self::Root,
) {
self.reset(); self.reset();
match msg { match msg {
AppMsg::TryLoad => { AppMsg::TryLoad => {
@ -615,6 +635,12 @@ impl Component for AppModel {
self.config.clone(), self.config.clone(),
)); ));
} }
AppMsg::UpdateDB => {
self.windowloading.emit(WindowAsyncHandlerMsg::UpdateDB(
self.syspkgtype.clone(),
self.userpkgtype.clone(),
));
}
AppMsg::LoadConfig(config) => { AppMsg::LoadConfig(config) => {
info!("AppMsg::LoadConfig"); info!("AppMsg::LoadConfig");
self.config = config; self.config = config;
@ -758,12 +784,12 @@ impl Component for AppModel {
self.categoryrec = categoryrec; self.categoryrec = categoryrec;
self.categoryall = categoryall; self.categoryall = categoryall;
self.page = Page::FrontPage;
self.pkgpage.emit(PkgMsg::UpdateConfig(self.config.clone())); self.pkgpage.emit(PkgMsg::UpdateConfig(self.config.clone()));
self.updatepage self.updatepage
.emit(UpdatePageMsg::UpdateConfig(self.config.clone())); .emit(UpdatePageMsg::UpdateConfig(self.config.clone()));
sender.input(AppMsg::UpdateRecPkgs(recommendedapps)); sender.input(AppMsg::UpdateRecPkgs(recommendedapps));
let mut cat_guard = self.categories.guard(); let mut cat_guard = self.categories.guard();
cat_guard.clear();
for c in vec![ for c in vec![
PkgCategory::Audio, PkgCategory::Audio,
PkgCategory::Development, PkgCategory::Development,
@ -824,7 +850,10 @@ impl Component for AppModel {
.and_then(|x| x.get("C")) .and_then(|x| x.get("C"))
.map(|x| x.to_string()) .map(|x| x.to_string())
.unwrap_or_default(), .unwrap_or_default(),
installeduser: installeduser.contains_key(&match userpkgtype { UserPkgs::Env => pname.0, UserPkgs::Profile => pkg.to_string() }), installeduser: installeduser.contains_key(&match userpkgtype {
UserPkgs::Env => pname.0,
UserPkgs::Profile => pkg.to_string(),
}),
installedsystem: installedsystem.contains(&pkg), installedsystem: installedsystem.contains(&pkg),
}) })
} }
@ -835,6 +864,7 @@ impl Component for AppModel {
} }
AppMsg::OpenPkg(pkg) => { AppMsg::OpenPkg(pkg) => {
info!("AppMsg::OpenPkg {}", pkg); info!("AppMsg::OpenPkg {}", pkg);
sender.input(AppMsg::CheckNetwork);
if let Ok(pool) = &SqlitePool::connect(&format!("sqlite://{}", self.pkgdb)).await { if let Ok(pool) = &SqlitePool::connect(&format!("sqlite://{}", self.pkgdb)).await {
let pkgdata: Result< let pkgdata: Result<
( (
@ -1371,10 +1401,7 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
.fetch_one(latestpool) .fetch_one(latestpool)
.await .await
.unwrap(); .unwrap();
debug!( debug!("PROFILE: {} {} {}", installedpkg, version, newver);
"PROFILE: {} {} {}",
installedpkg, version, newver
);
if version != newver { if version != newver {
updateuseritems.push(UpdateItem { updateuseritems.push(UpdateItem {
name, name,
@ -1551,6 +1578,9 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
sender.input(AppMsg::SetSearch(false)) sender.input(AppMsg::SetSearch(false))
} }
} }
if name == "updates" && self.online {
sender.input(AppMsg::CheckNetwork);
}
} }
AppMsg::SetVsBar(vsbar) => { AppMsg::SetVsBar(vsbar) => {
self.set_showvsbar(vsbar); self.set_showvsbar(vsbar);
@ -1869,7 +1899,7 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
.as_ref() .as_ref()
.and_then(|x| x.cached.as_ref()) .and_then(|x| x.cached.as_ref())
.map(|x| x[0].name.clone()), .map(|x| x[0].name.clone()),
message: msg message: msg,
}) })
} else { } else {
unavailableuser.push(UnavailableItemModel { unavailableuser.push(UnavailableItemModel {
@ -1885,7 +1915,7 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
.as_ref() .as_ref()
.and_then(|x| x.cached.as_ref()) .and_then(|x| x.cached.as_ref())
.map(|x| x[0].name.clone()), .map(|x| x[0].name.clone()),
message: msg message: msg,
}) })
} }
} else { } else {
@ -1894,7 +1924,7 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
name: pkg.to_string(), name: pkg.to_string(),
pname: String::new(), pname: String::new(),
icon: None, icon: None,
message: msg message: msg,
}) })
} }
} }
@ -1921,7 +1951,7 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
.as_ref() .as_ref()
.and_then(|x| x.cached.as_ref()) .and_then(|x| x.cached.as_ref())
.map(|x| x[0].name.clone()), .map(|x| x[0].name.clone()),
message: msg message: msg,
}) })
} else { } else {
unavailablesys.push(UnavailableItemModel { unavailablesys.push(UnavailableItemModel {
@ -1937,7 +1967,7 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
.as_ref() .as_ref()
.and_then(|x| x.cached.as_ref()) .and_then(|x| x.cached.as_ref())
.map(|x| x[0].name.clone()), .map(|x| x[0].name.clone()),
message: msg message: msg,
}) })
} }
} else { } else {
@ -1946,19 +1976,39 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
name: pkg.to_string(), name: pkg.to_string(),
pname: String::new(), pname: String::new(),
icon: None, icon: None,
message: msg message: msg,
}) })
} }
} }
} }
UNAVAILABLE_BROKER.send(UnavailableDialogMsg::Show(unavailableuser, unavailablesys, updatetype)); UNAVAILABLE_BROKER.send(UnavailableDialogMsg::Show(
unavailableuser,
unavailablesys,
updatetype,
));
});
}
AppMsg::CheckNetwork => {
let selfonline = self.online;
let senderclone = sender.clone();
sender.oneshot_command(async move {
info!("AppMsg::CheckNetwork");
let online = util::checkonline();
if online && !selfonline {
senderclone.input(AppMsg::UpdateDB);
}
AppAsyncMsg::SetNetwork(online)
}); });
} }
} }
} }
fn update_cmd(&mut self, msg: Self::CommandOutput, sender: ComponentSender<Self>, _root: &Self::Root) { fn update_cmd(
&mut self,
msg: Self::CommandOutput,
sender: ComponentSender<Self>,
_root: &Self::Root,
) {
match msg { match msg {
AppAsyncMsg::Search(search, pkgitems) => { AppAsyncMsg::Search(search, pkgitems) => {
if search == self.searchquery { if search == self.searchquery {
@ -1990,7 +2040,11 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
debug!("Got recommended apps guard"); debug!("Got recommended apps guard");
for item in recommendedapps_guard.iter_mut() { for item in recommendedapps_guard.iter_mut() {
debug!("Got item {}", item.pkg); debug!("Got item {}", item.pkg);
item.installeduser = self.installeduserpkgs.contains_key(match self.userpkgtype { UserPkgs::Env => &item.pname, UserPkgs::Profile => &item.pkg }); item.installeduser =
self.installeduserpkgs.contains_key(match self.userpkgtype {
UserPkgs::Env => &item.pname,
UserPkgs::Profile => &item.pkg,
});
item.installedsystem = self.installedsystempkgs.contains(&item.pkg); item.installedsystem = self.installedsystempkgs.contains(&item.pkg);
} }
if self.searching { if self.searching {
@ -2006,6 +2060,11 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
self.categorypage self.categorypage
.emit(CategoryPageMsg::Open(category, catrec, catall)); .emit(CategoryPageMsg::Open(category, catrec, catall));
} }
AppAsyncMsg::SetNetwork(online) => {
self.online = online;
self.updatepage.emit(UpdatePageMsg::UpdateOnline(online));
self.pkgpage.emit(PkgMsg::UpdateOnline(online));
}
} }
} }
} }

View File

@ -18,6 +18,7 @@ pub struct WindowAsyncHandler;
#[derive(Debug)] #[derive(Debug)]
pub enum WindowAsyncHandlerMsg { pub enum WindowAsyncHandlerMsg {
CheckCache(SystemPkgs, UserPkgs, NixDataConfig), CheckCache(SystemPkgs, UserPkgs, NixDataConfig),
UpdateDB(SystemPkgs, UserPkgs),
} }
impl Worker for WindowAsyncHandler { impl Worker for WindowAsyncHandler {
@ -42,9 +43,14 @@ impl Worker for WindowAsyncHandler {
Ok(p) => p, Ok(p) => p,
Err(e) => { Err(e) => {
error!("Error getting NixOS pkgs: {}", e); error!("Error getting NixOS pkgs: {}", e);
sender.output(AppMsg::LoadError(
String::from("Error retrieving NixOS package database"),
e.to_string(),
));
return; return;
} }
}; };
let pool = SqlitePool::connect(&format!("sqlite://{}", pkgdb)) let pool = SqlitePool::connect(&format!("sqlite://{}", pkgdb))
.await .await
.unwrap(); .unwrap();
@ -381,6 +387,50 @@ impl Worker for WindowAsyncHandler {
)); ));
}); });
} }
WindowAsyncHandlerMsg::UpdateDB(syspkgs, userpkgs) => {
relm4::spawn(async move {
let _pkgdb = match nix_data::cache::nixos::nixospkgs().await {
Ok(p) => p,
Err(e) => {
error!("Error getting NixOS pkgs: {}", e);
sender.output(AppMsg::LoadError(
String::from("Error retrieving NixOS package database"),
e.to_string(),
));
return;
}
};
let _nixpkgsdb = match userpkgs {
UserPkgs::Profile => {
if let Ok(x) = nix_data::cache::profile::nixpkgslatest().await {
Some(x)
} else {
None
}
}
UserPkgs::Env => None,
};
let _systemdb = match syspkgs {
SystemPkgs::None => None,
SystemPkgs::Legacy => {
if let Ok(x) = nix_data::cache::channel::legacypkgs().await {
Some(x)
} else {
None
}
}
SystemPkgs::Flake => {
if let Ok(x) = nix_data::cache::flakes::flakespkgs().await {
Some(x)
} else {
None
}
}
};
});
}
} }
} }
} }
@ -467,8 +517,7 @@ impl SimpleComponent for LoadErrorModel {
} }
LoadErrorMsg::Close => { LoadErrorMsg::Close => {
sender.output(AppMsg::Close); sender.output(AppMsg::Close);
} } // LoadErrorMsg::Preferences => sender.output(AppMsg::ShowPrefMenu),
// LoadErrorMsg::Preferences => sender.output(AppMsg::ShowPrefMenu),
} }
} }
} }