diff --git a/.idea/workspace.xml b/.idea/workspace.xml index aaa320e..af042ec 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -8,9 +8,11 @@ - + + + diff --git a/src/apt_package_row/imp.rs b/src/apt_package_row/imp.rs index dcaaf71..00230ca 100644 --- a/src/apt_package_row/imp.rs +++ b/src/apt_package_row/imp.rs @@ -52,7 +52,12 @@ impl ObjectSubclass for AptPackageRow { impl ObjectImpl for AptPackageRow { fn signals() -> &'static [Signal] { static SIGNALS: OnceLock> = OnceLock::new(); - SIGNALS.get_or_init(|| vec![Signal::builder("checkbutton-toggled").build(), Signal::builder("checkbutton-untoggled").build()]) + SIGNALS.get_or_init(|| { + vec![ + Signal::builder("checkbutton-toggled").build(), + Signal::builder("checkbutton-untoggled").build(), + ] + }) } fn constructed(&self) { let current_locale = match env::var_os("LANG") { diff --git a/src/apt_update/main.rs b/src/apt_update/main.rs index 1348f1a..8f591be 100644 --- a/src/apt_update/main.rs +++ b/src/apt_update/main.rs @@ -1,8 +1,8 @@ -use std::process::exit; use pika_unixsocket_tools::*; use rust_apt::new_cache; use rust_apt::progress::{AcquireProgress, DynAcquireProgress}; use rust_apt::raw::{AcqTextStatus, ItemDesc, PkgAcquire}; +use std::process::exit; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::UnixStream; use tokio::runtime::Runtime; diff --git a/src/apt_update_page/mod.rs b/src/apt_update_page/mod.rs index b634eaa..8695d70 100644 --- a/src/apt_update_page/mod.rs +++ b/src/apt_update_page/mod.rs @@ -1,6 +1,5 @@ mod process; -use std::rc::Rc; use crate::apt_package_row::AptPackageRow; use adw::gio::{Action, SimpleAction}; use adw::prelude::*; @@ -12,13 +11,14 @@ use rust_apt::cache::*; use rust_apt::new_cache; use rust_apt::records::RecordField; use rust_apt::*; -use std::borrow::BorrowMut; +use std::cell::RefCell; +use std::ops::Deref; use std::path::Path; use std::process::Command; +use std::rc::Rc; use std::sync::atomic::AtomicBool; use std::sync::Arc; use std::{fs, thread}; -use std::ops::Deref; use tokio::io::AsyncReadExt; use tokio::net::{UnixListener, UnixStream}; use tokio::runtime::Runtime; @@ -36,7 +36,10 @@ pub struct AptPackageSocket { pub installed_size: u64, pub is_last: bool, } -pub fn apt_update_page(window: adw::ApplicationWindow, retry_signal_action: &SimpleAction) -> gtk::Box { +pub fn apt_update_page( + window: adw::ApplicationWindow, + retry_signal_action: &SimpleAction, +) -> gtk::Box { let (update_percent_sender, update_percent_receiver) = async_channel::unbounded::(); let update_percent_sender = update_percent_sender.clone(); let (update_status_sender, update_status_receiver) = async_channel::unbounded::(); @@ -45,7 +48,7 @@ pub fn apt_update_page(window: adw::ApplicationWindow, retry_signal_action: &Sim let (get_upgradable_sender, get_upgradable_receiver) = async_channel::unbounded(); let get_upgradable_sender = get_upgradable_sender.clone(); - //let excluded_updates_vec = Vec::new(); + let excluded_updates_vec: Rc>> = Rc::new(RefCell::new(Vec::new())); thread::spawn(move || { Runtime::new() @@ -68,8 +71,12 @@ pub fn apt_update_page(window: adw::ApplicationWindow, retry_signal_action: &Sim 0 => {} 53 => {} _ => { - update_status_sender_clone0.send_blocking(t!("update_status_error_perms").to_string()).unwrap(); - update_status_sender_clone0.send_blocking("FN_OVERRIDE_FAILED".to_owned()).unwrap() + update_status_sender_clone0 + .send_blocking(t!("update_status_error_perms").to_string()) + .unwrap(); + update_status_sender_clone0 + .send_blocking("FN_OVERRIDE_FAILED".to_owned()) + .unwrap() } } }); @@ -139,7 +146,10 @@ pub fn apt_update_page(window: adw::ApplicationWindow, retry_signal_action: &Sim .width_request(500) .build(); - apt_update_dialog.add_response("apt_update_dialog_retry", &t!("apt_update_dialog_retry_label").to_string()); + apt_update_dialog.add_response( + "apt_update_dialog_retry", + &t!("apt_update_dialog_retry_label").to_string(), + ); apt_update_dialog.set_response_appearance( "apt_update_dialog_retry", @@ -150,15 +160,15 @@ pub fn apt_update_page(window: adw::ApplicationWindow, retry_signal_action: &Sim let retry_signal_action0 = retry_signal_action.clone(); - apt_update_dialog.clone().choose(None::<&gio::Cancellable>, move |choice| { - if choice == "apt_update_dialog_retry" { - retry_signal_action0.activate(None); - } - }); + apt_update_dialog + .clone() + .choose(None::<&gio::Cancellable>, move |choice| { + if choice == "apt_update_dialog_retry" { + retry_signal_action0.activate(None); + } + }); - let bottom_bar = gtk::Box::builder() - .valign(Align::End) - .build(); + let bottom_bar = gtk::Box::builder().valign(Align::End).build(); let select_button = gtk::Button::builder() .halign(Align::End) @@ -193,6 +203,10 @@ pub fn apt_update_page(window: adw::ApplicationWindow, retry_signal_action: &Sim .build(); update_button.add_css_class("destructive-action"); + update_button.connect_clicked(clone!(@strong excluded_updates_vec => move |_| { + process::apt_process_update(&excluded_updates_vec.borrow()); + })); + bottom_bar.append(&select_button); bottom_bar.append(&update_button); @@ -263,7 +277,7 @@ pub fn apt_update_page(window: adw::ApplicationWindow, retry_signal_action: &Sim let get_upgradable_server_context = MainContext::default(); // The main loop executes the asynchronous block get_upgradable_server_context.spawn_local( - clone!(@weak packages_boxedlist => async move { + clone!(@weak select_button, @weak update_button, @weak packages_boxedlist, @strong excluded_updates_vec => async move { while let Ok(state) = get_upgradable_receiver.recv().await { let apt_row = AptPackageRow::new(AptPackageSocket { name: state.name, @@ -280,19 +294,23 @@ pub fn apt_update_page(window: adw::ApplicationWindow, retry_signal_action: &Sim apt_row.connect_closure( "checkbutton-toggled", false, - closure_local!(@strong apt_row, @strong select_button, @strong packages_boxedlist => move |apt_row: AptPackageRow| { + closure_local!(@strong apt_row, @strong select_button, @strong update_button, @strong packages_boxedlist, @strong excluded_updates_vec => move |apt_row: AptPackageRow| { if is_widget_select_all_ready(&packages_boxedlist) { - select_button.set_label(&t!("select_button_select_all").to_string()) + select_button.set_label(&t!("select_button_select_all").to_string()); } else { - select_button.set_label(&t!("select_button_deselect_all").to_string()) + select_button.set_label(&t!("select_button_deselect_all").to_string()); } + update_button.set_sensitive(!is_all_children_unmarked(&packages_boxedlist)); + excluded_updates_vec.borrow_mut().retain(|x| x != &apt_row.package_name()); }), ); apt_row.connect_closure( "checkbutton-untoggled", false, - closure_local!(@strong apt_row, @strong select_button, @strong packages_boxedlist => move |apt_row: AptPackageRow| { - select_button.set_label(&t!("select_button_select_all").to_string()) + closure_local!(@strong apt_row, @strong select_button, @strong update_button, @strong packages_boxedlist, @strong excluded_updates_vec => move |apt_row: AptPackageRow| { + select_button.set_label(&t!("select_button_select_all").to_string()); + update_button.set_sensitive(!is_all_children_unmarked(&packages_boxedlist)); + excluded_updates_vec.borrow_mut().push(apt_row.package_name()) }), ); packages_boxedlist.append(&apt_row); @@ -338,13 +356,28 @@ fn is_widget_select_all_ready(parent_listbox: &impl IsA) -> bool { let downcast = child.downcast::().unwrap(); if !downcast.package_marked() { is_ready = true; - break + break; } child_counter = next_child } is_ready } +fn is_all_children_unmarked(parent_listbox: &impl IsA) -> bool { + let mut is_all_unmarked = true; + let mut child_counter = parent_listbox.borrow().first_child(); + while let Some(child) = child_counter { + let next_child = child.next_sibling(); + let downcast = child.downcast::().unwrap(); + if downcast.package_marked() { + is_all_unmarked = false; + break; + } + child_counter = next_child + } + is_all_unmarked +} + fn set_all_apt_row_marks_to(parent_listbox: &impl IsA, value: bool) { let mut child_counter = parent_listbox.borrow().first_child(); while let Some(child) = child_counter { diff --git a/src/apt_update_page/process.rs b/src/apt_update_page/process.rs index e69de29..e826a85 100644 --- a/src/apt_update_page/process.rs +++ b/src/apt_update_page/process.rs @@ -0,0 +1,3 @@ +pub fn apt_process_update(excluded_updates_vec: &Vec) { + dbg!(excluded_updates_vec); +} diff --git a/src/build_ui/mod.rs b/src/build_ui/mod.rs index 9ce949d..e90b7b8 100644 --- a/src/build_ui/mod.rs +++ b/src/build_ui/mod.rs @@ -1,18 +1,18 @@ -use crate::glib::closure_local; use crate::apt_update_page; use crate::apt_update_page::apt_update_page; use crate::config::{APP_GITHUB, APP_ICON, APP_ID, VERSION}; +use crate::glib::closure_local; +use adw::glib::ffi::G_VARIANT_TYPE_ANY; use adw::prelude::*; use adw::*; use gtk::glib::{clone, MainContext}; +use gtk::pango::AttrType::Variant; use gtk::{License, Orientation, SignalAction}; use std::cell::RefCell; use std::ops::Deref; use std::process::Command; use std::rc::Rc; use std::thread; -use adw::glib::ffi::G_VARIANT_TYPE_ANY; -use gtk::pango::AttrType::Variant; pub fn build_ui(app: &adw::Application) { // setup glib @@ -139,20 +139,30 @@ pub fn build_ui(app: &adw::Application) { let apt_retry_signal_action = gio::SimpleAction::new("retry", None); let apt_update_view_stack_bin = adw::Bin::builder() - .child(&apt_update_page::apt_update_page(window.clone(), &apt_retry_signal_action)) + .child(&apt_update_page::apt_update_page( + window.clone(), + &apt_retry_signal_action, + )) .build(); apt_retry_signal_action.connect_activate(clone!(@weak window, @strong apt_retry_signal_action, @strong apt_update_view_stack_bin => move |_, _| { apt_update_view_stack_bin.set_child(Some(&apt_update_page::apt_update_page(window, &apt_retry_signal_action))); })); - window_adw_view_stack.add_titled_with_icon(&apt_update_view_stack_bin, Some("apt_update_page"), &t!("apt_update_page_title"), "software-update-available-symbolic"); + window_adw_view_stack.add_titled_with_icon( + &apt_update_view_stack_bin, + Some("apt_update_page"), + &t!("apt_update_page_title"), + "software-update-available-symbolic", + ); // - refresh_button.connect_clicked(clone!(@weak apt_retry_signal_action, @weak window_adw_view_stack => move |_| { - match window_adw_view_stack.visible_child_name().unwrap().as_str() { - "apt_update_page" => apt_retry_signal_action.activate(None), - _ => {} - } - })); + refresh_button.connect_clicked( + clone!(@weak apt_retry_signal_action, @weak window_adw_view_stack => move |_| { + match window_adw_view_stack.visible_child_name().unwrap().as_str() { + "apt_update_page" => apt_retry_signal_action.activate(None), + _ => {} + } + }), + ); }