Refactor around nix-data crate

This commit is contained in:
Victor Fuentes 2022-10-26 21:59:58 -04:00
parent 5532c19944
commit ee0c62b3da
No known key found for this signature in database
GPG Key ID: 0A88B68D6A9ACAE0
27 changed files with 2461 additions and 1822 deletions

1192
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
[package] [package]
name = "nix-software-center" name = "nix-software-center"
version = "0.0.3" version = "0.1.0"
edition = "2021" edition = "2021"
default-run = "nix-software-center" default-run = "nix-software-center"
[dependencies] [dependencies]
relm4 = { git = "https://github.com/Relm4/Relm4", tag = "v0.5.0-beta.2", features = ["all"] } relm4 = { git = "https://github.com/Relm4/Relm4", tag = "v0.5.0-beta.3", features = ["all"] }
relm4-components = { package = "relm4-components", git = "https://github.com/Relm4/Relm4", tag = "v0.5.0-beta.2"} relm4-components = { package = "relm4-components", git = "https://github.com/Relm4/Relm4", tag = "v0.5.0-beta.3"}
adw = { package = "libadwaita", git = "https://gitlab.gnome.org/World/Rust/libadwaita-rs", features = ["v1_2", "gtk_v4_6"] } adw = { package = "libadwaita", git = "https://gitlab.gnome.org/World/Rust/libadwaita-rs", features = ["v1_2", "gtk_v4_6"] }
gtk = { package = "gtk4", git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_6"] } gtk = { package = "gtk4", git = "https://github.com/gtk-rs/gtk4-rs", features = ["v4_6"] }
tokio = { version = "1.21", features = ["rt", "macros", "time", "rt-multi-thread", "sync", "process"] } tokio = { version = "1.21", features = ["rt", "macros", "time", "rt-multi-thread", "sync", "process"] }
@ -15,12 +15,13 @@ tracker = "0.1"
serde_json = "1.0" serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9" serde_yaml = "0.9"
simd-json = { version = "0.6", features = ["allow-non-simd"] }
nix-editor = "0.2.12" nix-editor = "0.3.0-beta.1"
nix-data = { git = "https://github.com/snowflakelinux/nix-data", rev = "a5168c768e8cf8bd3e1afe1772f8e05e5b03ed95" }
sqlx = { version = "0.6", features = [ "runtime-tokio-native-tls" , "sqlite" ] }
html2pango = "0.5" html2pango = "0.5"
brotli = "3.3"
log = "0.4" log = "0.4"
pretty_env_logger = "0.4" pretty_env_logger = "0.4"
flate2 = "1.0" flate2 = "1.0"
@ -30,11 +31,10 @@ reqwest = { version = "0.11", features = ["blocking"] }
sha256 = "1.0" sha256 = "1.0"
image = "0.24" image = "0.24"
spdx = "0.9" spdx = "0.9"
edit-distance = "2.1"
ijson = "0.1"
strum = "0.24" strum = "0.24"
strum_macros = "0.24" strum_macros = "0.24"
which = "4.3"
anyhow = "1.0"
[workspace] [workspace]
members = [".", "nsc-helper"] members = [".", "nsc-helper"]

View File

@ -2,16 +2,6 @@
, lib ? import <nixpkgs/lib> , lib ? import <nixpkgs/lib>
}: }:
let let
libadwaita-git = pkgs.libadwaita.overrideAttrs (oldAttrs: rec {
version = "1.2.0";
src = pkgs.fetchFromGitLab {
domain = "gitlab.gnome.org";
owner = "GNOME";
repo = "libadwaita";
rev = version;
hash = "sha256-3lH7Vi9M8k+GSrCpvruRpLrIpMoOakKbcJlaAc/FK+U=";
};
});
nixos-appstream-data = (import nixos-appstream-data = (import
(pkgs.fetchFromGitHub { (pkgs.fetchFromGitHub {
owner = "vlinkz"; owner = "vlinkz";
@ -23,14 +13,14 @@ let
in in
pkgs.stdenv.mkDerivation rec { pkgs.stdenv.mkDerivation rec {
pname = "nix-software-center"; pname = "nix-software-center";
version = "0.0.3"; version = "0.1.0";
src = [ ./. ]; src = [ ./. ];
cargoDeps = pkgs.rustPlatform.fetchCargoTarball { cargoDeps = pkgs.rustPlatform.fetchCargoTarball {
inherit src; inherit src;
name = "${pname}-${version}"; name = "${pname}-${version}";
hash = "sha256-8eUFl3N1tVZ2j+S6iIIpFSH5F5fXAl5+Yz3xS/NxF2I="; hash = "sha256-NqjBlNHt9rlej5Y3R6cYDZFwpDIFa3ZmfsxSXaTUOUI=";
}; };
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
@ -54,7 +44,8 @@ pkgs.stdenv.mkDerivation rec {
glib glib
gtk4 gtk4
gtksourceview5 gtksourceview5
libadwaita-git libadwaita
libxml2
openssl openssl
wayland wayland
gnome.adwaita-icon-theme gnome.adwaita-icon-theme

View File

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1664195620, "lastModified": 1665732960,
"narHash": "sha256-/0V1a1gAR+QbiQe4aCxBoivhkxss0xyt2mBD6yDrgjw=", "narHash": "sha256-WBZ+uSHKFyjvd0w4inbm0cNExYTn8lpYFcHEes8tmec=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "62228ccc672ed000f35b1e5c82e4183e46767e52", "rev": "4428e23312933a196724da2df7ab78eb5e67a88e",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -10,16 +10,6 @@
pkgs = import nixpkgs { pkgs = import nixpkgs {
inherit system; inherit system;
}; };
libadwaita-git = pkgs.libadwaita.overrideAttrs (oldAttrs: rec {
version = "1.2.0";
src = pkgs.fetchFromGitLab {
domain = "gitlab.gnome.org";
owner = "GNOME";
repo = "libadwaita";
rev = version;
hash = "sha256-3lH7Vi9M8k+GSrCpvruRpLrIpMoOakKbcJlaAc/FK+U=";
};
});
nixos-appstream-data = pkgs.fetchFromGitHub { nixos-appstream-data = pkgs.fetchFromGitHub {
owner = "vlinkz"; owner = "vlinkz";
repo = "nixos-appstream-data"; repo = "nixos-appstream-data";
@ -58,7 +48,7 @@
graphene graphene
gtk4 gtk4
gtksourceview5 gtksourceview5
libadwaita-git libadwaita
meson meson
ninja ninja
openssl openssl

View File

@ -1,7 +1,7 @@
project( project(
'nix-software-center', 'nix-software-center',
'rust', 'rust',
version: '0.0.3', version: '0.1.0',
meson_version: '>= 0.59', meson_version: '>= 0.59',
license: 'GPL-3.0-only', license: 'GPL-3.0-only',
) )

View File

@ -8,6 +8,5 @@ fn main() {
gio::resources_register(&res); gio::resources_register(&res);
} }
let app = RelmApp::new(nix_software_center::config::APP_ID); let app = RelmApp::new(nix_software_center::config::APP_ID);
let application = app.app.clone(); app.run::<AppModel>(());
app.run::<AppModel>(application);
} }

View File

@ -1,56 +1,15 @@
use std::{ use anyhow::Result;
env, use nix_data::config::configfile::NixDataConfig;
error::Error,
fs::{self, File},
io::Write,
path::Path,
};
use serde::{Deserialize, Serialize}; pub fn getconfig() -> Option<NixDataConfig> {
if let Ok(c) = nix_data::config::configfile::getconfig() {
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
pub struct NscConfig {
pub systemconfig: Option<String>,
pub flake: Option<String>,
pub flakearg: Option<String>,
}
pub fn getconfig() -> Option<NscConfig> {
if let Ok(c) = getconfigval() {
Some(c) Some(c)
} else { } else {
None None
} }
} }
fn getconfigval() -> Result<NscConfig, Box<dyn Error>> { pub fn editconfig(config: NixDataConfig) -> Result<()> {
let configfile = checkconfig()?; nix_data::config::configfile::setuserconfig(config)?;
let config: NscConfig =
serde_json::from_reader(File::open(format!("{}/config.json", configfile))?)?;
Ok(config)
}
fn checkconfig() -> Result<String, Box<dyn Error>> {
let cfgdir = format!("{}/.config/nix-software-center", env::var("HOME")?);
if !Path::is_file(Path::new(&format!("{}/config.json", &cfgdir))) {
if !Path::is_file(Path::new("/etc/nix-software-center/config.json")) {
Err(Box::new(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"No config file found",
)))
} else {
Ok("/etc/nix-software-center/".to_string())
}
} else {
Ok(cfgdir)
}
}
pub fn editconfig(config: NscConfig) -> Result<(), Box<dyn Error>> {
let cfgdir = format!("{}/.config/nix-software-center", env::var("HOME")?);
fs::create_dir_all(&cfgdir)?;
let json = serde_json::to_string_pretty(&config)?;
let mut file = File::create(format!("{}/config.json", cfgdir))?;
file.write_all(json.as_bytes())?;
Ok(()) Ok(())
} }

View File

@ -1,3 +1,3 @@
pub mod cache; // pub mod cache;
pub mod packages; pub mod packages;
pub mod config; pub mod config;

View File

@ -1,91 +1,58 @@
use flate2::bufread::GzDecoder; use flate2::bufread::GzDecoder;
use ijson::IString;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fs; use std::{self, fs::File, collections::HashMap, io::{BufReader, Read}};
use std::io::Read;
use std::{self, fs::File, collections::HashMap, error::Error, env, io::BufReader};
use log::*; use log::*;
use anyhow::Result;
use crate::APPINFO; use crate::APPINFO;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
pub struct PackageBase {
packages: HashMap<String, Package>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Package {
pub system: IString,
pub pname: IString,
pub meta: Meta,
pub version: IString,
#[serde(skip_deserializing)]
pub appdata: Option<AppData>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Meta {
pub broken: Option<bool>,
pub insecure: Option<bool>,
pub unsupported: Option<bool>,
pub unfree: Option<bool>,
pub description: Option<IString>,
#[serde(rename = "longDescription")]
pub longdescription: Option<IString>,
pub homepage: Option<StrOrVec>,
pub maintainers: Option<ijson::IValue>,
pub position: Option<IString>,
pub license: Option<LicenseEnum>,
pub platforms: Option<Platform>
}
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
#[serde(untagged)] #[serde(untagged)]
pub enum StrOrVec { pub enum StrOrVec {
Single(IString), Single(String),
List(Vec<IString>), List(Vec<String>),
} }
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(untagged)] #[serde(untagged)]
pub enum Platform { pub enum Platform {
Single(IString), Single(String),
List(Vec<IString>), List(Vec<String>),
ListList(Vec<Vec<IString>>), ListList(Vec<Vec<String>>),
} }
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
#[serde(untagged)] #[serde(untagged)]
pub enum LicenseEnum { pub enum LicenseEnum {
Single(License), Single(License),
List(Vec<License>), List(Vec<License>),
SingleStr(IString), SingleStr(String),
VecStr(Vec<IString>), VecStr(Vec<String>),
Mixed(Vec<LicenseEnum>) Mixed(Vec<LicenseEnum>)
} }
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
pub struct License { pub struct License {
pub free: Option<bool>, pub free: Option<bool>,
#[serde(rename = "fullName")] #[serde(rename = "fullName")]
pub fullname: Option<IString>, pub fullname: Option<String>,
#[serde(rename = "spdxId")] #[serde(rename = "spdxId")]
pub spdxid: Option<IString>, pub spdxid: Option<String>,
pub url: Option<IString>, pub url: Option<String>,
} }
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
pub struct PkgMaintainer { pub struct PkgMaintainer {
pub email: Option<IString>, pub email: Option<String>,
pub github: Option<IString>, pub github: Option<String>,
pub matrix: Option<IString>, pub matrix: Option<String>,
pub name: Option<IString> pub name: Option<String>
} }
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct AppData { pub struct AppData {
#[serde(rename = "Type")] #[serde(rename = "Type")]
pub metatype: IString, pub metatype: String,
#[serde(rename = "ID")] #[serde(rename = "ID")]
pub id: String, pub id: String,
#[serde(rename = "Package")] #[serde(rename = "Package")]
@ -110,7 +77,7 @@ pub struct AppData {
pub categories: Option<Vec<String>>, pub categories: Option<Vec<String>>,
} }
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct AppUrl { pub struct AppUrl {
pub homepage: Option<String>, pub homepage: Option<String>,
pub bugtracker: Option<String>, pub bugtracker: Option<String>,
@ -118,27 +85,27 @@ pub struct AppUrl {
pub donation: Option<String>, pub donation: Option<String>,
} }
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct AppIconList { pub struct AppIconList {
pub cached: Option<Vec<AppIcon>>, pub cached: Option<Vec<AppIcon>>,
pub stock: Option<String>, pub stock: Option<String>,
// TODO: add support for other icon types // TODO: add support for other icon types
} }
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct AppIcon { pub struct AppIcon {
pub name: String, pub name: String,
pub width: u32, pub width: u32,
pub height: u32, pub height: u32,
} }
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct AppLaunchable { pub struct AppLaunchable {
#[serde(rename = "desktop-id")] #[serde(rename = "desktop-id")]
pub desktopid: Vec<String> pub desktopid: Vec<String>
} }
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct AppProvides { pub struct AppProvides {
pub binaries: Option<Vec<String>>, pub binaries: Option<Vec<String>>,
pub ids: Option<Vec<String>>, pub ids: Option<Vec<String>>,
@ -146,7 +113,7 @@ pub struct AppProvides {
pub libraries: Option<Vec<String>>, pub libraries: Option<Vec<String>>,
} }
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct AppScreenshot { pub struct AppScreenshot {
pub default: Option<bool>, pub default: Option<bool>,
pub thumbnails: Option<Vec<String>>, pub thumbnails: Option<Vec<String>>,
@ -154,33 +121,12 @@ pub struct AppScreenshot {
pub sourceimage: Option<AppScreenshotImage>, pub sourceimage: Option<AppScreenshotImage>,
} }
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct AppScreenshotImage { pub struct AppScreenshotImage {
pub url: String, pub url: String,
} }
#[derive(Debug, Serialize, Deserialize)] pub fn appsteamdata() -> Result<HashMap<String, AppData>> {
struct FlakePkgs {
packages: HashMap<String, FlakeJson>
}
#[derive(Debug, Serialize, Deserialize)]
struct FlakeJson {
pname: IString,
version: IString,
}
pub async fn readpkgs() -> Result<HashMap<String, Package>, Box<dyn Error + Send + Sync>> {
info!("Reading package list");
let cachedir = format!("{}/.cache/nix-software-center/", env::var("HOME")?);
let cachefile = format!("{}/packages.json", cachedir);
let file = File::open(cachefile)?;
let reader = BufReader::new(file);
trace!("Reading packages.json");
let pkgbase: PackageBase = simd_json::serde::from_reader(reader)?;
trace!("Finished reading packages.json");
let mut pkgs = pkgbase.packages;
debug!("APPDATADIR {}", APPINFO);
let appdata = File::open(&format!("{}/xmls/nixos_x86_64_linux.yml.gz", APPINFO))?; let appdata = File::open(&format!("{}/xmls/nixos_x86_64_linux.yml.gz", APPINFO))?;
let appreader = BufReader::new(appdata); let appreader = BufReader::new(appdata);
let mut d = GzDecoder::new(appreader); let mut d = GzDecoder::new(appreader);
@ -188,61 +134,15 @@ pub async fn readpkgs() -> Result<HashMap<String, Package>, Box<dyn Error + Sen
d.read_to_string(&mut s)?; d.read_to_string(&mut s)?;
let mut files = s.split("\n---\n").collect::<Vec<_>>(); let mut files = s.split("\n---\n").collect::<Vec<_>>();
files.remove(0); files.remove(0);
let mut out = HashMap::new();
for f in files { for f in files {
if let Ok(appstream) = serde_yaml::from_str::<AppData>(f) { if let Ok(appstream) = serde_yaml::from_str::<AppData>(f) {
if let Some(p) = pkgs.get_mut(&appstream.package.to_string()) { out.insert(appstream.package.to_string(), appstream);
p.appdata = Some(appstream);
}
} else { } else {
warn!("Failed to parse some appstream data"); warn!("Failed to parse some appstream data");
} }
} }
Ok(pkgs) Ok(out)
} }
pub fn readlegacysyspkgs() -> Result<HashMap<String, String>, Box<dyn Error + Send + Sync>> {
info!("Reading legacy system package list");
let cachedir = format!("{}/.cache/nix-software-center/", env::var("HOME")?);
let cachefile = format!("{}/syspackages.json", cachedir);
if let Ok(f) = fs::read_to_string(&cachefile) {
if f.trim().is_empty() {
return Ok(HashMap::new());
}
}
let file = File::open(cachefile)?;
let reader = BufReader::new(file);
let newpkgs: HashMap<String, String> = simd_json::serde::from_reader(reader)?;
Ok(newpkgs)
}
pub fn readflakesyspkgs() -> Result<HashMap<String, String>, Box<dyn Error + Send + Sync>> {
info!("Reading flake system package list");
let cachedir = format!("{}/.cache/nix-software-center/", env::var("HOME")?);
let cachefile = format!("{}/syspackages.json", cachedir);
if let Ok(f) = fs::read_to_string(&cachefile) {
if f.trim().is_empty() {
return Ok(HashMap::new());
}
}
let file = File::open(cachefile)?;
let reader = BufReader::new(file);
let newpkgs: HashMap<String, FlakeJson> = simd_json::serde::from_reader(reader)?;
let newpkgs = newpkgs.into_iter().filter_map(|(k, v)| if let Some(pkg) = k.strip_prefix("legacyPackages.x86_64-linux.") { Some((pkg.to_string(), v.version.to_string())) } else { None }).collect::<HashMap<_, _>>();
Ok(newpkgs)
}
pub fn readprofilepkgs() -> Result<HashMap<String, String>, Box<dyn Error + Send + Sync>> {
info!("Reading profile package list");
let cachedir = format!("{}/.cache/nix-software-center/", env::var("HOME")?);
let cachefile = format!("{}/profilepackages.json", cachedir);
if let Ok(f) = fs::read_to_string(&cachefile) {
if f.trim().is_empty() {
return Ok(HashMap::new());
}
}
let file = File::open(cachefile)?;
let reader = BufReader::new(file);
let profilepkgs: FlakePkgs = simd_json::serde::from_reader(reader)?;
let profilepkgs = profilepkgs.packages.into_iter().map(|(pkg, v)| (pkg.to_string(), v.version.to_string())).collect::<HashMap<_, _>>();
Ok(profilepkgs)
}

View File

@ -17,7 +17,7 @@ pub enum AboutPageMsg {
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for AboutPageModel { impl SimpleComponent for AboutPageModel {
type InitParams = gtk::Window; type Init = gtk::Window;
type Input = AboutPageMsg; type Input = AboutPageMsg;
type Output = AppMsg; type Output = AppMsg;
type Widgets = AboutPageWidgets; type Widgets = AboutPageWidgets;
@ -40,7 +40,7 @@ impl SimpleComponent for AboutPageModel {
} }
fn init( fn init(
parent_window: Self::InitParams, parent_window: Self::Init,
root: &Self::Root, root: &Self::Root,
_sender: ComponentSender<Self>, _sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {

View File

@ -5,7 +5,7 @@ use strum_macros::{EnumIter, Display};
use super::window::AppMsg; use super::window::AppMsg;
#[derive(Debug, PartialEq)] #[derive(Debug)]
pub struct PkgGroup { pub struct PkgGroup {
pub category: PkgCategory, pub category: PkgCategory,
} }
@ -33,7 +33,7 @@ impl FactoryComponent for PkgGroup {
type Output = PkgCategoryMsg; type Output = PkgCategoryMsg;
type Widgets = PkgGroupWidgets; type Widgets = PkgGroupWidgets;
type ParentWidget = gtk::FlowBox; type ParentWidget = gtk::FlowBox;
type ParentMsg = AppMsg; type ParentInput = AppMsg;
view! { view! {
gtk::FlowBoxChild { gtk::FlowBoxChild {
@ -95,7 +95,7 @@ impl FactoryComponent for PkgGroup {
} }
} }
fn output_to_parent_msg(output: Self::Output) -> Option<AppMsg> { fn output_to_parent_input(output: Self::Output) -> Option<AppMsg> {
Some(match output { Some(match output {
PkgCategoryMsg::Open(x) => AppMsg::OpenCategoryPage(x), PkgCategoryMsg::Open(x) => AppMsg::OpenCategoryPage(x),
}) })

View File

@ -1,6 +1,7 @@
use super::{window::*, categories::PkgCategory, categorytile::CategoryTile}; use super::{window::*, categories::PkgCategory, categorytile::CategoryTile};
use adw::prelude::*; use adw::prelude::*;
use relm4::{factory::*, *}; use relm4::{factory::*, *};
use log::*;
#[tracker::track] #[tracker::track]
#[derive(Debug)] #[derive(Debug)]
@ -22,12 +23,19 @@ pub enum CategoryPageMsg {
UpdateInstalled(Vec<String>, Vec<String>) UpdateInstalled(Vec<String>, Vec<String>)
} }
#[derive(Debug)]
pub enum CategoryPageAsyncMsg {
PushRec(CategoryTile),
Push(CategoryTile),
}
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for CategoryPageModel { impl Component for CategoryPageModel {
type InitParams = (); type Init = ();
type Input = CategoryPageMsg; type Input = CategoryPageMsg;
type Output = AppMsg; type Output = AppMsg;
type Widgets = CategoryPageWidgets; type Widgets = CategoryPageWidgets;
type CommandOutput = CategoryPageAsyncMsg;
view! { view! {
gtk::Box { gtk::Box {
@ -59,11 +67,14 @@ impl SimpleComponent for CategoryPageModel {
set_maximum_size: 1000, set_maximum_size: 1000,
set_tightening_threshold: 750, set_tightening_threshold: 750,
if model.busy { if model.busy {
#[name(spinner)]
gtk::Spinner { gtk::Spinner {
set_hexpand: true,
set_vexpand: true,
set_halign: gtk::Align::Center, set_halign: gtk::Align::Center,
set_valign: gtk::Align::Center, set_valign: gtk::Align::Center,
set_spinning: true, set_spinning: true,
set_height_request: 32, set_size_request: (64, 64),
} }
} else { } else {
gtk::Box { gtk::Box {
@ -115,14 +126,14 @@ impl SimpleComponent for CategoryPageModel {
} }
fn init( fn init(
(): Self::InitParams, (): Self::Init,
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let model = CategoryPageModel { let model = CategoryPageModel {
category: PkgCategory::Audio, category: PkgCategory::Audio,
recommendedapps: FactoryVecDeque::new(gtk::FlowBox::new(), &sender.input), recommendedapps: FactoryVecDeque::new(gtk::FlowBox::new(), sender.input_sender()),
apps: FactoryVecDeque::new(gtk::FlowBox::new(), &sender.input), apps: FactoryVecDeque::new(gtk::FlowBox::new(), sender.input_sender()),
busy: true, busy: true,
tracker: 0 tracker: 0
}; };
@ -139,30 +150,39 @@ impl SimpleComponent for CategoryPageModel {
self.reset(); self.reset();
match msg { match msg {
CategoryPageMsg::Close => { CategoryPageMsg::Close => {
let mut recapps_guard = self.recommendedapps.guard(); // let mut recapps_guard = self.recommendedapps.guard();
let mut apps_guard = self.apps.guard(); // let mut apps_guard = self.apps.guard();
recapps_guard.clear(); // recapps_guard.clear();
apps_guard.clear(); // apps_guard.clear();
sender.output(AppMsg::FrontFrontPage) sender.output(AppMsg::FrontFrontPage)
} }
CategoryPageMsg::OpenPkg(pkg) => { CategoryPageMsg::OpenPkg(pkg) => {
sender.output(AppMsg::OpenPkg(pkg)) sender.output(AppMsg::OpenPkg(pkg))
} }
CategoryPageMsg::Open(category, catrec, catall) => { CategoryPageMsg::Open(category, catrec, catall) => {
info!("CategoryPageMsg::Open");
self.set_category(category); self.set_category(category);
let mut recapps_guard = self.recommendedapps.guard(); let mut recapps_guard = self.recommendedapps.guard();
recapps_guard.clear(); recapps_guard.clear();
recapps_guard.drop();
for app in catrec { for app in catrec {
recapps_guard.push_back(app); sender.oneshot_command(async move {
CategoryPageAsyncMsg::PushRec(app)
});
} }
let mut apps_guard = self.apps.guard(); let mut apps_guard = self.apps.guard();
apps_guard.clear(); apps_guard.clear();
apps_guard.drop();
for app in catall { for app in catall {
apps_guard.push_back(app); sender.oneshot_command(async move {
CategoryPageAsyncMsg::Push(app)
});
} }
self.busy = false; self.busy = false;
info!("DONE CategoryPageMsg::Open");
} }
CategoryPageMsg::Loading(category) => { CategoryPageMsg::Loading(category) => {
info!("CategoryPageMsg::Loading");
self.set_category(category); self.set_category(category);
self.busy = true; self.busy = true;
} }
@ -199,4 +219,19 @@ impl SimpleComponent for CategoryPageModel {
} }
} }
fn update_cmd(&mut self, msg: Self::CommandOutput, _sender: ComponentSender<Self>) {
match msg {
CategoryPageAsyncMsg::PushRec(tile) => {
let mut recapps_guard = self.recommendedapps.guard();
recapps_guard.push_back(tile);
recapps_guard.drop();
}
CategoryPageAsyncMsg::Push(tile) => {
let mut apps_guard = self.apps.guard();
apps_guard.push_back(tile);
apps_guard.drop();
}
}
}
} }

View File

@ -7,7 +7,7 @@ use relm4::adw::prelude::*;
use relm4::gtk::pango; use relm4::gtk::pango;
use relm4::{factory::*, *}; use relm4::{factory::*, *};
#[derive(Default, Debug, PartialEq, Clone)] #[derive(Default, Debug, PartialEq, Eq, Clone)]
pub struct CategoryTile { pub struct CategoryTile {
pub name: String, pub name: String,
pub pkg: String, pub pkg: String,
@ -31,7 +31,7 @@ impl FactoryComponent for CategoryTile {
type Output = CategoryTileMsg; type Output = CategoryTileMsg;
type Widgets = CategoryTileWidgets; type Widgets = CategoryTileWidgets;
type ParentWidget = gtk::FlowBox; type ParentWidget = gtk::FlowBox;
type ParentMsg = CategoryPageMsg; type ParentInput = CategoryPageMsg;
view! { view! {
gtk::FlowBoxChild { gtk::FlowBoxChild {
@ -176,7 +176,7 @@ impl FactoryComponent for CategoryTile {
} }
} }
fn output_to_parent_msg(output: Self::Output) -> Option<CategoryPageMsg> { fn output_to_parent_input(output: Self::Output) -> Option<CategoryPageMsg> {
Some(match output { Some(match output {
CategoryTileMsg::Open(x) => CategoryPageMsg::OpenPkg(x), CategoryTileMsg::Open(x) => CategoryPageMsg::OpenPkg(x),
}) })

View File

@ -28,7 +28,7 @@ pub enum InstalledPageMsg {
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for InstalledPageModel { impl SimpleComponent for InstalledPageModel {
type InitParams = (SystemPkgs, UserPkgs); type Init = (SystemPkgs, UserPkgs);
type Input = InstalledPageMsg; type Input = InstalledPageMsg;
type Output = AppMsg; type Output = AppMsg;
type Widgets = InstalledPageWidgets; type Widgets = InstalledPageWidgets;
@ -93,13 +93,13 @@ impl SimpleComponent for InstalledPageModel {
} }
fn init( fn init(
(systempkgtype, userpkgtype): Self::InitParams, (systempkgtype, userpkgtype): Self::Init,
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let model = InstalledPageModel { let model = InstalledPageModel {
installeduserlist: FactoryVecDeque::new(gtk::ListBox::new(), &sender.input), installeduserlist: FactoryVecDeque::new(gtk::ListBox::new(), sender.input_sender()),
installedsystemlist: FactoryVecDeque::new(gtk::ListBox::new(), &sender.input), installedsystemlist: FactoryVecDeque::new(gtk::ListBox::new(), sender.input_sender()),
updatetracker: 0, updatetracker: 0,
userpkgtype, userpkgtype,
systempkgtype, systempkgtype,
@ -196,7 +196,7 @@ impl SimpleComponent for InstalledPageModel {
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub struct InstalledItem { pub struct InstalledItem {
pub name: String, pub name: String,
pub pkg: Option<String>, pub pkg: Option<String>,
@ -207,7 +207,7 @@ pub struct InstalledItem {
pub busy: bool, pub busy: bool,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
pub struct InstalledItemModel { pub struct InstalledItemModel {
pub item: InstalledItem, pub item: InstalledItem,
} }
@ -230,7 +230,7 @@ impl FactoryComponent for InstalledItemModel {
type Output = InstalledItemMsg; type Output = InstalledItemMsg;
type Widgets = InstalledItemWidgets; type Widgets = InstalledItemWidgets;
type ParentWidget = adw::gtk::ListBox; type ParentWidget = adw::gtk::ListBox;
type ParentMsg = InstalledPageMsg; type ParentInput = InstalledPageMsg;
view! { view! {
adw::PreferencesRow { adw::PreferencesRow {
@ -363,7 +363,7 @@ impl FactoryComponent for InstalledItemModel {
} }
} }
fn output_to_parent_msg(output: Self::Output) -> Option<InstalledPageMsg> { fn output_to_parent_input(output: Self::Output) -> Option<InstalledPageMsg> {
Some(match output { Some(match output {
InstalledItemMsg::Delete(item) => InstalledPageMsg::Remove(item), InstalledItemMsg::Delete(item) => InstalledPageMsg::Remove(item),
}) })

View File

@ -1,8 +1,7 @@
use crate::parse::config::NscConfig;
use super::pkgpage::{InstallType, PkgAction, PkgMsg, WorkPkg}; use super::pkgpage::{InstallType, PkgAction, PkgMsg, WorkPkg};
use super::window::{SystemPkgs, UserPkgs}; use super::window::{SystemPkgs, UserPkgs};
use log::*; use log::*;
use nix_data::config::configfile::NixDataConfig;
use relm4::*; use relm4::*;
use std::error::Error; use std::error::Error;
use std::path::Path; use std::path::Path;
@ -25,7 +24,7 @@ pub struct InstallAsyncHandler {
#[derive(Debug)] #[derive(Debug)]
pub enum InstallAsyncHandlerMsg { pub enum InstallAsyncHandlerMsg {
SetConfig(NscConfig), SetConfig(NixDataConfig),
SetPkgTypes(SystemPkgs, UserPkgs), SetPkgTypes(SystemPkgs, UserPkgs),
Process(WorkPkg), Process(WorkPkg),
CancelProcess, CancelProcess,
@ -39,11 +38,11 @@ pub struct InstallAsyncHandlerInit {
} }
impl Worker for InstallAsyncHandler { impl Worker for InstallAsyncHandler {
type InitParams = InstallAsyncHandlerInit; type Init = InstallAsyncHandlerInit;
type Input = InstallAsyncHandlerMsg; type Input = InstallAsyncHandlerMsg;
type Output = PkgMsg; type Output = PkgMsg;
fn init(params: Self::InitParams, _sender: relm4::ComponentSender<Self>) -> Self { fn init(params: Self::Init, _sender: relm4::ComponentSender<Self>) -> Self {
Self { Self {
process: None, process: None,
work: None, work: None,

View File

@ -2,6 +2,7 @@ use adw::gio;
use adw::prelude::*; use adw::prelude::*;
use html2pango; use html2pango;
use image::{imageops::FilterType, ImageFormat}; use image::{imageops::FilterType, ImageFormat};
use nix_data::config::configfile::NixDataConfig;
use relm4::actions::RelmAction; use relm4::actions::RelmAction;
use relm4::actions::RelmActionGroup; use relm4::actions::RelmActionGroup;
use relm4::gtk::pango; use relm4::gtk::pango;
@ -22,9 +23,7 @@ use std::{
}; };
use log::*; use log::*;
use crate::parse::config::NscConfig;
use crate::parse::packages::PkgMaintainer; use crate::parse::packages::PkgMaintainer;
use crate::parse::packages::StrOrVec;
use crate::ui::installworker::InstallAsyncHandlerMsg; use crate::ui::installworker::InstallAsyncHandlerMsg;
use super::installworker::InstallAsyncHandler; use super::installworker::InstallAsyncHandler;
@ -36,7 +35,7 @@ use super::{screenshotfactory::ScreenshotItem, window::AppMsg};
#[tracker::track] #[tracker::track]
#[derive(Debug)] #[derive(Debug)]
pub struct PkgModel { pub struct PkgModel {
config: NscConfig, config: NixDataConfig,
name: String, name: String,
pkg: String, pkg: String,
pname: String, pname: String,
@ -87,13 +86,13 @@ pub enum PkgAction {
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
pub enum Launch { pub enum Launch {
GtkApp(String), GtkApp(String),
TerminalApp(String), TerminalApp(String),
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
pub enum CarouselPage { pub enum CarouselPage {
First, First,
Middle, Middle,
@ -107,7 +106,7 @@ pub enum InstallType {
System, System,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
pub struct License { pub struct License {
pub free: Option<bool>, pub free: Option<bool>,
pub fullname: String, pub fullname: String,
@ -126,7 +125,7 @@ pub struct PkgInitModel {
pub description: Option<String>, pub description: Option<String>,
pub icon: Option<String>, pub icon: Option<String>,
pub screenshots: Vec<String>, pub screenshots: Vec<String>,
pub homepage: Option<StrOrVec>, pub homepage: Option<String>,
pub licenses: Vec<License>, pub licenses: Vec<License>,
pub platforms: Vec<String>, pub platforms: Vec<String>,
pub maintainers: Vec<PkgMaintainer>, pub maintainers: Vec<PkgMaintainer>,
@ -135,7 +134,7 @@ pub struct PkgInitModel {
#[derive(Debug)] #[derive(Debug)]
pub enum PkgMsg { pub enum PkgMsg {
UpdateConfig(NscConfig), UpdateConfig(NixDataConfig),
UpdatePkgTypes(SystemPkgs, UserPkgs), UpdatePkgTypes(SystemPkgs, UserPkgs),
Open(Box<PkgInitModel>), Open(Box<PkgInitModel>),
LoadScreenshot(String, usize, String), LoadScreenshot(String, usize, String),
@ -168,7 +167,7 @@ pub enum PkgAsyncMsg {
pub struct PkgPageInit { pub struct PkgPageInit {
pub syspkgs: SystemPkgs, pub syspkgs: SystemPkgs,
pub userpkgs: UserPkgs, pub userpkgs: UserPkgs,
pub config: NscConfig, pub config: NixDataConfig,
} }
#[relm4::component(pub)] #[relm4::component(pub)]
@ -1123,22 +1122,23 @@ impl Component for PkgModel {
self.description = Some(pango.strip_prefix('\n').unwrap_or(&pango).to_string()); self.description = Some(pango.strip_prefix('\n').unwrap_or(&pango).to_string());
} }
if let Some(h) = pkgmodel.homepage { self.homepage = pkgmodel.homepage;
match h { // if let Some(h) = pkgmodel.homepage {
StrOrVec::Single(h) => { // match h {
self.homepage = Some(h.to_string()); // StrOrVec::Single(h) => {
} // self.homepage = Some(h.to_string());
StrOrVec::List(h) => { // }
if let Some(first) = h.get(0) { // StrOrVec::List(h) => {
self.homepage = Some(first.to_string()); // if let Some(first) = h.get(0) {
} else { // self.homepage = Some(first.to_string());
self.homepage = None; // } else {
} // self.homepage = None;
} // }
} // }
} else { // }
self.homepage = None; // } else {
} // self.homepage = None;
// }
if pkgmodel.screenshots.len() <= 1 { if pkgmodel.screenshots.len() <= 1 {
self.carpage = CarouselPage::Single; self.carpage = CarouselPage::Single;
@ -1150,14 +1150,14 @@ impl Component for PkgModel {
let mut scrn_guard = self.screenshots.guard(); let mut scrn_guard = self.screenshots.guard();
scrn_guard.clear(); scrn_guard.clear();
for _i in 0..pkgmodel.screenshots.len() { for _i in 0..pkgmodel.screenshots.len() {
scrn_guard.push_back(()) scrn_guard.push_back(());
} }
} }
for (i, url) in pkgmodel.screenshots.into_iter().enumerate() { for (i, url) in pkgmodel.screenshots.into_iter().enumerate() {
if let Ok(home) = env::var("HOME") { if let Ok(home) = env::var("HOME") {
let cachedir = format!("{}/.cache/nix-software-center", home); let cachedir = format!("{}/.cache/nix-software-center", home);
let sha = digest(&url); let sha = digest(url.to_string());
let scrnpath = format!("{}/screenshots/{}", cachedir, sha); let scrnpath = format!("{}/screenshots/{}", cachedir, sha);
let pkg = self.pkg.clone(); let pkg = self.pkg.clone();
@ -1289,13 +1289,13 @@ impl Component for PkgModel {
} }
} }
PkgMsg::Close => { PkgMsg::Close => {
self.pkg = String::default(); // self.pkg = String::default();
self.name = String::default(); // self.name = String::default();
self.summary = None; // self.summary = None;
self.description = None; // self.description = None;
self.icon = None; // self.icon = None;
let mut scrn_guard = self.screenshots.guard(); // let mut scrn_guard = self.screenshots.guard();
scrn_guard.clear(); // scrn_guard.clear();
sender.output(AppMsg::FrontPage) sender.output(AppMsg::FrontPage)
} }
PkgMsg::InstallUser => { PkgMsg::InstallUser => {
@ -1391,10 +1391,11 @@ impl Component for PkgModel {
self.installedsystempkgs.remove(&work.pkg); self.installedsystempkgs.remove(&work.pkg);
} }
}; };
sender.output(AppMsg::UpdateUpdatePkgs); // sender.output(AppMsg::UpdateUpdatePkgs);
// sender.output(AppMsg::UpdateInstalledPkgs);
} }
} }
sender.output(AppMsg::UpdatePkgs(None)); sender.output(AppMsg::UpdateInstalledPkgs);
if let Some(n) = &work.notify { if let Some(n) = &work.notify {
match n { match n {
NotifyPage::Installed => { NotifyPage::Installed => {
@ -1556,29 +1557,7 @@ impl Component for PkgModel {
} }
fn launchterm(cmd: &str) { fn launchterm(cmd: &str) {
if which::which("kgx").is_ok() { let _ = Command::new("kgx").arg("-e").arg(&cmd).spawn();
let _ = Command::new("kgx").arg("-e").arg(&cmd).spawn();
} else if which::which("gnome-terminal").is_ok() {
let _ = Command::new("gnome-terminal").arg("--").arg(&cmd).spawn();
} else if which::which("konsole").is_ok() {
let _ = Command::new("konsole").arg("-e").arg(&cmd).spawn();
} else if which::which("mate-terminal").is_ok() {
let _ = Command::new("mate-terminal").arg("-e").arg(&cmd).spawn();
} else if which::which("xfce4-terminal").is_ok() {
let _ = Command::new("xfce4-terminal").arg("-e").arg(&cmd).spawn();
} else if which::which("tilix").is_ok() {
let _ = Command::new("tilix").arg("-e").arg(&cmd).spawn();
} else if which::which("terminology").is_ok() {
let _ = Command::new("terminology").arg("-e").arg(&cmd).spawn();
} else if which::which("alacritty").is_ok() {
let _ = Command::new("alacritty").arg("-e").arg(&cmd).spawn();
} else if which::which("urxvt").is_ok() {
let _ = Command::new("urxvt").arg("-e").arg(&cmd).spawn();
} else if which::which("xterm").is_ok() {
let _ = Command::new("xterm").arg("-e").arg(&cmd).spawn();
} else {
error!("No terminal detected!")
}
} }
relm4::new_action_group!(ModeActionGroup, "mode"); relm4::new_action_group!(ModeActionGroup, "mode");

View File

@ -8,7 +8,7 @@ use crate::APPINFO;
use super::window::AppMsg; use super::window::AppMsg;
#[derive(Default, Debug, PartialEq)] #[derive(Default, Debug, PartialEq, Eq)]
pub struct PkgTile { pub struct PkgTile {
pub name: String, pub name: String,
pub pkg: String, pub pkg: String,
@ -32,7 +32,7 @@ impl FactoryComponent for PkgTile {
type Output = PkgTileMsg; type Output = PkgTileMsg;
type Widgets = PkgTileWidgets; type Widgets = PkgTileWidgets;
type ParentWidget = gtk::FlowBox; type ParentWidget = gtk::FlowBox;
type ParentMsg = AppMsg; type ParentInput = AppMsg;
view! { view! {
gtk::FlowBoxChild { gtk::FlowBoxChild {
@ -171,7 +171,7 @@ impl FactoryComponent for PkgTile {
} }
} }
fn output_to_parent_msg(output: Self::Output) -> Option<AppMsg> { fn output_to_parent_input(output: Self::Output) -> Option<AppMsg> {
Some(match output { Some(match output {
PkgTileMsg::Open(x) => AppMsg::OpenPkg(x), PkgTileMsg::Open(x) => AppMsg::OpenPkg(x),
}) })

View File

@ -1,9 +1,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use crate::parse::config::NscConfig;
use super::window::AppMsg; use super::window::AppMsg;
use adw::prelude::*; use adw::prelude::*;
use nix_data::config::configfile::NixDataConfig;
use relm4::*; use relm4::*;
use relm4_components::open_dialog::*; use relm4_components::open_dialog::*;
@ -22,7 +20,7 @@ pub struct PreferencesPageModel {
#[derive(Debug)] #[derive(Debug)]
pub enum PreferencesPageMsg { pub enum PreferencesPageMsg {
Show(NscConfig), Show(NixDataConfig),
Open, Open,
OpenFlake, OpenFlake,
SetConfigPath(Option<PathBuf>), SetConfigPath(Option<PathBuf>),
@ -34,7 +32,7 @@ pub enum PreferencesPageMsg {
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for PreferencesPageModel { impl SimpleComponent for PreferencesPageModel {
type InitParams = gtk::Window; type Init = gtk::Window;
type Input = PreferencesPageMsg; type Input = PreferencesPageMsg;
type Output = AppMsg; type Output = AppMsg;
type Widgets = PreferencesPageWidgets; type Widgets = PreferencesPageWidgets;
@ -165,7 +163,7 @@ impl SimpleComponent for PreferencesPageModel {
} @flakeentry, } @flakeentry,
#[track(model.changed(PreferencesPageModel::flake()))] #[track(model.changed(PreferencesPageModel::flake()))]
#[block_signal(flakeentry)] #[block_signal(flakeentry)]
set_text: &model.flakearg.as_ref().unwrap_or(&String::new()) set_text: model.flakearg.as_ref().unwrap_or(&String::new())
} }
} }
@ -174,21 +172,21 @@ impl SimpleComponent for PreferencesPageModel {
} }
fn init( fn init(
parent_window: Self::InitParams, parent_window: Self::Init,
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let open_dialog = OpenDialog::builder() let open_dialog = OpenDialog::builder()
.transient_for_native(root) .transient_for_native(root)
.launch(OpenDialogSettings::default()) .launch(OpenDialogSettings::default())
.forward(&sender.input, |response| match response { .forward(sender.input_sender(), |response| match response {
OpenDialogResponse::Accept(path) => PreferencesPageMsg::SetConfigPath(Some(path)), OpenDialogResponse::Accept(path) => PreferencesPageMsg::SetConfigPath(Some(path)),
OpenDialogResponse::Cancel => PreferencesPageMsg::Ignore, OpenDialogResponse::Cancel => PreferencesPageMsg::Ignore,
}); });
let flake_file_dialog = OpenDialog::builder() let flake_file_dialog = OpenDialog::builder()
.transient_for_native(root) .transient_for_native(root)
.launch(OpenDialogSettings::default()) .launch(OpenDialogSettings::default())
.forward(&sender.input, |response| match response { .forward(sender.input_sender(), |response| match response {
OpenDialogResponse::Accept(path) => PreferencesPageMsg::SetFlakePath(Some(path)), OpenDialogResponse::Accept(path) => PreferencesPageMsg::SetFlakePath(Some(path)),
OpenDialogResponse::Cancel => PreferencesPageMsg::Ignore, OpenDialogResponse::Cancel => PreferencesPageMsg::Ignore,
}); });
@ -211,9 +209,9 @@ impl SimpleComponent for PreferencesPageModel {
self.reset(); self.reset();
match msg { match msg {
PreferencesPageMsg::Show(config) => { PreferencesPageMsg::Show(config) => {
self.configpath = config.systemconfig.as_ref().map(|x| PathBuf::from(x)); self.configpath = config.systemconfig.as_ref().map(PathBuf::from);
self.set_flake(config.flake.as_ref().map(|x| PathBuf::from(x))); self.set_flake(config.flake.as_ref().map(PathBuf::from));
self.set_flakearg(config.flakearg.clone()); self.set_flakearg(config.flakearg);
self.hidden = false; self.hidden = false;
} }
PreferencesPageMsg::Open => self.open_dialog.emit(OpenDialogMsg::Open), PreferencesPageMsg::Open => self.open_dialog.emit(OpenDialogMsg::Open),

View File

@ -3,7 +3,7 @@ use relm4::{factory::*, *};
use super::pkgpage::PkgMsg; use super::pkgpage::PkgMsg;
#[derive(Default, Debug, PartialEq)] #[derive(Default, Debug, PartialEq, Eq)]
pub struct ScreenshotItem { pub struct ScreenshotItem {
pub path: Option<String>, pub path: Option<String>,
pub error: bool, pub error: bool,
@ -20,7 +20,7 @@ impl FactoryComponent for ScreenshotItem {
type Output = ScreenshotItemMsg; type Output = ScreenshotItemMsg;
type Widgets = PkgTileWidgets; type Widgets = PkgTileWidgets;
type ParentWidget = adw::Carousel; type ParentWidget = adw::Carousel;
type ParentMsg = PkgMsg; type ParentInput = PkgMsg;
view! { view! {
gtk::Box { gtk::Box {

View File

@ -25,7 +25,7 @@ pub enum SearchPageMsg {
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for SearchPageModel { impl SimpleComponent for SearchPageModel {
type InitParams = (); type Init = ();
type Input = SearchPageMsg; type Input = SearchPageMsg;
type Output = AppMsg; type Output = AppMsg;
type Widgets = SearchPageWidgets; type Widgets = SearchPageWidgets;
@ -53,12 +53,12 @@ impl SimpleComponent for SearchPageModel {
} }
fn init( fn init(
(): Self::InitParams, (): Self::Init,
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let model = SearchPageModel { let model = SearchPageModel {
searchitems: FactoryVecDeque::new(gtk::ListBox::new(), &sender.input), searchitems: FactoryVecDeque::new(gtk::ListBox::new(), sender.input_sender()),
searchitemtracker: 0, searchitemtracker: 0,
tracker: 0, tracker: 0,
}; };
@ -110,7 +110,7 @@ impl SimpleComponent for SearchPageModel {
} }
} }
#[derive(Default, Debug, PartialEq)] #[derive(Default, Debug, PartialEq, Eq)]
pub struct SearchItem { pub struct SearchItem {
pub name: String, pub name: String,
pub pkg: String, pub pkg: String,
@ -122,7 +122,7 @@ pub struct SearchItem {
} }
#[tracker::track] #[tracker::track]
#[derive(Default, Debug, PartialEq)] #[derive(Default, Debug, PartialEq, Eq)]
pub struct SearchItemModel { pub struct SearchItemModel {
pub item: SearchItem, pub item: SearchItem,
} }
@ -138,7 +138,7 @@ impl FactoryComponent for SearchItemModel {
type Output = SearchItemMsg; type Output = SearchItemMsg;
type Widgets = SearchItemWidgets; type Widgets = SearchItemWidgets;
type ParentWidget = adw::gtk::ListBox; type ParentWidget = adw::gtk::ListBox;
type ParentMsg = SearchPageMsg; type ParentInput = SearchPageMsg;
view! { view! {
adw::PreferencesRow { adw::PreferencesRow {

View File

@ -21,7 +21,7 @@ pub enum UpdateDialogMsg {
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for UpdateDialogModel { impl SimpleComponent for UpdateDialogModel {
type InitParams = gtk::Window; type Init = gtk::Window;
type Input = UpdateDialogMsg; type Input = UpdateDialogMsg;
type Output = UpdatePageMsg; type Output = UpdatePageMsg;
type Widgets = UpdateDialogWidgets; type Widgets = UpdateDialogWidgets;
@ -99,7 +99,7 @@ impl SimpleComponent for UpdateDialogModel {
} }
fn init( fn init(
parent_window: Self::InitParams, parent_window: Self::Init,
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {

View File

@ -1,7 +1,8 @@
use crate::{parse::{cache::channelver, config::NscConfig}, APPINFO}; use crate::APPINFO;
use super::{pkgpage::InstallType, window::*, updatedialog::{UpdateDialogModel, UpdateDialogMsg}, updateworker::{UpdateAsyncHandler, UpdateAsyncHandlerMsg, UpdateAsyncHandlerInit}}; use super::{pkgpage::InstallType, window::*, updatedialog::{UpdateDialogModel, UpdateDialogMsg}, updateworker::{UpdateAsyncHandler, UpdateAsyncHandlerMsg, UpdateAsyncHandlerInit}};
use adw::prelude::*; use adw::prelude::*;
use nix_data::config::configfile::NixDataConfig;
use relm4::{factory::*, gtk::pango, *}; use relm4::{factory::*, gtk::pango, *};
use std::{path::Path, convert::identity}; use std::{path::Path, convert::identity};
use log::*; use log::*;
@ -18,7 +19,7 @@ pub struct UpdatePageModel {
updatedialog: Controller<UpdateDialogModel>, updatedialog: Controller<UpdateDialogModel>,
#[tracker::no_eq] #[tracker::no_eq]
updateworker: WorkerController<UpdateAsyncHandler>, updateworker: WorkerController<UpdateAsyncHandler>,
config: NscConfig, config: NixDataConfig,
systype: SystemPkgs, systype: SystemPkgs,
usertype: UserPkgs, usertype: UserPkgs,
updatetracker: u8, updatetracker: u8,
@ -26,7 +27,7 @@ pub struct UpdatePageModel {
#[derive(Debug)] #[derive(Debug)]
pub enum UpdatePageMsg { pub enum UpdatePageMsg {
UpdateConfig(NscConfig), UpdateConfig(NixDataConfig),
UpdatePkgTypes(SystemPkgs, UserPkgs), UpdatePkgTypes(SystemPkgs, UserPkgs),
Update(Vec<UpdateItem>, Vec<UpdateItem>), Update(Vec<UpdateItem>, Vec<UpdateItem>),
OpenRow(usize, InstallType), OpenRow(usize, InstallType),
@ -45,12 +46,12 @@ pub struct UpdatePageInit {
pub window: gtk::Window, pub window: gtk::Window,
pub systype: SystemPkgs, pub systype: SystemPkgs,
pub usertype: UserPkgs, pub usertype: UserPkgs,
pub config: NscConfig, pub config: NixDataConfig,
} }
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for UpdatePageModel { impl SimpleComponent for UpdatePageModel {
type InitParams = UpdatePageInit; type Init = UpdatePageInit;
type Input = UpdatePageMsg; type Input = UpdatePageMsg;
type Output = AppMsg; type Output = AppMsg;
type Widgets = UpdatePageWidgets; type Widgets = UpdatePageWidgets;
@ -277,7 +278,7 @@ impl SimpleComponent for UpdatePageModel {
} }
fn init( fn init(
initparams: Self::InitParams, initparams: Self::Init,
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
@ -292,8 +293,8 @@ impl SimpleComponent for UpdatePageModel {
updateworker.emit(UpdateAsyncHandlerMsg::UpdateConfig(config.clone())); updateworker.emit(UpdateAsyncHandlerMsg::UpdateConfig(config.clone()));
let model = UpdatePageModel { let model = UpdatePageModel {
updateuserlist: FactoryVecDeque::new(gtk::ListBox::new(), &sender.input), updateuserlist: FactoryVecDeque::new(gtk::ListBox::new(), sender.input_sender()),
updatesystemlist: FactoryVecDeque::new(gtk::ListBox::new(), &sender.input), updatesystemlist: FactoryVecDeque::new(gtk::ListBox::new(), sender.input_sender()),
channelupdate: None, channelupdate: None,
updatetracker: 0, updatetracker: 0,
updatedialog, updatedialog,
@ -320,15 +321,21 @@ impl SimpleComponent for UpdatePageModel {
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateConfig(self.config.clone())); self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateConfig(self.config.clone()));
} }
UpdatePageMsg::UpdatePkgTypes(systype, usertype) => { UpdatePageMsg::UpdatePkgTypes(systype, usertype) => {
self.systype = systype.clone(); self.systype = systype;
self.usertype = usertype.clone(); self.usertype = usertype;
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdatePkgTypes(self.systype.clone(), self.usertype.clone())); self.updateworker.emit(UpdateAsyncHandlerMsg::UpdatePkgTypes(self.systype.clone(), self.usertype.clone()));
} }
UpdatePageMsg::Update(updateuserlist, updatesystemlist) => { UpdatePageMsg::Update(updateuserlist, updatesystemlist) => {
info!("UpdatePageMsg::Update"); info!("UpdatePageMsg::Update");
debug!("UPDATEUSERLIST: {:?}", updateuserlist); debug!("UPDATEUSERLIST: {:?}", updateuserlist);
debug!("UPDATESYSTEMLIST: {:?}", updatesystemlist); debug!("UPDATESYSTEMLIST: {:?}", updatesystemlist);
self.channelupdate = channelver().unwrap_or(None); self.channelupdate = match nix_data::cache::channel::uptodate() {
Ok(x) => {
x
},
Err(_) => None,
};
debug!("CHANNELUPDATE: {:?}", self.channelupdate);
self.update_updatetracker(|_| ()); self.update_updatetracker(|_| ());
let mut updateuserlist_guard = self.updateuserlist.guard(); let mut updateuserlist_guard = self.updateuserlist.guard();
updateuserlist_guard.clear(); updateuserlist_guard.clear();
@ -384,7 +391,7 @@ impl SimpleComponent for UpdatePageModel {
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateAll); self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateAll);
} }
UpdatePageMsg::DoneWorking => { UpdatePageMsg::DoneWorking => {
sender.output(AppMsg::ReloadUpdate); sender.output(AppMsg::UpdateInstalledPkgs);
} }
UpdatePageMsg::DoneLoading => { UpdatePageMsg::DoneLoading => {
self.updatedialog.emit(UpdateDialogMsg::Done); self.updatedialog.emit(UpdateDialogMsg::Done);
@ -396,7 +403,7 @@ impl SimpleComponent for UpdatePageModel {
} }
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
pub struct UpdateItem { pub struct UpdateItem {
pub name: String, pub name: String,
pub pkg: Option<String>, pub pkg: Option<String>,
@ -408,7 +415,7 @@ pub struct UpdateItem {
pub verto: Option<String>, pub verto: Option<String>,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
pub struct UpdateItemModel { pub struct UpdateItemModel {
item: UpdateItem, item: UpdateItem,
} }
@ -424,7 +431,7 @@ impl FactoryComponent for UpdateItemModel {
type Output = UpdateItemMsg; type Output = UpdateItemMsg;
type Widgets = UpdateItemWidgets; type Widgets = UpdateItemWidgets;
type ParentWidget = adw::gtk::ListBox; type ParentWidget = adw::gtk::ListBox;
type ParentMsg = UpdatePageMsg; type ParentInput = UpdatePageMsg;
view! { view! {
adw::PreferencesRow { adw::PreferencesRow {

View File

@ -1,10 +1,9 @@
use nix_data::config::configfile::NixDataConfig;
use relm4::*; use relm4::*;
use std::{error::Error, path::Path, process::Stdio}; use std::{error::Error, path::Path, process::Stdio};
use tokio::io::AsyncBufReadExt; use tokio::io::AsyncBufReadExt;
use log::*; use log::*;
use crate::parse::config::NscConfig;
use super::{ use super::{
updatepage::UpdatePageMsg, updatepage::UpdatePageMsg,
window::{SystemPkgs, UserPkgs}, window::{SystemPkgs, UserPkgs},
@ -23,7 +22,7 @@ pub struct UpdateAsyncHandler {
#[derive(Debug)] #[derive(Debug)]
pub enum UpdateAsyncHandlerMsg { pub enum UpdateAsyncHandlerMsg {
UpdateConfig(NscConfig), UpdateConfig(NixDataConfig),
UpdatePkgTypes(SystemPkgs, UserPkgs), UpdatePkgTypes(SystemPkgs, UserPkgs),
UpdateChannels, UpdateChannels,
@ -47,11 +46,11 @@ pub struct UpdateAsyncHandlerInit {
} }
impl Worker for UpdateAsyncHandler { impl Worker for UpdateAsyncHandler {
type InitParams = UpdateAsyncHandlerInit; type Init = UpdateAsyncHandlerInit;
type Input = UpdateAsyncHandlerMsg; type Input = UpdateAsyncHandlerMsg;
type Output = UpdatePageMsg; type Output = UpdatePageMsg;
fn init(params: Self::InitParams, _sender: relm4::ComponentSender<Self>) -> Self { fn init(params: Self::Init, _sender: relm4::ComponentSender<Self>) -> Self {
Self { Self {
process: None, process: None,
systemconfig: None, systemconfig: None,

View File

@ -2,11 +2,10 @@ use std::path::{PathBuf, Path};
use adw::prelude::*; use adw::prelude::*;
use log::info; use log::info;
use nix_data::config::configfile::NixDataConfig;
use relm4::*; use relm4::*;
use relm4_components::open_dialog::*; use relm4_components::open_dialog::*;
use crate::parse::config::NscConfig;
use super::window::AppMsg; use super::window::AppMsg;
#[tracker::track] #[tracker::track]
@ -36,7 +35,7 @@ pub enum WelcomeMsg {
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for WelcomeModel { impl SimpleComponent for WelcomeModel {
type InitParams = gtk::Window; type Init = gtk::Window;
type Input = WelcomeMsg; type Input = WelcomeMsg;
type Output = AppMsg; type Output = AppMsg;
type Widgets = WelcomeWidgets; type Widgets = WelcomeWidgets;
@ -176,7 +175,7 @@ impl SimpleComponent for WelcomeModel {
} }
fn init( fn init(
parent_window: Self::InitParams, parent_window: Self::Init,
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
@ -184,7 +183,7 @@ impl SimpleComponent for WelcomeModel {
let conf_dialog = OpenDialog::builder() let conf_dialog = OpenDialog::builder()
.transient_for_native(root) .transient_for_native(root)
.launch(OpenDialogSettings::default()) .launch(OpenDialogSettings::default())
.forward(&sender.input, |response| match response { .forward(sender.input_sender(), |response| match response {
OpenDialogResponse::Accept(path) => WelcomeMsg::UpdateConfPath(path), OpenDialogResponse::Accept(path) => WelcomeMsg::UpdateConfPath(path),
OpenDialogResponse::Cancel => WelcomeMsg::Ignore, OpenDialogResponse::Cancel => WelcomeMsg::Ignore,
}); });
@ -193,7 +192,7 @@ impl SimpleComponent for WelcomeModel {
let flake_dialog = OpenDialog::builder() let flake_dialog = OpenDialog::builder()
.transient_for_native(root) .transient_for_native(root)
.launch(OpenDialogSettings::default()) .launch(OpenDialogSettings::default())
.forward(&sender.input, |response| match response { .forward(sender.input_sender(), |response| match response {
OpenDialogResponse::Accept(path) => WelcomeMsg::UpdateFlakePath(path), OpenDialogResponse::Accept(path) => WelcomeMsg::UpdateFlakePath(path),
OpenDialogResponse::Cancel => WelcomeMsg::Ignore, OpenDialogResponse::Cancel => WelcomeMsg::Ignore,
}); });
@ -222,7 +221,7 @@ impl SimpleComponent for WelcomeModel {
self.hidden = false; self.hidden = false;
} }
WelcomeMsg::Close => { WelcomeMsg::Close => {
let config = NscConfig { let config = NixDataConfig {
systemconfig: self.confpath.as_ref().map(|x| x.to_string_lossy().to_string()), systemconfig: self.confpath.as_ref().map(|x| x.to_string_lossy().to_string()),
flake: self.flakepath.as_ref().map(|x| x.to_string_lossy().to_string()), flake: self.flakepath.as_ref().map(|x| x.to_string_lossy().to_string()),
flakearg: None, flakearg: None,

File diff suppressed because it is too large Load Diff

View File

@ -1,423 +1,375 @@
use super::window::AppMsg; use super::window::AppMsg;
use super::window::SystemPkgs; use super::window::SystemPkgs;
use crate::parse::cache::checkcache; use crate::parse::packages::appsteamdata;
use crate::parse::config::NscConfig; use crate::parse::packages::AppData;
use crate::parse::packages::readflakesyspkgs;
use crate::parse::packages::readpkgs;
use crate::parse::packages::readlegacysyspkgs;
use crate::parse::packages::Package;
use crate::parse::packages::readprofilepkgs;
use crate::ui::categories::PkgCategory; use crate::ui::categories::PkgCategory;
use crate::ui::window::UserPkgs; use crate::ui::window::UserPkgs;
use log::*;
use nix_data::config::configfile::NixDataConfig;
use rand::prelude::SliceRandom; use rand::prelude::SliceRandom;
use rand::thread_rng; use rand::thread_rng;
use relm4::adw::prelude::*; use relm4::adw::prelude::*;
use relm4::*; use relm4::*;
use sqlx::SqlitePool;
use std::{collections::HashMap, env}; use std::{collections::HashMap, env};
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use log::*;
pub struct WindowAsyncHandler; pub struct WindowAsyncHandler;
#[derive(Debug)] #[derive(Debug)]
pub enum WindowAsyncHandlerMsg { pub enum WindowAsyncHandlerMsg {
CheckCache(CacheReturn, SystemPkgs, UserPkgs, NscConfig), CheckCache(SystemPkgs, UserPkgs, NixDataConfig),
}
#[derive(Debug, PartialEq)]
pub enum CacheReturn {
Init,
Update,
} }
impl Worker for WindowAsyncHandler { impl Worker for WindowAsyncHandler {
type InitParams = (); type Init = ();
type Input = WindowAsyncHandlerMsg; type Input = WindowAsyncHandlerMsg;
type Output = AppMsg; type Output = AppMsg;
fn init(_params: Self::InitParams, _sender: relm4::ComponentSender<Self>) -> Self { fn init(_params: Self::Init, _sender: relm4::ComponentSender<Self>) -> Self {
Self Self
} }
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) { fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
match msg { match msg {
WindowAsyncHandlerMsg::CheckCache(cr, syspkgs, userpkgs, config) => { WindowAsyncHandlerMsg::CheckCache(syspkgs, userpkgs, _config) => {
info!("WindowAsyncHandlerMsg::CheckCache"); info!("WindowAsyncHandlerMsg::CheckCache");
let syspkgs2 = syspkgs.clone();
let userpkgs2 = userpkgs.clone();
let config = config.clone();
relm4::spawn(async move { relm4::spawn(async move {
match checkcache(syspkgs2, userpkgs2, config) {
Ok(_) => {}
Err(e) => {
warn!("FAILED TO CHECK CACHE");
warn!("{}", e);
sender.output(AppMsg::LoadError(
String::from("Could not load cache"),
String::from(
"Try connecting to the internet or launching the application again",
),
));
return;
}
}
let pkgs = match readpkgs().await {
Ok(pkgs) => pkgs,
Err(e) => {
warn!("FAILED TO LOAD PKGS");
warn!("{}", e);
sender.output(AppMsg::LoadError(
String::from("Could not load packages"),
String::from(
"Try connecting to the internet or launching the application again",
),
));
return;
}
};
let newpkgs = match syspkgs {
SystemPkgs::Legacy => {
match readlegacysyspkgs() {
Ok(newpkgs) => newpkgs,
Err(e) => {
warn!("FAILED TO LOAD NEW PKGS");
warn!("{}", e);
sender.output(AppMsg::LoadError(
String::from("Could not load new packages"),
String::from(
"Try connecting to the internet or launching the application again",
),
));
return;
}
}
}
SystemPkgs::Flake => {
match readflakesyspkgs() {
Ok(newpkgs) => newpkgs,
Err(e) => {
warn!("FAILED TO LOAD NEW PKGS");
warn!("{}", e);
sender.output(AppMsg::LoadError(
String::from("Could not load new packages"),
String::from(
"Try connecting to the internet or launching the application again",
),
));
return;
}
}
}
SystemPkgs::None => {
HashMap::new()
}
};
let profilepkgs = match userpkgs {
UserPkgs::Env => None,
UserPkgs::Profile => if let Ok(r) = readprofilepkgs() { Some(r) } else { None },
};
let mut recpicks = vec![]; let mut recpicks = vec![];
let mut catpicks: HashMap<PkgCategory, Vec<String>> = HashMap::new(); let mut catpicks: HashMap<PkgCategory, Vec<String>> = HashMap::new();
let mut catpkgs: HashMap<PkgCategory, Vec<String>> = HashMap::new(); let mut catpkgs: HashMap<PkgCategory, Vec<String>> = HashMap::new();
println!("Connecting to DB");
let pkgdb = nix_data::cache::nixos::nixospkgs().await.unwrap();
let pool = SqlitePool::connect(&format!("sqlite://{}", pkgdb))
.await
.unwrap();
if cr == CacheReturn::Init { let nixpkgsdb = match userpkgs {
let desktopenv = env::var("XDG_CURRENT_DESKTOP").unwrap_or_default(); UserPkgs::Profile => {
let appdatapkgs = pkgs if let Ok(x) = nix_data::cache::profile::nixpkgslatest().await {
.iter() Some(x)
.filter(|(x, _)| { } else {
if let Some(p) = pkgs.get(*x) { None
if let Some(data) = &p.appdata { }
(if let Some(i) = &data.icon {
i.cached.is_some()
} else {
false
}) && data.description.is_some()
&& data.name.is_some()
&& data.launchable.is_some()
&& data.screenshots.is_some()
&& (!x.starts_with("gnome.") || desktopenv == "GNOME")
&& (!x.starts_with("xfce.") || desktopenv == "XFCE")
&& (!x.starts_with("mate.") || desktopenv == "MATE")
&& (!x.starts_with("cinnamon.")
|| desktopenv == "X-Cinnamon")
&& (!x.starts_with("libsForQt5") || desktopenv == "KDE")
&& (!x.starts_with("pantheon.")
|| desktopenv == "Pantheon")
} else {
false
}
} else {
false
}
})
.collect::<HashMap<_, _>>();
let mut recommendedpkgs = appdatapkgs
.keys()
.map(|x| x.to_string())
.collect::<Vec<_>>();
let mut rng = thread_rng();
recommendedpkgs.shuffle(&mut rng);
let mut desktoppicks = recommendedpkgs
.iter()
.filter(|x| {
if desktopenv == "GNOME" {
x.starts_with("gnome.") || x.starts_with("gnome-")
} else if desktopenv == "XFCE" {
x.starts_with("xfce.")
} else if desktopenv == "MATE" {
x.starts_with("mate.")
} else if desktopenv == "X-Cinnamon" {
x.starts_with("cinnamon.")
} else if desktopenv == "KDE" {
x.starts_with("libsForQt5")
} else if desktopenv == "Pantheon" {
x.starts_with("pantheon.")
} else {
false
}
})
.collect::<Vec<_>>();
for p in desktoppicks.iter().take(3) {
recpicks.push(p.to_string());
} }
for category in PkgCategory::iter() { UserPkgs::Env => None,
desktoppicks.shuffle(&mut rng); };
let mut cvec = vec![];
let mut allvec = vec![]; let systemdb = match syspkgs {
let mut rpkgs = recommendedpkgs.clone(); SystemPkgs::None => None,
fn checkpkgs( SystemPkgs::Legacy => {
pkg: String, if let Ok(x) = nix_data::cache::channel::legacypkgs().await {
pkgs: &HashMap<&String, &Package>, Some(x)
category: PkgCategory, } else {
) -> bool { None
match category { }
PkgCategory::Audio => { }
// Audio: SystemPkgs::Flake => {
// - pkgs/applications/audio if let Ok(x) = nix_data::cache::flakes::flakespkgs().await {
if let Some(p) = pkgs.get(&pkg) { Some(x)
if let Some(pos) = &p.meta.position { } else {
if pos.starts_with("pkgs/applications/audio") { None
}
}
};
let pkglist: Vec<(String,)> = sqlx::query_as("SELECT attribute FROM pkgs")
.fetch_all(&pool)
.await
.unwrap();
let pkglist = pkglist.iter().map(|x| x.0.clone()).collect::<Vec<String>>();
let posvec: Vec<(String, String)> =
sqlx::query_as("SELECT attribute, position FROM meta")
.fetch_all(&pool)
.await
.unwrap();
println!("Got DB data");
let appdata = appsteamdata().unwrap();
let desktopenv = env::var("XDG_CURRENT_DESKTOP").unwrap_or_default();
let mut recpkgs = pkglist
.iter()
.filter(|x| {
if let Some(data) = appdata.get(&x.to_string()) {
(if let Some(i) = &data.icon {
i.cached.is_some()
} else {
false
}) && data.description.is_some()
&& data.name.is_some()
&& data.launchable.is_some()
&& data.screenshots.is_some()
&& (!x.starts_with("gnome.") || desktopenv == "GNOME")
&& (!x.starts_with("xfce.") || desktopenv == "XFCE")
&& (!x.starts_with("mate.") || desktopenv == "MATE")
&& (!x.starts_with("cinnamon.") || desktopenv == "X-Cinnamon")
&& (!x.starts_with("libsForQt5") || desktopenv == "KDE")
&& (!x.starts_with("pantheon.") || desktopenv == "Pantheon")
} else {
false
}
})
.collect::<Vec<_>>();
let mut rng = thread_rng();
recpkgs.shuffle(&mut rng);
let mut desktoppicks = recpkgs
.iter()
.filter(|x| {
if desktopenv == "GNOME" {
x.starts_with("gnome.") || x.starts_with("gnome-")
} else if desktopenv == "XFCE" {
x.starts_with("xfce.")
} else if desktopenv == "MATE" {
x.starts_with("mate.")
} else if desktopenv == "X-Cinnamon" {
x.starts_with("cinnamon.")
} else if desktopenv == "KDE" {
x.starts_with("libsForQt5")
} else if desktopenv == "Pantheon" {
x.starts_with("pantheon.")
} else {
false
}
})
.collect::<Vec<_>>();
for p in desktoppicks.iter().take(3) {
recpicks.push(p.to_string());
}
let pospkgs = posvec
.into_iter()
.map(|(x, y)| (x, if y.is_empty() { None } else { Some(y) }))
.collect::<HashMap<String, Option<String>>>();
println!("Starting category");
for category in PkgCategory::iter() {
desktoppicks.shuffle(&mut rng);
let mut cvec = vec![];
let mut allvec = vec![];
let mut rpkgs = recpkgs.clone();
fn checkpkgs(
pkg: String,
pospkgs: &HashMap<String, Option<String>>,
appdata: &HashMap<String, AppData>,
category: PkgCategory,
) -> bool {
match category {
PkgCategory::Audio => {
// Audio:
// - pkgs/applications/audio
if let Some(Some(pos)) = pospkgs.get(&pkg) {
if pos.starts_with("pkgs/applications/audio") {
return true;
}
if let Some(data) = appdata.get(&pkg) {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Audio")) {
return true; return true;
} }
} }
if let Some(data) = &p.appdata {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Audio")) {
return true;
}
}
}
} }
false
} }
PkgCategory::Development => { false
// Development: }
// - pkgs/development PkgCategory::Development => {
// - pkgs/applications/terminal-emulators // Development:
// - xdg: Development // - pkgs/development
if let Some(p) = pkgs.get(&pkg) { // - pkgs/applications/terminal-emulators
if let Some(pos) = &p.meta.position { // - xdg: Development
if pos.starts_with("pkgs/development") if let Some(Some(pos)) = pospkgs.get(&pkg) {
|| pos.starts_with( if pos.starts_with("pkgs/development")
"pkgs/applications/terminal-emulators", || pos
) .starts_with("pkgs/applications/terminal-emulators")
{
return true;
}
if let Some(data) = appdata.get(&pkg) {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Development"))
{ {
return true; return true;
} }
} }
if let Some(data) = &p.appdata {
if let Some(categories) = &data.categories {
if categories
.contains(&String::from("Development"))
{
return true;
}
}
}
} }
false
} }
PkgCategory::Games => { false
// Games: }
// - pkgs/games PkgCategory::Games => {
// - pkgs/applications/emulators // Games:
// - pkgs/tools/games // - pkgs/games
// - xdg::Games // - pkgs/applications/emulators
if let Some(p) = pkgs.get(&pkg) { // - pkgs/tools/games
if let Some(pos) = &p.meta.position { // - xdg::Games
if pos.starts_with("pkgs/games") if let Some(Some(pos)) = pospkgs.get(&pkg) {
|| pos.starts_with( if pos.starts_with("pkgs/games")
"pkgs/applications/emulators", || pos.starts_with("pkgs/applications/emulators")
) || pos.starts_with("pkgs/tools/games")
|| pos.starts_with("pkgs/tools/games") {
{ return true;
}
if let Some(data) = &appdata.get(&pkg) {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Games")) {
return true; return true;
} }
} }
if let Some(data) = &p.appdata {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Games")) {
return true;
}
}
}
} }
false
} }
PkgCategory::Graphics => { false
// Graphics: }
// - pkgs/applications/graphics PkgCategory::Graphics => {
// - xdg: Graphics // Graphics:
if let Some(p) = pkgs.get(&pkg) { // - pkgs/applications/graphics
if let Some(pos) = &p.meta.position { // - xdg: Graphics
if pos.starts_with("pkgs/applications/graphics") if let Some(Some(pos)) = pospkgs.get(&pkg) {
|| pos.starts_with("xdg:Graphics") if pos.starts_with("pkgs/applications/graphics")
{ || pos.starts_with("xdg:Graphics")
{
return true;
}
if let Some(data) = &appdata.get(&pkg) {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Graphics")) {
return true; return true;
} }
} }
if let Some(data) = &p.appdata {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Graphics")) {
return true;
}
}
}
}
false
}
PkgCategory::Network => {
// Network:
// - pkgs/applications/networking
// - xdg: Network
if let Some(p) = pkgs.get(&pkg) {
if let Some(pos) = &p.meta.position {
if pos.starts_with("pkgs/applications/networking")
|| pos.starts_with("xdg:Network")
{
return true;
}
}
if let Some(data) = &p.appdata {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Network")) {
return true;
}
}
}
}
false
}
PkgCategory::Video => {
// Video:
// - pkgs/applications/video
// - xdg: Video
if let Some(p) = pkgs.get(&pkg) {
if let Some(pos) = &p.meta.position {
if pos.starts_with("pkgs/applications/video")
|| pos.starts_with("xdg:Video")
{
return true;
}
}
if let Some(data) = &p.appdata {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Video")) {
return true;
}
}
}
} }
false
} }
false
}
PkgCategory::Network => {
// Network:
// - pkgs/applications/networking
// - xdg: Network
if let Some(Some(pos)) = pospkgs.get(&pkg) {
if pos.starts_with("pkgs/applications/networking")
|| pos.starts_with("xdg:Network")
{
return true;
}
if let Some(data) = &appdata.get(&pkg) {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Network")) {
return true;
}
}
}
}
false
}
PkgCategory::Video => {
// Video:
// - pkgs/applications/video
// - xdg: Video
if let Some(Some(pos)) = pospkgs.get(&pkg) {
if pos.starts_with("pkgs/applications/video")
|| pos.starts_with("xdg:Video")
{
return true;
}
if let Some(data) = &appdata.get(&pkg) {
if let Some(categories) = &data.categories {
if categories.contains(&String::from("Video")) {
return true;
}
}
}
}
false
} }
} }
}
for pkg in desktoppicks.iter().take(3) { for pkg in desktoppicks.iter().take(3) {
if checkpkgs(pkg.to_string(), &appdatapkgs, category.clone()) { if checkpkgs(pkg.to_string(), &pospkgs, &appdata, category.clone()) {
cvec.push(pkg.to_string());
}
}
while cvec.len() < 12 {
if let Some(pkg) = rpkgs.pop() {
if !cvec.contains(&pkg.to_string())
&& checkpkgs(
pkg.to_string(),
&pospkgs,
&appdata,
category.clone(),
)
{
cvec.push(pkg.to_string()); cvec.push(pkg.to_string());
} }
}
while cvec.len() < 12 {
if let Some(pkg) = rpkgs.pop() {
if !cvec.contains(&pkg.to_string())
&& checkpkgs(
pkg.to_string(),
&appdatapkgs,
category.clone(),
)
{
cvec.push(pkg.to_string());
}
} else {
break;
}
}
let catagortypkgs = pkgs
.iter()
.filter(|(x, _)| {
if let Some(p) = appdatapkgs.get(*x) {
if let Some(position) = &p.meta.position {
(position.starts_with("pkgs/applications/audio") && category == PkgCategory::Audio)
|| (position.starts_with("pkgs/applications/terminal-emulators") && category == PkgCategory::Development)
|| (position.starts_with("pkgs/applications/emulators") && category == PkgCategory::Games)
|| (position.starts_with("pkgs/applications/graphics") && category == PkgCategory::Graphics)
|| (position.starts_with("pkgs/applications/networking") && category == PkgCategory::Network)
|| (position.starts_with("pkgs/applications/video") && category == PkgCategory::Video)
|| (position.starts_with("pkgs/tools/games") && category == PkgCategory::Games)
|| (position.starts_with("pkgs/games") && category == PkgCategory::Games)
|| (position.starts_with("pkgs/development") && category == PkgCategory::Development)
|| appdatapkgs.contains_key(x)
} else {
false
}
} else {
false
}
})
.collect::<HashMap<_, _>>();
for pkg in catagortypkgs.keys() {
if checkpkgs(pkg.to_string(), &catagortypkgs, category.clone()) {
allvec.push(pkg.to_string());
}
}
cvec.shuffle(&mut rng);
allvec.sort_by_key(|x| x.to_lowercase());
catpicks.insert(category.clone(), cvec);
catpkgs.insert(category.clone(), allvec);
}
while recpicks.len() < 12 {
if let Some(p) = recommendedpkgs.pop() {
if !recpicks.contains(&p.to_string()) {
recpicks.push(p);
}
} else { } else {
break; break;
} }
} }
recpicks.shuffle(&mut rng);
let catagortypkgs = pkglist
.iter()
.filter(|x| {
if appdata.get(*x).is_some() {
if let Some(Some(position)) = &pospkgs.get(*x) {
(position.starts_with("pkgs/applications/audio")
&& category == PkgCategory::Audio)
|| (position.starts_with(
"pkgs/applications/terminal-emulators",
) && category == PkgCategory::Development)
|| (position.starts_with("pkgs/applications/emulators")
&& category == PkgCategory::Games)
|| (position.starts_with("pkgs/applications/graphics")
&& category == PkgCategory::Graphics)
|| (position
.starts_with("pkgs/applications/networking")
&& category == PkgCategory::Network)
|| (position.starts_with("pkgs/applications/video")
&& category == PkgCategory::Video)
|| (position.starts_with("pkgs/tools/games")
&& category == PkgCategory::Games)
|| (position.starts_with("pkgs/games")
&& category == PkgCategory::Games)
|| (position.starts_with("pkgs/development")
&& category == PkgCategory::Development)
|| recpkgs.contains(x)
} else {
false
}
} else {
false
}
})
.collect::<Vec<_>>();
for pkg in catagortypkgs {
if checkpkgs(pkg.to_string(), &pospkgs, &appdata, category.clone()) {
allvec.push(pkg.to_string());
}
}
cvec.shuffle(&mut rng);
allvec.sort_by_key(|x| x.to_lowercase());
catpicks.insert(category.clone(), cvec);
catpkgs.insert(category.clone(), allvec);
} }
match cr { while recpicks.len() < 12 {
CacheReturn::Init => { if let Some(p) = recpkgs.pop() {
sender.output(AppMsg::Initialize(pkgs, recpicks, newpkgs, catpicks, catpkgs, profilepkgs)); if !recpicks.contains(&p.to_string()) {
} recpicks.push(p.to_string());
CacheReturn::Update => { }
sender.output(AppMsg::ReloadUpdateItems(pkgs, newpkgs)); } else {
break;
} }
} }
recpicks.shuffle(&mut rng);
sender.output(AppMsg::Initialize(
pkgdb, nixpkgsdb, systemdb, appdata, recpicks, catpicks, catpkgs,
));
}); });
} }
} }
@ -435,12 +387,11 @@ pub enum LoadErrorMsg {
Show(String, String), Show(String, String),
Retry, Retry,
Close, Close,
// Preferences,
} }
#[relm4::component(pub)] #[relm4::component(pub)]
impl SimpleComponent for LoadErrorModel { impl SimpleComponent for LoadErrorModel {
type InitParams = gtk::Window; type Init = gtk::Window;
type Input = LoadErrorMsg; type Input = LoadErrorMsg;
type Output = AppMsg; type Output = AppMsg;
type Widgets = LoadErrorWidgets; type Widgets = LoadErrorWidgets;
@ -472,7 +423,7 @@ impl SimpleComponent for LoadErrorModel {
} }
fn init( fn init(
parent_window: Self::InitParams, parent_window: Self::Init,
root: &Self::Root, root: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {