diff --git a/Cargo.lock b/Cargo.lock index d5f307b..866b738 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -926,8 +926,6 @@ version = "1.0.2" dependencies = [ "async-channel", "duct", - "glib 0.18.5", - "glib 0.20.0", "glob", "gnome-desktop", "gtk4", diff --git a/Cargo.toml b/Cargo.toml index c571ba4..3fd0102 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,11 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -glib_old = { version = "0.18", package = "glib"} adw = { version = "0.7.0", package = "libadwaita", features = ["v1_5"] } async-channel = "2.3.1" duct = "0.13.7" -glib = "0.20.0" gtk = { version = "0.9.0", package = "gtk4", features = ["v4_14"] } pretty-bytes = "0.2.2" time = "0.3.31" diff --git a/src/build_ui.rs b/src/build_ui.rs index 858ee9b..bafe916 100644 --- a/src/build_ui.rs +++ b/src/build_ui.rs @@ -1,6 +1,6 @@ use std::{path::Path, rc::Rc, cell::RefCell}; use gtk::{prelude::*, glib as glib, gio as gio}; -use crate::{efi_error_page, welcome_page, language_page, eula_page, keyboard_page, timezone_page, partitioning_page}; +use crate::{efi_error_page, eula_page, keyboard_page, language_page, partitioning_page::{self, CrypttabEntry, FstabEntry}, timezone_page, welcome_page}; pub fn build_ui(app: &adw::Application) { glib::set_prgname(Some("pikaos_installer")); @@ -60,9 +60,9 @@ pub fn build_ui(app: &adw::Application) { let partition_method_automatic_luks_refcell: Rc> = Rc::new(RefCell::default()); let partition_method_automatic_ratio_refcell: Rc> = Rc::new(RefCell::new(0.0)); let partition_method_automatic_seperation_refcell: Rc> = Rc::new(RefCell::default()); - let partition_method_manual_fstab_json_refcell: Rc> = Rc::new(RefCell::default()); + let partition_method_manual_fstab_entry_array_refcell: Rc>> = Rc::new(RefCell::new(Vec::new())); let partition_method_manual_luks_enabled_refcell: Rc> = Rc::new(RefCell::new(false)); - let partition_method_manual_crypttab_json_refcell: Rc> = Rc::new(RefCell::default()); + let partition_method_manual_crypttab_entry_array_refcell: Rc>> = Rc::new(RefCell::new(Vec::new())); let language_changed_action = gio::SimpleAction::new("lang-changed", None); @@ -83,9 +83,9 @@ pub fn build_ui(app: &adw::Application) { &partition_method_automatic_luks_refcell, &partition_method_automatic_ratio_refcell, &partition_method_automatic_seperation_refcell, - &partition_method_manual_fstab_json_refcell, + &partition_method_manual_fstab_entry_array_refcell, &partition_method_manual_luks_enabled_refcell, - &partition_method_manual_crypttab_json_refcell, + &partition_method_manual_crypttab_entry_array_refcell, &language_changed_action); window.present() diff --git a/src/drive_mount_row/imp.rs b/src/drive_mount_row/imp.rs new file mode 100644 index 0000000..c2791ca --- /dev/null +++ b/src/drive_mount_row/imp.rs @@ -0,0 +1,175 @@ +use std::{cell::RefCell, env, rc::Rc, sync::OnceLock}; + +use adw::{prelude::*, subclass::prelude::*, *}; +use gtk::{glib as glib, Orientation::Horizontal}; +use glib::{clone, subclass::Signal, Properties}; + +use crate::partitioning_page::FstabEntry; + + + +// ANCHOR: custom_button +// Object holding the state +#[derive(Properties, Default)] +#[properties(wrapper_type = super::DriveMountRow)] +pub struct DriveMountRow { + #[property(get, set)] + fstabentry: RefCell, + #[property(get, set)] + deletable: RefCell, + #[property(get, set)] + partitionscroll: Rc>, +} +// ANCHOR_END: custom_button + +// The central trait for subclassing a GObject +#[glib::object_subclass] +impl ObjectSubclass for DriveMountRow { + const NAME: &'static str = "DriveMountRow"; + type Type = super::DriveMountRow; + type ParentType = adw::ActionRow; +} + +// ANCHOR: object_impl +// Trait shared by all GObjects +#[glib::derived_properties] +impl ObjectImpl for DriveMountRow { + fn signals() -> &'static [Signal] { + static SIGNALS: OnceLock> = OnceLock::new(); + SIGNALS.get_or_init(|| vec![Signal::builder("row-deleted").build()]) + } + fn constructed(&self) { + let current_locale = match env::var_os("LANG") { + Some(v) => v.into_string().unwrap(), + None => panic!("$LANG is not set"), + }; + rust_i18n::set_locale(current_locale.strip_suffix(".UTF-8").unwrap()); + + self.parent_constructed(); + + // Bind label to number + // `SYNC_CREATE` ensures that the label will be immediately set + let obj = self.obj(); + let action_row_content_box = gtk::Box::builder() + .orientation(Horizontal) + .spacing(0) + .vexpand(true) + .hexpand(true) + .build(); + + let partition_row_expander_adw_listbox = gtk::ListBox::builder() + .margin_end(5) + .margin_start(10) + .margin_top(5) + .margin_bottom(5) + .vexpand(true) + .hexpand(true) + .build(); + partition_row_expander_adw_listbox.add_css_class("boxed-list"); + + let partition_row_expander = adw::ExpanderRow::builder() + .subtitle(t!("subtitle_partition")) + .vexpand(true) + .hexpand(true) + .width_request(300) + .build(); + + let mountpoint_entry_row = gtk::Entry::builder() + .placeholder_text(t!("title_mountpoint")) + .hexpand(true) + .vexpand(true) + .margin_bottom(5) + .margin_top(5) + .width_request(300) + .build(); + + let mountopt_entry_row = gtk::Entry::builder() + .placeholder_text(t!("title_mountopt")) + .hexpand(true) + .vexpand(true) + .margin_start(10) + .margin_bottom(5) + .margin_top(5) + .width_request(300) + .build(); + + let partition_row_delete_button = gtk::Button::builder() + .margin_end(5) + .margin_top(5) + .margin_bottom(5) + .vexpand(true) + .icon_name("user-trash") + .halign(gtk::Align::End) + .build(); + + obj.bind_property("deletable", &partition_row_delete_button, "visible") + .sync_create() + .bidirectional() + .build(); + + partition_row_delete_button.connect_clicked(clone!( + #[weak] + obj, + move |_| + { + obj.emit_by_name::<()>("row-deleted", &[]); + } + ) + ); + + partition_row_expander_adw_listbox.append(&partition_row_expander); + action_row_content_box.append(&partition_row_expander_adw_listbox); + + action_row_content_box.append(&mountpoint_entry_row); + + action_row_content_box.append(&mountopt_entry_row); + + obj.add_prefix(&action_row_content_box); + + obj.add_suffix(&partition_row_delete_button); + + // Bind label to number + // `SYNC_CREATE` ensures that the label will be immediately set + let obj = self.obj(); + obj.bind_property("partition", &partition_row_expander, "title") + .sync_create() + .bidirectional() + .build(); + + obj.bind_property("mountpoint", &mountpoint_entry_row, "text") + .sync_create() + .bidirectional() + .build(); + + obj.bind_property("mountopt", &mountopt_entry_row, "text") + .sync_create() + .bidirectional() + .build(); + + obj.connect_partitionscroll_notify(clone!( + #[weak] + obj, + move |_| + { + partition_row_expander.add_row(&obj.property::("partitionscroll")); + } + ) + ); + } +} +// Trait shared by all widgets +impl WidgetImpl for DriveMountRow {} + +// Trait shared by all buttons +// Trait shared by all buttons + +impl ListBoxRowImpl for DriveMountRow {} + +impl PreferencesRowImpl for DriveMountRow {} + +impl ActionRowImpl for DriveMountRow { + //fn clicked(&self) { + // let incremented_number = self.obj().number() + 1; + // self.obj().set_number(incremented_number); + //} +} diff --git a/src/drive_mount_row/mod.rs b/src/drive_mount_row/mod.rs new file mode 100644 index 0000000..15a2bec --- /dev/null +++ b/src/drive_mount_row/mod.rs @@ -0,0 +1,28 @@ +mod imp; + +use glib::Object; +use gtk::glib; + +glib::wrapper! { + pub struct DriveMountRow(ObjectSubclass) + @extends adw::ActionRow, gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow, + @implements gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget; +} + +impl DriveMountRow { + pub fn new() -> Self { + Object::builder().build() + } + pub fn new_with_scroll(partitions_scroll: >k::ScrolledWindow) -> Self { + Object::builder() + .property("partitionscroll", partitions_scroll) + .build() + } +} +// ANCHOR_END: mod + +impl Default for DriveMountRow { + fn default() -> Self { + Self::new() + } +} diff --git a/src/main.rs b/src/main.rs index f1e880c..e7c8834 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,8 @@ mod timezone_page; mod partitioning_page; mod automatic_partitioning_page; mod manual_partitioning_page; +mod fstab_entry; +mod drive_mount_row; #[macro_use] extern crate rust_i18n; diff --git a/src/manual_partitioning/mod.rs b/src/manual_partitioning/mod.rs index 5a38d05..b395967 100644 --- a/src/manual_partitioning/mod.rs +++ b/src/manual_partitioning/mod.rs @@ -14,9 +14,9 @@ const MINIMUM_ROOT_BYTE_SIZE: f64 = 39000000000.0; pub fn manual_partitioning( partition_carousel: &adw::Carousel, partition_method_type_refcell: &Rc>, - partition_method_manual_fstab_json_refcell: &Rc>, + partition_method_manual_fstab_entry_array_refcell: &Rc>, partition_method_manual_luks_enabled_refcell: &Rc>, - partition_method_manual_crypttab_json_refcell: &Rc>, + partition_method_manual_crypttab_entry_array_refcell: &Rc>, language_changed_action: &gio::SimpleAction ) { let manual_partitioning_page = installer_stack_page::InstallerStackPage::new(); @@ -58,19 +58,19 @@ pub fn manual_partitioning( #[strong] partition_method_type_refcell, #[strong] - partition_method_manual_fstab_json_refcell, + partition_method_manual_fstab_entry_array_refcell, #[strong] partition_method_manual_luks_enabled_refcell, #[strong] - partition_method_manual_crypttab_json_refcell, + partition_method_manual_crypttab_entry_array_refcell, move |_automatic_partitioning_page: installer_stack_page::InstallerStackPage| { *partition_method_type_refcell.borrow_mut() = String::from("automatic"); //partition_carousel.scroll_to(&partition_carousel.nth_page(5), true) dbg!(partition_method_type_refcell.borrow()); - dbg!(partition_method_manual_fstab_json_refcell.borrow()); + dbg!(partition_method_manual_fstab_entry_array_refcell.borrow()); dbg!(partition_method_manual_luks_enabled_refcell.borrow()); - dbg!(partition_method_manual_crypttab_json_refcell.borrow()); + dbg!(partition_method_manual_crypttab_entry_array_refcell.borrow()); } ) ); diff --git a/src/manual_partitioning_page/mod.rs b/src/manual_partitioning_page/mod.rs index 022599e..dbecdd0 100644 --- a/src/manual_partitioning_page/mod.rs +++ b/src/manual_partitioning_page/mod.rs @@ -1,7 +1,8 @@ use adw::gio; use crate::installer_stack_page; use gtk::{prelude::*, glib as glib}; -use crate::partitioning_page::{get_block_devices}; +use crate::partitioning_page::{get_partitions, CrypttabEntry, FstabEntry, Partition}; +use crate::drive_mount_row::{DriveMountRow}; use adw::{prelude::*}; use glib::{clone, closure_local, ffi::gboolean}; use std::{rc::Rc, cell::RefCell}; @@ -10,13 +11,12 @@ const MINIMUM_EFI_BYTE_SIZE: f64 = 500000000.0; const MINIMUM_BOOT_BYTE_SIZE: f64 = 1000000000.0; const MINIMUM_ROOT_BYTE_SIZE: f64 = 39000000000.0; - pub fn manual_partitioning_page( partition_carousel: &adw::Carousel, partition_method_type_refcell: &Rc>, - partition_method_manual_fstab_json_refcell: &Rc>, + partition_method_manual_fstab_entry_array_refcell: &Rc>>, partition_method_manual_luks_enabled_refcell: &Rc>, - partition_method_manual_crypttab_json_refcell: &Rc>, + partition_method_manual_crypttab_entry_array_refcell: &Rc>>, language_changed_action: &gio::SimpleAction ) { let manual_partitioning_page = installer_stack_page::InstallerStackPage::new(); @@ -26,6 +26,8 @@ pub fn manual_partitioning_page( manual_partitioning_page.set_back_sensitive(true); manual_partitioning_page.set_next_sensitive(false); + let partition_array_refcell = Rc::new(RefCell::new(get_partitions())); + // let content_box = gtk::Box::builder() @@ -34,8 +36,44 @@ pub fn manual_partitioning_page( .vexpand(true) .build(); - // + let drive_mounts_adw_listbox = gtk::ListBox::builder().hexpand(true).vexpand(true).build(); + drive_mounts_adw_listbox.add_css_class("boxed-list"); + + let drive_mounts_viewport = gtk::ScrolledWindow::builder() + .margin_top(30) + .margin_bottom(30) + .margin_start(30) + .margin_end(30) + .hexpand(true) + .vexpand(true) + .child(&drive_mounts_adw_listbox) + .build(); + let drive_mount_add_button = gtk::Button::builder() + .icon_name("list-add") + .vexpand(true) + .hexpand(true) + .build(); + + drive_mounts_adw_listbox.append(&drive_mount_add_button); + content_box.append(&drive_mounts_viewport); + + + drive_mount_add_button.connect_clicked(clone!( + #[weak] + drive_mounts_adw_listbox, + #[strong] + partition_array_refcell, + #[strong] + partition_method_manual_fstab_entry_array_refcell, + move |_| + { + drive_mounts_adw_listbox.append(&create_mount_row(&drive_mounts_adw_listbox, &partition_array_refcell.borrow(), &partition_method_manual_fstab_entry_array_refcell)) + } + ) + ); + + // manual_partitioning_page.connect_closure( "back-button-pressed", false, @@ -58,19 +96,19 @@ pub fn manual_partitioning_page( #[strong] partition_method_type_refcell, #[strong] - partition_method_manual_fstab_json_refcell, + partition_method_manual_fstab_entry_array_refcell, #[strong] partition_method_manual_luks_enabled_refcell, #[strong] - partition_method_manual_crypttab_json_refcell, + partition_method_manual_crypttab_entry_array_refcell, move |_automatic_partitioning_page: installer_stack_page::InstallerStackPage| { *partition_method_type_refcell.borrow_mut() = String::from("manual"); //partition_carousel.scroll_to(&partition_carousel.nth_page(5), true) dbg!(partition_method_type_refcell.borrow()); - dbg!(partition_method_manual_fstab_json_refcell.borrow()); + //dbg!(partition_method_manual_fstab_entry_array_refcell.borrow()); dbg!(partition_method_manual_luks_enabled_refcell.borrow()); - dbg!(partition_method_manual_crypttab_json_refcell.borrow()); + //dbg!(partition_method_manual_crypttab_entry_array_refcell.borrow()); } ) ); @@ -96,4 +134,92 @@ pub fn manual_partitioning_page( ) ); // +} + +fn create_mount_row( + listbox: >k::ListBox, + partition_array: &Vec, + fstab_refcell_array: &Rc>> +) -> DriveMountRow { + let partition_scroll_child = gtk::ListBox::builder().build(); + + let partitions_scroll = gtk::ScrolledWindow::builder() + .hexpand(true) + .vexpand(true) + .child(&partition_scroll_child) + .build(); + + // Create row + let row = DriveMountRow::new_with_scroll(&partitions_scroll); + + let null_checkbutton = gtk::CheckButton::builder().build(); + + for partition in partition_array { + let part_name = &partition.part_name.to_owned(); + let partition_button = gtk::CheckButton::builder() + .valign(gtk::Align::Center) + .can_focus(false) + .build(); + partition_button.set_group(Some(&null_checkbutton)); + let partition_row: adw::ActionRow = + if partition.need_mapper { + let prow = adw::ActionRow::builder() + .activatable_widget(&partition_button) + .title(part_name) + .name(part_name) + .subtitle(t!("part_need_mapper")) + .build(); + prow + } else { + let prow = adw::ActionRow::builder() + .activatable_widget(&partition_button) + .title(part_name) + .name(part_name) + .subtitle(String::from(&partition.part_fs) + &pretty_bytes::converter::convert(partition.part_size)) + .build(); + prow + }; + partition_row.add_prefix(&partition_button); + partition_button.connect_toggled(clone!( + #[weak] + row, + #[weak] + listbox, + #[weak] + partition_button, + #[strong] + partition, + #[strong] + fstab_refcell_array, + move |_| + { + let mut fstab_refcell_array_ref = RefCell::borrow_mut(&fstab_refcell_array); + if partition_button.is_active() == true { + let part_name = &partition.part_name; + //row.set_partition(part_name.to_string()); + } else { + + } + } + ) + ); + partition_scroll_child.append(&partition_row); + } + + let listbox_clone = listbox.clone(); + row.connect_closure( + "row-deleted", + false, + closure_local!( + #[strong] + row, + move |row: DriveMountRow| + { + listbox_clone.remove(&row); + } + ), + ); + + // Return row + row } \ No newline at end of file diff --git a/src/partitioning_page/mod.rs b/src/partitioning_page/mod.rs index 0948479..f50f6cd 100644 --- a/src/partitioning_page/mod.rs +++ b/src/partitioning_page/mod.rs @@ -1,6 +1,7 @@ +use crate::drive_mount_row::DriveMountRow; use crate::installer_stack_page; use gtk::{prelude::*, glib as glib, gio as gio}; -use glib::{clone, closure_local}; +use glib::{clone, closure_local, Properties}; use crate::{automatic_partitioning_page, manual_partitioning_page}; use std::{rc::Rc, cell::RefCell}; use std::io::BufRead; @@ -14,9 +15,9 @@ pub fn partitioning_page( partition_method_automatic_luks_refcell: &Rc>, partition_method_automatic_ratio_refcell: &Rc>, partition_method_automatic_seperation_refcell: &Rc>, - partition_method_manual_fstab_json_refcell: &Rc>, + partition_method_manual_fstab_entry_array_refcell: &Rc>>, partition_method_manual_luks_enabled_refcell: &Rc>, - partition_method_manual_crypttab_json_refcell: &Rc>, + partition_method_manual_crypttab_entry_array_refcell: &Rc>>, language_changed_action: &gio::SimpleAction ) { let partitioning_page = installer_stack_page::InstallerStackPage::new(); @@ -109,9 +110,9 @@ pub fn partitioning_page( manual_partitioning_page::manual_partitioning_page( &partitioning_carousel, &partition_method_type_refcell, - &partition_method_manual_fstab_json_refcell, + &partition_method_manual_fstab_entry_array_refcell, &partition_method_manual_luks_enabled_refcell, - &partition_method_manual_crypttab_json_refcell, + &partition_method_manual_crypttab_entry_array_refcell, &language_changed_action); partitioning_page.connect_closure( @@ -136,7 +137,7 @@ pub struct BlockDevice { pub block_size_pretty: String } -#[derive(Debug)] +#[derive(Clone)] pub struct Partition { pub part_name: String, pub part_fs: String, @@ -146,6 +147,19 @@ pub struct Partition { pub part_size_pretty: String } +#[derive(Default)] +pub struct FstabEntry { + pub partition: String, + pub mountpoint: String, + pub mountopt: String, +} + +pub struct CrypttabEntry { + pub map: String, + pub uuid: String, + pub password: Option, +} + pub fn get_block_devices() -> Vec { let mut block_devices = Vec::new();