This commit is contained in:
Ward from fusion-voyager-3 2024-02-24 20:48:53 +03:00
parent 3620df450e
commit 02e7cac3a9
6 changed files with 720 additions and 0 deletions

81
data/config/credits.json Normal file
View File

@ -0,0 +1,81 @@
{
"developers": [
{
"id": 0,
"dev": "Welcome App's coding:\nCosmo & GlouriousEggroll"
},
{
"id": 1,
"dev": "Welcome App's UI:\nPizzaLovingNerd - risiOS BDFL"
},
{
"id": 2,
"dev": "Webapps manager:\nThe Linux Mint team"
},
{
"id": 3,
"dev": "Standalone gamescope session:\nThe ChimeraOS Team & KyleGospo"
},
{
"id": 4,
"dev": "Repositories, and firmware Manager, \nand The tiling in gnome-shell with pop-shell: \nThe Pop!OS Team"
},
{
"id": 5,
"dev": "Hybrid GPU Controls:\nasus-linux"
}, {
"id": 6,
"dev": "ISO testing VMs:\nAkiToasterUwU"
},
{
"id": 7,
"dev": "APX package manager:\nThe Vanilla OS Team"
}, {
"id": 8,
"dev": "Wallpapers:\nNeytirix & Colorman"
},
{
"id": 9,
"dev": "Logo artist:\nnesper8 (willsmanic) & MattsCreative & Piaf_Jaune"
},
{
"id": 10,
"dev": "Kernel Base:\nCachyOS team (ptr1337)"
},
{
"id": 11,
"dev": "Themeing:\nVinceliuice & Papirus"
},
{
"id": 12,
"dev": "Encryption Support:\nSkimmingDeath"
},
{
"id": 13,
"dev": "Graphics Drivers:\nKisak & Oibaf"
},
{
"id": 14,
"dev": "pikman package manager, Package Builder Hardware, \nServer Hosting:\nFerreo"
}, {
"id": 15,
"dev": "Website:\nFerreo & BL4Z3"
},
{
"id": 16,
"dev": "Anti Snap:\nThe Xtradeb team"
},
{
"id": 17,
"dev": "Technical Advisors:\nFerreo & ptr1337 & Zukureneno"
},
{
"id": 18,
"dev": "Audio Artist:\n4lk4"
},
{
"id": 19,
"dev": "Financial Contributors:\nnesper8 (willsmanic) & FlibbyJibbit & Zukureneno"
}
]
}

View File

@ -0,0 +1,157 @@
// GTK crates
use duct::cmd;
use std::path::Path;
use std::fs;
use serde::Deserialize;
use std::{thread, time};
use std::rc::Rc;
use std::cell::RefCell;
use adw::prelude::*;
use adw::*;
use glib::*;
#[allow(non_camel_case_types)]
#[derive(PartialEq, Debug, Eq, Hash, Clone, Ord, PartialOrd, Deserialize)]
struct setup_steps_entry {
id: i32,
title: String,
subtitle: String,
icon: String,
button: String,
command: String
}
pub fn setup_steps_page(
setup_steps_content_page_stack: &gtk::Stack,
window: &adw::ApplicationWindow,
internet_connected: &Rc<RefCell<bool>>
) {
let internet_connected_status = internet_connected.clone();
let (internet_loop_sender, internet_loop_receiver) = async_channel::unbounded();
let internet_loop_sender = internet_loop_sender.clone();
// The long running operation runs now in a separate thread
gio::spawn_blocking(move || loop {
thread::sleep(time::Duration::from_secs(1));
internet_loop_sender
.send_blocking(true)
.expect("The channel needs to be open.");
});
let setup_steps_page_box = gtk::Box::builder()
.vexpand(true)
.hexpand(true)
.build();
let setup_steps_page_listbox = gtk::ListBox::builder()
.margin_top(20)
.margin_bottom(20)
.margin_start(20)
.margin_end(20)
.vexpand(true)
.hexpand(true)
.build();
setup_steps_page_listbox.add_css_class("boxed-list");
let setup_steps_page_scroll = gtk::ScrolledWindow::builder()
// that puts items vertically
.hexpand(true)
.vexpand(true)
.child(&setup_steps_page_box)
.propagate_natural_width(true)
.propagate_natural_height(true)
.build();
let internet_loop_context = MainContext::default();
// The main loop executes the asynchronous block
internet_loop_context.spawn_local(
clone!(@strong internet_connected_status, @weak setup_steps_page_box => async move {
while let Ok(_state) = internet_loop_receiver.recv().await {
if *internet_connected_status.borrow_mut() == true {
setup_steps_page_box.set_sensitive(true);
} else {
setup_steps_page_box.set_sensitive(false);
}
}
}),
);
let mut json_array: Vec<setup_steps_entry> = Vec::new();
let json_path = "/home/ward/builds/pkg-pika-welcome/data/config/setup_steps.json";
let json_data = fs::read_to_string(json_path).expect("Unable to read json");
let json_data: serde_json::Value = serde_json::from_str(&json_data).expect("JSON format invalid");
if let serde_json::Value::Array(setup_steps) = &json_data["setup_steps"] {
for setup_steps_entry in setup_steps {
let setup_steps_entry_struct: setup_steps_entry = serde_json::from_value(setup_steps_entry.clone()).unwrap();
json_array.push(setup_steps_entry_struct);
}
}
for setup_steps_entry in json_array {
let (entry_command_status_loop_sender, entry_command_status_loop_receiver) = async_channel::unbounded();
let entry_command_status_loop_sender: async_channel::Sender<bool> = entry_command_status_loop_sender.clone();
let entry_title = setup_steps_entry.title;
let entry_subtitle = setup_steps_entry.subtitle;
let entry_icon = setup_steps_entry.icon;
let entry_button = setup_steps_entry.button;
let entry_command = setup_steps_entry.command;
let entry_row = adw::ActionRow::builder()
.title(t!(&entry_title))
.subtitle(t!(&entry_subtitle))
.vexpand(true)
.hexpand(true)
.build();
let entry_row_icon = gtk::Image::builder()
.icon_name(entry_icon)
.pixel_size(80)
.vexpand(true)
.valign(gtk::Align::Center)
.build();
let entry_row_button = gtk::Button::builder()
.label(t!(&entry_button))
.vexpand(true)
.valign(gtk::Align::Center)
.build();
entry_row.add_prefix(&entry_row_icon);
entry_row.add_suffix(&entry_row_button);
entry_row_button.connect_clicked(clone!(@strong entry_command, @weak window => move |_| {
gio::spawn_blocking(clone!(@strong entry_command_status_loop_sender, @strong entry_command => move || {
if Path::new("/tmp/pika-welcome-exec.sh").exists() {
fs::remove_file("/tmp/pika-welcome-exec.sh").expect("Bad permissions on /tmp/pika-installer-gtk4-target-manual.txt");
}
fs::write("/tmp/pika-welcome-exec.sh", "#! /bin/bash\nset -e\n".to_owned() + &entry_command).expect("Unable to write file");
let _ = cmd!("chmod", "+x", "/tmp/pika-welcome-exec.sh").read();
let command = cmd!("/tmp/pika-welcome-exec.sh").run();
if command.is_err() {
entry_command_status_loop_sender.send_blocking(false).expect("The channel needs to be open.");
} else {
entry_command_status_loop_sender.send_blocking(true).expect("The channel needs to be open.");
}
}));
}));
let cmd_err_dialog = adw::MessageDialog::builder()
.body(t!("cmd_err_dialog_body"))
.heading(t!("cmd_err_dialog_heading"))
.transient_for(window)
.build();
cmd_err_dialog.add_response("cmd_err_dialog_ok", &t!("cmd_err_dialog_ok_label").to_string());
let entry_command_status_loop_context = MainContext::default();
// The main loop executes the asynchronous block
entry_command_status_loop_context.spawn_local(clone!(@weak cmd_err_dialog, @strong entry_command_status_loop_receiver => async move {
while let Ok(state) = entry_command_status_loop_receiver.recv().await {
if state == false {
cmd_err_dialog.present();
}
}
}));
setup_steps_page_listbox.append(&entry_row)
}
setup_steps_page_box.append(&setup_steps_page_listbox);
setup_steps_content_page_stack.add_titled(&setup_steps_page_scroll, Some("setup_steps_page"), &t!("setup_steps_page_title").to_string());
}

View File

@ -0,0 +1,157 @@
// GTK crates
use duct::cmd;
use std::path::Path;
use std::fs;
use serde::Deserialize;
use std::{thread, time};
use std::rc::Rc;
use std::cell::RefCell;
use adw::prelude::*;
use adw::*;
use glib::*;
#[allow(non_camel_case_types)]
#[derive(PartialEq, Debug, Eq, Hash, Clone, Ord, PartialOrd, Deserialize)]
struct setup_steps_entry {
id: i32,
title: String,
subtitle: String,
icon: String,
button: String,
command: String
}
pub fn setup_steps_page(
setup_steps_content_page_stack: &gtk::Stack,
window: &adw::ApplicationWindow,
internet_connected: &Rc<RefCell<bool>>
) {
let internet_connected_status = internet_connected.clone();
let (internet_loop_sender, internet_loop_receiver) = async_channel::unbounded();
let internet_loop_sender = internet_loop_sender.clone();
// The long running operation runs now in a separate thread
gio::spawn_blocking(move || loop {
thread::sleep(time::Duration::from_secs(1));
internet_loop_sender
.send_blocking(true)
.expect("The channel needs to be open.");
});
let setup_steps_page_box = gtk::Box::builder()
.vexpand(true)
.hexpand(true)
.build();
let setup_steps_page_listbox = gtk::ListBox::builder()
.margin_top(20)
.margin_bottom(20)
.margin_start(20)
.margin_end(20)
.vexpand(true)
.hexpand(true)
.build();
setup_steps_page_listbox.add_css_class("boxed-list");
let setup_steps_page_scroll = gtk::ScrolledWindow::builder()
// that puts items vertically
.hexpand(true)
.vexpand(true)
.child(&setup_steps_page_box)
.propagate_natural_width(true)
.propagate_natural_height(true)
.build();
let internet_loop_context = MainContext::default();
// The main loop executes the asynchronous block
internet_loop_context.spawn_local(
clone!(@strong internet_connected_status, @weak setup_steps_page_box => async move {
while let Ok(_state) = internet_loop_receiver.recv().await {
if *internet_connected_status.borrow_mut() == true {
setup_steps_page_box.set_sensitive(true);
} else {
setup_steps_page_box.set_sensitive(false);
}
}
}),
);
let mut json_array: Vec<setup_steps_entry> = Vec::new();
let json_path = "/home/ward/builds/pkg-pika-welcome/data/config/setup_steps.json";
let json_data = fs::read_to_string(json_path).expect("Unable to read json");
let json_data: serde_json::Value = serde_json::from_str(&json_data).expect("JSON format invalid");
if let serde_json::Value::Array(setup_steps) = &json_data["setup_steps"] {
for setup_steps_entry in setup_steps {
let setup_steps_entry_struct: setup_steps_entry = serde_json::from_value(setup_steps_entry.clone()).unwrap();
json_array.push(setup_steps_entry_struct);
}
}
for setup_steps_entry in json_array {
let (entry_command_status_loop_sender, entry_command_status_loop_receiver) = async_channel::unbounded();
let entry_command_status_loop_sender: async_channel::Sender<bool> = entry_command_status_loop_sender.clone();
let entry_title = setup_steps_entry.title;
let entry_subtitle = setup_steps_entry.subtitle;
let entry_icon = setup_steps_entry.icon;
let entry_button = setup_steps_entry.button;
let entry_command = setup_steps_entry.command;
let entry_row = adw::ActionRow::builder()
.title(t!(&entry_title))
.subtitle(t!(&entry_subtitle))
.vexpand(true)
.hexpand(true)
.build();
let entry_row_icon = gtk::Image::builder()
.icon_name(entry_icon)
.pixel_size(80)
.vexpand(true)
.valign(gtk::Align::Center)
.build();
let entry_row_button = gtk::Button::builder()
.label(t!(&entry_button))
.vexpand(true)
.valign(gtk::Align::Center)
.build();
entry_row.add_prefix(&entry_row_icon);
entry_row.add_suffix(&entry_row_button);
entry_row_button.connect_clicked(clone!(@strong entry_command, @weak window => move |_| {
gio::spawn_blocking(clone!(@strong entry_command_status_loop_sender, @strong entry_command => move || {
if Path::new("/tmp/pika-welcome-exec.sh").exists() {
fs::remove_file("/tmp/pika-welcome-exec.sh").expect("Bad permissions on /tmp/pika-installer-gtk4-target-manual.txt");
}
fs::write("/tmp/pika-welcome-exec.sh", "#! /bin/bash\nset -e\n".to_owned() + &entry_command).expect("Unable to write file");
let _ = cmd!("chmod", "+x", "/tmp/pika-welcome-exec.sh").read();
let command = cmd!("/tmp/pika-welcome-exec.sh").run();
if command.is_err() {
entry_command_status_loop_sender.send_blocking(false).expect("The channel needs to be open.");
} else {
entry_command_status_loop_sender.send_blocking(true).expect("The channel needs to be open.");
}
}));
}));
let cmd_err_dialog = adw::MessageDialog::builder()
.body(t!("cmd_err_dialog_body"))
.heading(t!("cmd_err_dialog_heading"))
.transient_for(window)
.build();
cmd_err_dialog.add_response("cmd_err_dialog_ok", &t!("cmd_err_dialog_ok_label").to_string());
let entry_command_status_loop_context = MainContext::default();
// The main loop executes the asynchronous block
entry_command_status_loop_context.spawn_local(clone!(@weak cmd_err_dialog, @strong entry_command_status_loop_receiver => async move {
while let Ok(state) = entry_command_status_loop_receiver.recv().await {
if state == false {
cmd_err_dialog.present();
}
}
}));
setup_steps_page_listbox.append(&entry_row)
}
setup_steps_page_box.append(&setup_steps_page_listbox);
setup_steps_content_page_stack.add_titled(&setup_steps_page_scroll, Some("setup_steps_page"), &t!("setup_steps_page_title").to_string());
}

View File

@ -0,0 +1,157 @@
// GTK crates
use duct::cmd;
use std::path::Path;
use std::fs;
use serde::Deserialize;
use std::{thread, time};
use std::rc::Rc;
use std::cell::RefCell;
use adw::prelude::*;
use adw::*;
use glib::*;
#[allow(non_camel_case_types)]
#[derive(PartialEq, Debug, Eq, Hash, Clone, Ord, PartialOrd, Deserialize)]
struct setup_steps_entry {
id: i32,
title: String,
subtitle: String,
icon: String,
button: String,
command: String
}
pub fn setup_steps_page(
setup_steps_content_page_stack: &gtk::Stack,
window: &adw::ApplicationWindow,
internet_connected: &Rc<RefCell<bool>>
) {
let internet_connected_status = internet_connected.clone();
let (internet_loop_sender, internet_loop_receiver) = async_channel::unbounded();
let internet_loop_sender = internet_loop_sender.clone();
// The long running operation runs now in a separate thread
gio::spawn_blocking(move || loop {
thread::sleep(time::Duration::from_secs(1));
internet_loop_sender
.send_blocking(true)
.expect("The channel needs to be open.");
});
let setup_steps_page_box = gtk::Box::builder()
.vexpand(true)
.hexpand(true)
.build();
let setup_steps_page_listbox = gtk::ListBox::builder()
.margin_top(20)
.margin_bottom(20)
.margin_start(20)
.margin_end(20)
.vexpand(true)
.hexpand(true)
.build();
setup_steps_page_listbox.add_css_class("boxed-list");
let setup_steps_page_scroll = gtk::ScrolledWindow::builder()
// that puts items vertically
.hexpand(true)
.vexpand(true)
.child(&setup_steps_page_box)
.propagate_natural_width(true)
.propagate_natural_height(true)
.build();
let internet_loop_context = MainContext::default();
// The main loop executes the asynchronous block
internet_loop_context.spawn_local(
clone!(@strong internet_connected_status, @weak setup_steps_page_box => async move {
while let Ok(_state) = internet_loop_receiver.recv().await {
if *internet_connected_status.borrow_mut() == true {
setup_steps_page_box.set_sensitive(true);
} else {
setup_steps_page_box.set_sensitive(false);
}
}
}),
);
let mut json_array: Vec<setup_steps_entry> = Vec::new();
let json_path = "/home/ward/builds/pkg-pika-welcome/data/config/setup_steps.json";
let json_data = fs::read_to_string(json_path).expect("Unable to read json");
let json_data: serde_json::Value = serde_json::from_str(&json_data).expect("JSON format invalid");
if let serde_json::Value::Array(setup_steps) = &json_data["setup_steps"] {
for setup_steps_entry in setup_steps {
let setup_steps_entry_struct: setup_steps_entry = serde_json::from_value(setup_steps_entry.clone()).unwrap();
json_array.push(setup_steps_entry_struct);
}
}
for setup_steps_entry in json_array {
let (entry_command_status_loop_sender, entry_command_status_loop_receiver) = async_channel::unbounded();
let entry_command_status_loop_sender: async_channel::Sender<bool> = entry_command_status_loop_sender.clone();
let entry_title = setup_steps_entry.title;
let entry_subtitle = setup_steps_entry.subtitle;
let entry_icon = setup_steps_entry.icon;
let entry_button = setup_steps_entry.button;
let entry_command = setup_steps_entry.command;
let entry_row = adw::ActionRow::builder()
.title(t!(&entry_title))
.subtitle(t!(&entry_subtitle))
.vexpand(true)
.hexpand(true)
.build();
let entry_row_icon = gtk::Image::builder()
.icon_name(entry_icon)
.pixel_size(80)
.vexpand(true)
.valign(gtk::Align::Center)
.build();
let entry_row_button = gtk::Button::builder()
.label(t!(&entry_button))
.vexpand(true)
.valign(gtk::Align::Center)
.build();
entry_row.add_prefix(&entry_row_icon);
entry_row.add_suffix(&entry_row_button);
entry_row_button.connect_clicked(clone!(@strong entry_command, @weak window => move |_| {
gio::spawn_blocking(clone!(@strong entry_command_status_loop_sender, @strong entry_command => move || {
if Path::new("/tmp/pika-welcome-exec.sh").exists() {
fs::remove_file("/tmp/pika-welcome-exec.sh").expect("Bad permissions on /tmp/pika-installer-gtk4-target-manual.txt");
}
fs::write("/tmp/pika-welcome-exec.sh", "#! /bin/bash\nset -e\n".to_owned() + &entry_command).expect("Unable to write file");
let _ = cmd!("chmod", "+x", "/tmp/pika-welcome-exec.sh").read();
let command = cmd!("/tmp/pika-welcome-exec.sh").run();
if command.is_err() {
entry_command_status_loop_sender.send_blocking(false).expect("The channel needs to be open.");
} else {
entry_command_status_loop_sender.send_blocking(true).expect("The channel needs to be open.");
}
}));
}));
let cmd_err_dialog = adw::MessageDialog::builder()
.body(t!("cmd_err_dialog_body"))
.heading(t!("cmd_err_dialog_heading"))
.transient_for(window)
.build();
cmd_err_dialog.add_response("cmd_err_dialog_ok", &t!("cmd_err_dialog_ok_label").to_string());
let entry_command_status_loop_context = MainContext::default();
// The main loop executes the asynchronous block
entry_command_status_loop_context.spawn_local(clone!(@weak cmd_err_dialog, @strong entry_command_status_loop_receiver => async move {
while let Ok(state) = entry_command_status_loop_receiver.recv().await {
if state == false {
cmd_err_dialog.present();
}
}
}));
setup_steps_page_listbox.append(&entry_row)
}
setup_steps_page_box.append(&setup_steps_page_listbox);
setup_steps_content_page_stack.add_titled(&setup_steps_page_scroll, Some("setup_steps_page"), &t!("setup_steps_page_title").to_string());
}

View File

@ -62,6 +62,16 @@ pub fn welcome_content_page(window: &adw::ApplicationWindow, content_box: &gtk::
.icon_name("dialog-information-symbolic") .icon_name("dialog-information-symbolic")
.build(); .build();
let mut json_array: Vec<GString> = Vec::new();
let json_path = "/home/ward/builds/pkg-pika-welcome/data/config/credits.json";
let json_data = std::fs::read_to_string(json_path).expect("Unable to read json");
let json_data: serde_json::Value = serde_json::from_str(&json_data).expect("JSON format invalid");
if let serde_json::Value::Array(developers) = &json_data["developers"] {
for developer in developers {
json_array.push(developer["dev"].as_str().to_owned().unwrap().into())
}
}
let credits_window = adw::AboutWindow::builder() let credits_window = adw::AboutWindow::builder()
.application_icon(APP_ICON) .application_icon(APP_ICON)
.application_name(t!("app_name")) .application_name(t!("app_name"))
@ -69,6 +79,7 @@ pub fn welcome_content_page(window: &adw::ApplicationWindow, content_box: &gtk::
.version(VERSION) .version(VERSION)
.hide_on_close(true) .hide_on_close(true)
.developer_name(t!("app_dev")) .developer_name(t!("app_dev"))
.developers(json_array)
.issue_url(APP_GITHUB.to_owned() + "/issues") .issue_url(APP_GITHUB.to_owned() + "/issues")
.build(); .build();

View File

@ -0,0 +1,157 @@
// GTK crates
use duct::cmd;
use std::path::Path;
use std::fs;
use serde::Deserialize;
use std::{thread, time};
use std::rc::Rc;
use std::cell::RefCell;
use adw::prelude::*;
use adw::*;
use glib::*;
#[allow(non_camel_case_types)]
#[derive(PartialEq, Debug, Eq, Hash, Clone, Ord, PartialOrd, Deserialize)]
struct setup_steps_entry {
id: i32,
title: String,
subtitle: String,
icon: String,
button: String,
command: String
}
pub fn setup_steps_page(
setup_steps_content_page_stack: &gtk::Stack,
window: &adw::ApplicationWindow,
internet_connected: &Rc<RefCell<bool>>
) {
let internet_connected_status = internet_connected.clone();
let (internet_loop_sender, internet_loop_receiver) = async_channel::unbounded();
let internet_loop_sender = internet_loop_sender.clone();
// The long running operation runs now in a separate thread
gio::spawn_blocking(move || loop {
thread::sleep(time::Duration::from_secs(1));
internet_loop_sender
.send_blocking(true)
.expect("The channel needs to be open.");
});
let setup_steps_page_box = gtk::Box::builder()
.vexpand(true)
.hexpand(true)
.build();
let setup_steps_page_listbox = gtk::ListBox::builder()
.margin_top(20)
.margin_bottom(20)
.margin_start(20)
.margin_end(20)
.vexpand(true)
.hexpand(true)
.build();
setup_steps_page_listbox.add_css_class("boxed-list");
let setup_steps_page_scroll = gtk::ScrolledWindow::builder()
// that puts items vertically
.hexpand(true)
.vexpand(true)
.child(&setup_steps_page_box)
.propagate_natural_width(true)
.propagate_natural_height(true)
.build();
let internet_loop_context = MainContext::default();
// The main loop executes the asynchronous block
internet_loop_context.spawn_local(
clone!(@strong internet_connected_status, @weak setup_steps_page_box => async move {
while let Ok(_state) = internet_loop_receiver.recv().await {
if *internet_connected_status.borrow_mut() == true {
setup_steps_page_box.set_sensitive(true);
} else {
setup_steps_page_box.set_sensitive(false);
}
}
}),
);
let mut json_array: Vec<setup_steps_entry> = Vec::new();
let json_path = "/home/ward/builds/pkg-pika-welcome/data/config/setup_steps.json";
let json_data = fs::read_to_string(json_path).expect("Unable to read json");
let json_data: serde_json::Value = serde_json::from_str(&json_data).expect("JSON format invalid");
if let serde_json::Value::Array(setup_steps) = &json_data["setup_steps"] {
for setup_steps_entry in setup_steps {
let setup_steps_entry_struct: setup_steps_entry = serde_json::from_value(setup_steps_entry.clone()).unwrap();
json_array.push(setup_steps_entry_struct);
}
}
for setup_steps_entry in json_array {
let (entry_command_status_loop_sender, entry_command_status_loop_receiver) = async_channel::unbounded();
let entry_command_status_loop_sender: async_channel::Sender<bool> = entry_command_status_loop_sender.clone();
let entry_title = setup_steps_entry.title;
let entry_subtitle = setup_steps_entry.subtitle;
let entry_icon = setup_steps_entry.icon;
let entry_button = setup_steps_entry.button;
let entry_command = setup_steps_entry.command;
let entry_row = adw::ActionRow::builder()
.title(t!(&entry_title))
.subtitle(t!(&entry_subtitle))
.vexpand(true)
.hexpand(true)
.build();
let entry_row_icon = gtk::Image::builder()
.icon_name(entry_icon)
.pixel_size(80)
.vexpand(true)
.valign(gtk::Align::Center)
.build();
let entry_row_button = gtk::Button::builder()
.label(t!(&entry_button))
.vexpand(true)
.valign(gtk::Align::Center)
.build();
entry_row.add_prefix(&entry_row_icon);
entry_row.add_suffix(&entry_row_button);
entry_row_button.connect_clicked(clone!(@strong entry_command, @weak window => move |_| {
gio::spawn_blocking(clone!(@strong entry_command_status_loop_sender, @strong entry_command => move || {
if Path::new("/tmp/pika-welcome-exec.sh").exists() {
fs::remove_file("/tmp/pika-welcome-exec.sh").expect("Bad permissions on /tmp/pika-installer-gtk4-target-manual.txt");
}
fs::write("/tmp/pika-welcome-exec.sh", "#! /bin/bash\nset -e\n".to_owned() + &entry_command).expect("Unable to write file");
let _ = cmd!("chmod", "+x", "/tmp/pika-welcome-exec.sh").read();
let command = cmd!("/tmp/pika-welcome-exec.sh").run();
if command.is_err() {
entry_command_status_loop_sender.send_blocking(false).expect("The channel needs to be open.");
} else {
entry_command_status_loop_sender.send_blocking(true).expect("The channel needs to be open.");
}
}));
}));
let cmd_err_dialog = adw::MessageDialog::builder()
.body(t!("cmd_err_dialog_body"))
.heading(t!("cmd_err_dialog_heading"))
.transient_for(window)
.build();
cmd_err_dialog.add_response("cmd_err_dialog_ok", &t!("cmd_err_dialog_ok_label").to_string());
let entry_command_status_loop_context = MainContext::default();
// The main loop executes the asynchronous block
entry_command_status_loop_context.spawn_local(clone!(@weak cmd_err_dialog, @strong entry_command_status_loop_receiver => async move {
while let Ok(state) = entry_command_status_loop_receiver.recv().await {
if state == false {
cmd_err_dialog.present();
}
}
}));
setup_steps_page_listbox.append(&entry_row)
}
setup_steps_page_box.append(&setup_steps_page_listbox);
setup_steps_content_page_stack.add_titled(&setup_steps_page_scroll, Some("setup_steps_page"), &t!("setup_steps_page_title").to_string());
}