Adaptive Layout

This commit is contained in:
Ward from fusion-voyager-3 2024-02-24 15:34:58 +03:00
parent cfee89e952
commit a8d62bdb0d
15 changed files with 187 additions and 1277 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<schemalist> <schemalist>
<schema id="com.github.pikaos-linux.pikawelcome" path="/com/github/pikaos-linux/pikafirstsetup/"> <schema id="com.github.pikaos-linux.pikawelcome" path="/com/github/pikaos-linux/pikawelcome/">
<key name="window-width" type="i"> <key name="window-width" type="i">
<default>700</default> <default>700</default>
<summary>Default window width</summary> <summary>Default window width</summary>
@ -13,5 +13,12 @@
<default>false</default> <default>false</default>
<summary>Default window maximized behaviour</summary> <summary>Default window maximized behaviour</summary>
</key> </key>
<key type="b" name="startup-show">
<default>true</default>
<summary>Show PikaOS Welcome on startup.</summary>
<description>
Show PikaOS Welcome on startup.
</description>
</key>
</schema> </schema>
</schemalist> </schemalist>

2
debian/control vendored
View File

@ -15,4 +15,4 @@ Rules-Requires-Root: no
Package: pika-welcome Package: pika-welcome
Architecture: any Architecture: any
Depends: ${shlibs:Depends} Depends: ${shlibs:Depends}
Description: A frontend in GTK 4 and Libadwaita for initial user setup in pika. Description: A frontend in GTK 4 and Libadwaita for Post install PikaOS setup.

View File

@ -1,41 +1,56 @@
// GTK crates // GTK crates
use adw::prelude::*; use adw::prelude::*;
use adw::*; use adw::*;
use glib::*;
use gtk::Orientation;
/// Use all gtk4 libraries (gtk4 -> gtk because cargo) /// Use all gtk4 libraries (gtk4 -> gtk because cargo)
/// Use all libadwaita libraries (libadwaita -> adw because cargo) /// Use all libadwaita libraries (libadwaita -> adw because cargo)
// application crates // application crates
/// first setup crates /// first setup crates
use crate::config::*; use crate::config::*;
use crate::first_setup::*; use crate::save_window_size::save_window_size;
use crate::welcome_content_page::welcome_content_page;
pub fn build_ui(app: &adw::Application) { pub fn build_ui(app: &adw::Application) {
// setup glib // setup glib
gtk::glib::set_prgname(Some(t!("app_name").to_string())); gtk::glib::set_prgname(Some(t!("app_name").to_string()));
glib::set_application_name(&t!("app_name").to_string()); glib::set_application_name(&t!("app_name").to_string());
let glib_settings = gio::Settings::new(APP_ID);
let content_box = gtk::Box::builder()
.vexpand(true)
.hexpand(true)
.orientation(Orientation::Vertical)
.build();
// create the main Application window // create the main Application window
let window = adw::ApplicationWindow::builder() let window = adw::ApplicationWindow::builder()
// The text on the titlebar
.title(t!("app_name")) .title(t!("app_name"))
// link it to the application "app"
.application(app) .application(app)
// Add the box called "window_box" to it .content(&content_box)
// Application icon
.icon_name(APP_ICON) .icon_name(APP_ICON)
// Minimum Size/Default .default_width(glib_settings.int("window-width"))
.width_request(700) .default_height(glib_settings.int("window-height"))
.width_request(300)
.height_request(500) .height_request(500)
// Hide window instead of destroy
.hide_on_close(true)
.deletable(false)
// Startup
.startup_id(APP_ID) .startup_id(APP_ID)
// build the window
.build(); .build();
first_setup(&window); if glib_settings.boolean("is-maximized") == true {
window.maximize()
}
window.connect_close_request(move |window| {
if let Some(application) = window.application() {
save_window_size(&window, &glib_settings);
application.remove_window(window);
}
glib::Propagation::Proceed
});
//
welcome_content_page(&window, &content_box);
// show the window // show the window
window.present() window.present()
} }

View File

@ -1,223 +0,0 @@
use std::cell::RefCell;
use std::rc::Rc;
// GTK crates
use adw::prelude::*;
use adw::*;
use glib::*;
/// Use all gtk4 libraries (gtk4 -> gtk because cargo)
/// Use all libadwaita libraries (libadwaita -> adw because cargo)
use gtk::*;
use std::{thread, time};
use std::{
error::Error,
};
use duct::cmd;
use std::io::prelude::*;
use std::io::BufReader;
const CODEC_INSTALL_PROG: &str = "
#! /bin/bash
set -e
/usr/lib/pika/pika-welcome/scripts/pika-sudo.sh apt update -y && /usr/lib/pika/pika-welcome/scripts/pika-sudo.sh apt install pika-codecs-meta -y
";
fn codec_install(
log_loop_sender: async_channel::Sender<String>,
) -> Result<(), std::boxed::Box<dyn Error + Send + Sync>> {
let (pipe_reader, pipe_writer) = os_pipe::pipe()?;
let child = cmd!("bash", "-c", CODEC_INSTALL_PROG)
.stderr_to_stdout()
.stdout_file(pipe_writer)
.start()?;
for line in BufReader::new(pipe_reader).lines() {
log_loop_sender
.send_blocking(line?)
.expect("Channel needs to be opened.")
}
child.wait()?;
Ok(())
}
pub fn codec_carousel(
first_setup_carousel: &adw::Carousel,
internet_connected: &Rc<RefCell<bool>>,
window: &adw::ApplicationWindow,
) {
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 (log_loop_sender, log_loop_receiver) = async_channel::unbounded();
let log_loop_sender: async_channel::Sender<String> = log_loop_sender.clone();
let (log_status_loop_sender, log_status_loop_receiver) = async_channel::unbounded();
let log_status_loop_sender: async_channel::Sender<bool> = log_status_loop_sender.clone();
let first_setup_codec_box = gtk::Box::builder()
// that puts items vertically
.orientation(Orientation::Vertical)
.valign(gtk::Align::Center)
.hexpand(true)
.vexpand(true)
.build();
let first_setup_codec_box_text = adw::StatusPage::builder()
.icon_name("media-tape")
.title(t!("first_setup_codec_box_text_title"))
.description(t!("first_setup_codec_box_text_description"))
.build();
first_setup_codec_box_text.add_css_class("compact");
let first_setup_codec_button = gtk::Button::builder()
.label(t!("first_setup_codec_button_label"))
.sensitive(false)
.build();
first_setup_codec_button.add_css_class("suggested-action");
first_setup_codec_button.add_css_class("pill");
let first_setup_codec_skip_button = gtk::Button::builder()
.label(t!("first_setup_codec_skip_button_label"))
.sensitive(true)
.width_request(25)
.build();
let first_setup_codec_buttons_box = gtk::Box::builder()
.orientation(Orientation::Horizontal)
.halign(gtk::Align::Center)
.valign(gtk::Align::End)
.vexpand(true)
.hexpand(true)
.margin_end(15)
.margin_start(15)
.margin_bottom(15)
.margin_top(15)
.spacing(80)
.build();
first_setup_codec_skip_button.add_css_class("pill");
let codec_install_log_terminal_buffer = gtk::TextBuffer::builder().build();
let codec_install_log_terminal = gtk::TextView::builder()
.vexpand(true)
.hexpand(true)
.editable(false)
.buffer(&codec_install_log_terminal_buffer)
.build();
let codec_install_log_terminal_scroll = gtk::ScrolledWindow::builder()
.width_request(400)
.height_request(200)
.vexpand(true)
.hexpand(true)
.child(&codec_install_log_terminal)
.build();
let codec_install_dialog = adw::MessageDialog::builder()
.transient_for(window)
.hide_on_close(true)
.extra_child(&codec_install_log_terminal_scroll)
.width_request(400)
.height_request(200)
.heading(t!("codec_install_dialog_heading"))
.build();
codec_install_dialog.add_response("codec_install_dialog_ok", &t!("system_update_dialog_ok_label"));
first_setup_codec_buttons_box.append(&first_setup_codec_button);
first_setup_codec_buttons_box.append(&first_setup_codec_skip_button);
first_setup_codec_box.append(&first_setup_codec_box_text);
first_setup_codec_box.append(&first_setup_codec_buttons_box);
first_setup_carousel.append(&first_setup_codec_box);
let internet_loop_context = MainContext::default();
// The main loop executes the asynchronous block
internet_loop_context.spawn_local(
clone!(@strong internet_connected_status, @weak first_setup_codec_button => async move {
while let Ok(_state) = internet_loop_receiver.recv().await {
if *internet_connected_status.borrow_mut() == true {
first_setup_codec_button.set_sensitive(true);
first_setup_codec_button.set_label(&t!("first_setup_codec_button_label"));
} else {
first_setup_codec_button.set_sensitive(false);
first_setup_codec_button.set_label(&t!("internet_network_disabled"));
}
}
}),
);
let log_loop_context = MainContext::default();
// The main loop executes the asynchronous block
log_loop_context.spawn_local(clone!(@weak codec_install_log_terminal_buffer, @weak codec_install_dialog => async move {
while let Ok(state) = log_loop_receiver.recv().await {
codec_install_log_terminal_buffer.insert(&mut codec_install_log_terminal_buffer.end_iter(), &("\n".to_string() + &state))
}
}));
let log_status_loop_context = MainContext::default();
// The main loop executes the asynchronous block
log_status_loop_context.spawn_local(clone!(@weak codec_install_dialog, @weak first_setup_codec_button, @weak first_setup_codec_skip_button => async move {
while let Ok(state) = log_status_loop_receiver.recv().await {
if state == true {
codec_install_dialog.set_response_enabled("codec_install_dialog_ok", true);
codec_install_dialog.set_body(&t!("codec_install_dialog_success_true"));
first_setup_codec_button.remove_css_class("suggested-action");
first_setup_codec_skip_button.set_label(&t!("internet_next_button_label"));
first_setup_codec_skip_button.add_css_class("suggested-action");
} else {
first_setup_codec_skip_button.remove_css_class("suggested-action");
first_setup_codec_skip_button.set_label(&t!("first_setup_codec_skip_button_label"));
first_setup_codec_button.add_css_class("suggested-action");
codec_install_dialog.set_response_enabled("codec_install_dialog_ok", true);
codec_install_dialog.set_body(&t!("codec_install_dialog_success_false"));
}
}
}));
codec_install_log_terminal_buffer.connect_changed(clone!(@weak codec_install_log_terminal, @weak codec_install_log_terminal_buffer,@weak codec_install_log_terminal_scroll => move |_|{
if codec_install_log_terminal_scroll.vadjustment().upper() - codec_install_log_terminal_scroll.vadjustment().value() > 100.0 {
codec_install_log_terminal_scroll.vadjustment().set_value(codec_install_log_terminal_scroll.vadjustment().upper())
}
}));
first_setup_codec_button.connect_clicked(clone!(@strong internet_connected_status, @weak codec_install_log_terminal,@weak codec_install_log_terminal_buffer, @weak codec_install_dialog,@weak first_setup_carousel => move |_| {
codec_install_log_terminal_buffer.delete(&mut codec_install_log_terminal_buffer.bounds().0, &mut codec_install_log_terminal_buffer.bounds().1);
codec_install_dialog.set_response_enabled("codec_install_dialog_ok", false);
codec_install_dialog.set_body("");
codec_install_dialog.present();
// The long running operation runs now in a separate thread
gio::spawn_blocking(clone!(@strong log_loop_sender, @strong log_status_loop_sender => move || {
let command = codec_install(log_loop_sender);
match command {
Ok(_) => {
println!("Status: Codec install Successful");
log_status_loop_sender.send_blocking(true).expect("The channel needs to be open.");
}
Err(_) => {
println!("Status: Codec install Failed");
log_status_loop_sender.send_blocking(false).expect("The channel needs to be open.");
}
}
}));
}));
first_setup_codec_skip_button.connect_clicked(clone!(@weak first_setup_carousel => move |_|{
first_setup_carousel.scroll_to(&first_setup_carousel.nth_page(6), true);
}));
}

View File

@ -1,115 +0,0 @@
use std::cell::RefCell;
use std::rc::Rc;
// GTK crates
use adw::prelude::*;
use adw::*;
use glib::*;
/// Use all gtk4 libraries (gtk4 -> gtk because cargo)
/// Use all libadwaita libraries (libadwaita -> adw because cargo)
use gtk::*;
use std::{thread, time};
use std::{
process::{Command},
};
pub fn driver_carousel(
first_setup_carousel: &adw::Carousel,
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 first_setup_driver_box = gtk::Box::builder()
// that puts items vertically
.orientation(Orientation::Vertical)
.valign(gtk::Align::Center)
.hexpand(true)
.vexpand(true)
.build();
let first_setup_driver_box_text = adw::StatusPage::builder()
.icon_name("audio-card")
.title(t!("first_setup_driver_box_text_title"))
.description(t!("first_setup_driver_box_text_description"))
.build();
first_setup_driver_box_text.add_css_class("compact");
let first_setup_driver_button = gtk::Button::builder()
.label(t!("first_setup_driver_button_label"))
.sensitive(false)
.build();
first_setup_driver_button.add_css_class("suggested-action");
first_setup_driver_button.add_css_class("pill");
let first_setup_driver_skip_button = gtk::Button::builder()
.label(t!("first_setup_driver_skip_button_label"))
.sensitive(true)
.width_request(25)
.build();
let first_setup_driver_buttons_box = gtk::Box::builder()
.orientation(Orientation::Horizontal)
.halign(gtk::Align::Center)
.valign(gtk::Align::End)
.vexpand(true)
.hexpand(true)
.margin_end(15)
.margin_start(15)
.margin_bottom(15)
.margin_top(15)
.spacing(80)
.build();
first_setup_driver_skip_button.add_css_class("pill");
first_setup_driver_buttons_box.append(&first_setup_driver_button);
first_setup_driver_buttons_box.append(&first_setup_driver_skip_button);
first_setup_driver_box.append(&first_setup_driver_box_text);
first_setup_driver_box.append(&first_setup_driver_buttons_box);
first_setup_carousel.append(&first_setup_driver_box);
let internet_loop_context = MainContext::default();
// The main loop executes the asynchronous block
internet_loop_context.spawn_local(
clone!(@strong internet_connected_status, @weak first_setup_driver_button => async move {
while let Ok(_state) = internet_loop_receiver.recv().await {
if *internet_connected_status.borrow_mut() == true {
first_setup_driver_button.set_sensitive(true);
first_setup_driver_button.set_label(&t!("first_setup_driver_button_label"));
} else {
first_setup_driver_button.set_sensitive(false);
first_setup_driver_button.set_label(&t!("internet_network_disabled"));
}
}
}),
);
first_setup_driver_button.connect_clicked(clone!(@weak first_setup_carousel, @weak first_setup_driver_button, @weak first_setup_driver_skip_button => move |_| {
Command::new("pika-drivers")
.spawn()
.expect("pika-drivers failed to start");
first_setup_driver_button.remove_css_class("suggested-action");
first_setup_driver_skip_button.set_label(&t!("internet_next_button_label"));
first_setup_driver_skip_button.add_css_class("suggested-action");
}));
first_setup_driver_skip_button.connect_clicked(clone!(@weak first_setup_carousel => move |_|{
first_setup_carousel.scroll_to(&first_setup_carousel.nth_page(5), true);
}));
}

View File

@ -1,51 +0,0 @@
// GTK crates
use adw::prelude::*;
use adw::*;
/// Use all gtk4 libraries (gtk4 -> gtk because cargo)
/// Use all libadwaita libraries (libadwaita -> adw because cargo)
use gtk::*;
use duct::cmd;
const REBOOT_PROG: &str = r###"
#! /bin/bash
userdel -r -f pikaos
reboot
"###;
pub fn final_carousel(first_setup_carousel: &adw::Carousel) {
let first_setup_final_box = gtk::Box::builder()
// that puts items vertically
.orientation(Orientation::Vertical)
.vexpand(true)
.valign(Align::Center)
.hexpand(true)
.vexpand(true)
.build();
let first_setup_final_box_text = adw::StatusPage::builder()
.icon_name("emblem-favorite")
.title(t!("first_setup_final_box_text_title"))
.description(t!("first_setup_final_box_text_description"))
.build();
first_setup_final_box_text.add_css_class("compact");
let first_setup_start_button = gtk::Button::builder()
.label(t!("first_setup_reboot_button_label"))
.halign(Align::Center)
.build();
first_setup_start_button.add_css_class("suggested-action");
first_setup_start_button.add_css_class("pill");
first_setup_final_box.append(&first_setup_final_box_text);
first_setup_final_box.append(&first_setup_start_button);
first_setup_carousel.append(&first_setup_final_box);
first_setup_start_button.connect_clicked( move |_| {
let _ = cmd!("/usr/lib/pika/pika-welcome/scripts/pika-sudo.sh", "bash", "-c", REBOOT_PROG).read();
});
}

View File

@ -1,223 +0,0 @@
use std::cell::RefCell;
use std::rc::Rc;
// GTK crates
use adw::prelude::*;
use adw::*;
use glib::*;
/// Use all gtk4 libraries (gtk4 -> gtk because cargo)
/// Use all libadwaita libraries (libadwaita -> adw because cargo)
use gtk::*;
use std::{thread, time};
use std::{
error::Error,
};
use duct::cmd;
use std::io::prelude::*;
use std::io::BufReader;
const GAMEUTILS_INSTALL_PROG: &str = "
#! /bin/bash
set -e
/usr/lib/pika/pika-welcome/scripts/pika-sudo.sh apt update -y && /usr/lib/pika/pika-welcome/scripts/pika-sudo.sh apt install pika-gameutils-meta -y
";
fn gameutils_install(
log_loop_sender: async_channel::Sender<String>,
) -> Result<(), std::boxed::Box<dyn Error + Send + Sync>> {
let (pipe_reader, pipe_writer) = os_pipe::pipe()?;
let child = cmd!("bash", "-c", GAMEUTILS_INSTALL_PROG)
.stderr_to_stdout()
.stdout_file(pipe_writer)
.start()?;
for line in BufReader::new(pipe_reader).lines() {
log_loop_sender
.send_blocking(line?)
.expect("Channel needs to be opened.")
}
child.wait()?;
Ok(())
}
pub fn gameutils_carousel(
first_setup_carousel: &adw::Carousel,
internet_connected: &Rc<RefCell<bool>>,
window: &adw::ApplicationWindow,
) {
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 (log_loop_sender, log_loop_receiver) = async_channel::unbounded();
let log_loop_sender: async_channel::Sender<String> = log_loop_sender.clone();
let (log_status_loop_sender, log_status_loop_receiver) = async_channel::unbounded();
let log_status_loop_sender: async_channel::Sender<bool> = log_status_loop_sender.clone();
let first_setup_gameutils_box = gtk::Box::builder()
// that puts items vertically
.orientation(Orientation::Vertical)
.valign(gtk::Align::Center)
.hexpand(true)
.vexpand(true)
.build();
let first_setup_gameutils_box_text = adw::StatusPage::builder()
.icon_name("input-gaming")
.title(t!("first_setup_gameutils_box_text_title"))
.description(t!("first_setup_gameutils_box_text_description"))
.build();
first_setup_gameutils_box_text.add_css_class("compact");
let first_setup_gameutils_button = gtk::Button::builder()
.label(t!("first_setup_gameutils_button_label"))
.sensitive(false)
.build();
first_setup_gameutils_button.add_css_class("suggested-action");
first_setup_gameutils_button.add_css_class("pill");
let first_setup_gameutils_skip_button = gtk::Button::builder()
.label(t!("first_setup_gameutils_skip_button_label"))
.sensitive(true)
.width_request(25)
.build();
let first_setup_gameutils_buttons_box = gtk::Box::builder()
.orientation(Orientation::Horizontal)
.halign(gtk::Align::Center)
.valign(gtk::Align::End)
.vexpand(true)
.hexpand(true)
.margin_end(15)
.margin_start(15)
.margin_bottom(15)
.margin_top(15)
.spacing(80)
.build();
first_setup_gameutils_skip_button.add_css_class("pill");
let gameutils_install_log_terminal_buffer = gtk::TextBuffer::builder().build();
let gameutils_install_log_terminal = gtk::TextView::builder()
.vexpand(true)
.hexpand(true)
.editable(false)
.buffer(&gameutils_install_log_terminal_buffer)
.build();
let gameutils_install_log_terminal_scroll = gtk::ScrolledWindow::builder()
.width_request(400)
.height_request(200)
.vexpand(true)
.hexpand(true)
.child(&gameutils_install_log_terminal)
.build();
let gameutils_install_dialog = adw::MessageDialog::builder()
.transient_for(window)
.hide_on_close(true)
.extra_child(&gameutils_install_log_terminal_scroll)
.width_request(400)
.height_request(200)
.heading(t!("gameutils_install_dialog_heading"))
.build();
gameutils_install_dialog.add_response("gameutils_install_dialog_ok", &t!("system_update_dialog_ok_label"));
first_setup_gameutils_buttons_box.append(&first_setup_gameutils_button);
first_setup_gameutils_buttons_box.append(&first_setup_gameutils_skip_button);
first_setup_gameutils_box.append(&first_setup_gameutils_box_text);
first_setup_gameutils_box.append(&first_setup_gameutils_buttons_box);
first_setup_carousel.append(&first_setup_gameutils_box);
let internet_loop_context = MainContext::default();
// The main loop executes the asynchronous block
internet_loop_context.spawn_local(
clone!(@strong internet_connected_status, @weak first_setup_gameutils_button => async move {
while let Ok(_state) = internet_loop_receiver.recv().await {
if *internet_connected_status.borrow_mut() == true {
first_setup_gameutils_button.set_sensitive(true);
first_setup_gameutils_button.set_label(&t!("first_setup_gameutils_button_label"));
} else {
first_setup_gameutils_button.set_sensitive(false);
first_setup_gameutils_button.set_label(&t!("internet_network_disabled"));
}
}
}),
);
let log_loop_context = MainContext::default();
// The main loop executes the asynchronous block
log_loop_context.spawn_local(clone!(@weak gameutils_install_log_terminal_buffer, @weak gameutils_install_dialog => async move {
while let Ok(state) = log_loop_receiver.recv().await {
gameutils_install_log_terminal_buffer.insert(&mut gameutils_install_log_terminal_buffer.end_iter(), &("\n".to_string() + &state))
}
}));
let log_status_loop_context = MainContext::default();
// The main loop executes the asynchronous block
log_status_loop_context.spawn_local(clone!(@weak gameutils_install_dialog, @weak first_setup_gameutils_button, @weak first_setup_gameutils_skip_button => async move {
while let Ok(state) = log_status_loop_receiver.recv().await {
if state == true {
gameutils_install_dialog.set_response_enabled("gameutils_install_dialog_ok", true);
gameutils_install_dialog.set_body(&t!("gameutils_install_dialog_success_true"));
first_setup_gameutils_button.remove_css_class("suggested-action");
first_setup_gameutils_skip_button.set_label("Next");
first_setup_gameutils_skip_button.add_css_class("suggested-action");
} else {
first_setup_gameutils_skip_button.remove_css_class("suggested-action");
first_setup_gameutils_skip_button.set_label("Skip Meta Package Installation");
first_setup_gameutils_button.add_css_class("suggested-action");
gameutils_install_dialog.set_response_enabled("gameutils_install_dialog_ok", true);
gameutils_install_dialog.set_body(&t!("gameutils_install_dialog_success_false"));
}
}
}));
gameutils_install_log_terminal_buffer.connect_changed(clone!(@weak gameutils_install_log_terminal, @weak gameutils_install_log_terminal_buffer,@weak gameutils_install_log_terminal_scroll => move |_|{
if gameutils_install_log_terminal_scroll.vadjustment().upper() - gameutils_install_log_terminal_scroll.vadjustment().value() > 100.0 {
gameutils_install_log_terminal_scroll.vadjustment().set_value(gameutils_install_log_terminal_scroll.vadjustment().upper())
}
}));
first_setup_gameutils_button.connect_clicked(clone!(@strong internet_connected_status, @weak gameutils_install_log_terminal,@weak gameutils_install_log_terminal_buffer, @weak gameutils_install_dialog,@weak first_setup_carousel => move |_| {
gameutils_install_log_terminal_buffer.delete(&mut gameutils_install_log_terminal_buffer.bounds().0, &mut gameutils_install_log_terminal_buffer.bounds().1);
gameutils_install_dialog.set_response_enabled("gameutils_install_dialog_ok", false);
gameutils_install_dialog.set_body("");
gameutils_install_dialog.present();
// The long running operation runs now in a separate thread
gio::spawn_blocking(clone!(@strong log_loop_sender, @strong log_status_loop_sender => move || {
let command = gameutils_install(log_loop_sender);
match command {
Ok(_) => {
println!("Status: gameutils install Successful");
log_status_loop_sender.send_blocking(true).expect("The channel needs to be open.");
}
Err(_) => {
println!("Status: gameutils install Failed");
log_status_loop_sender.send_blocking(false).expect("The channel needs to be open.");
}
}
}));
}));
first_setup_gameutils_skip_button.connect_clicked(clone!(@weak first_setup_carousel => move |_|{
first_setup_carousel.scroll_to(&first_setup_carousel.nth_page(7), true);
}));
}

View File

@ -1,45 +0,0 @@
// GTK crates
use adw::prelude::*;
use adw::*;
use glib::*;
/// Use all gtk4 libraries (gtk4 -> gtk because cargo)
/// Use all libadwaita libraries (libadwaita -> adw because cargo)
use gtk::*;
use crate::config::{DISTRO_ICON};
pub fn initial_carousel(first_setup_carousel: &adw::Carousel) {
let first_setup_initial_box = gtk::Box::builder()
// that puts items vertically
.orientation(Orientation::Vertical)
.vexpand(true)
.valign(Align::Center)
.hexpand(true)
.vexpand(true)
.build();
let first_setup_initial_box_text = adw::StatusPage::builder()
.icon_name(DISTRO_ICON)
.title(t!("first_setup_initial_box_text_title"))
.description(t!("first_setup_initial_box_text_description"))
.build();
first_setup_initial_box_text.add_css_class("compact");
let first_setup_start_button = gtk::Button::builder()
.label(t!("first_setup_start_button_label"))
.halign(Align::Center)
.build();
first_setup_start_button.add_css_class("suggested-action");
first_setup_start_button.add_css_class("pill");
first_setup_initial_box.append(&first_setup_initial_box_text);
first_setup_initial_box.append(&first_setup_start_button);
first_setup_carousel.append(&first_setup_initial_box);
first_setup_start_button.connect_clicked(clone!(@weak first_setup_carousel => move |_| {
first_setup_carousel.scroll_to(&first_setup_carousel.nth_page(1), true)
}));
}

View File

@ -1,196 +0,0 @@
// GTK crates
use adw::prelude::*;
use adw::*;
use glib::*;
/// Use all gtk4 libraries (gtk4 -> gtk because cargo)
/// Use all libadwaita libraries (libadwaita -> adw because cargo)
use gtk::*;
//use crate::check_internet_connection;
use std::cell::RefCell;
use std::env;
use std::process::Command;
use std::rc::Rc;
pub fn internet_carousel(
first_setup_carousel: &adw::Carousel,
internet_connected: &Rc<RefCell<bool>>,
window: &adw::ApplicationWindow,
) {
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 {
//match check_internet_connection() {
// Ok(_) => {
// internet_loop_sender.send_blocking(true).expect("The channel needs to be open.");
// }
// Err(_) => {
// internet_loop_sender.send_blocking(false).expect("The channel needs to be open.");
// }
//}
let check_internet_connection_cli = Command::new("ping")
.arg("ppa.pika-os.com")
.arg("-c 1")
.output()
.expect("failed to execute process");
if check_internet_connection_cli.status.success() {
internet_loop_sender
.send_blocking(true)
.expect("The channel needs to be open.");
} else {
internet_loop_sender
.send_blocking(false)
.expect("The channel needs to be open.");
}
}
});
let first_setup_internet_box = gtk::Box::builder()
// that puts items vertically
.orientation(Orientation::Vertical)
.hexpand(true)
.vexpand(true)
.margin_end(15)
.margin_start(15)
.margin_bottom(15)
.margin_top(15)
.build();
let first_setup_internet_box_text = adw::StatusPage::builder()
.icon_name("network-cellular-acquiring")
.title(t!("first_setup_internet_box_text_title"))
.description(t!("first_setup_internet_box_text_description"))
.hexpand(true)
.vexpand(true)
.valign(Align::Start)
.build();
first_setup_internet_box_text.add_css_class("compact");
let internet_skip_button = gtk::Button::builder()
.label(t!("internet_skip_button_label"))
.halign(Align::Center)
.sensitive(false)
.build();
internet_skip_button.add_css_class("destructive-action");
internet_skip_button.add_css_class("pill");
let internet_next_button = gtk::Button::builder()
.label(t!("internet_next_button_label"))
.halign(Align::Center)
.sensitive(false)
.build();
internet_next_button.add_css_class("suggested-action");
internet_next_button.add_css_class("pill");
let internet_buttons_box = gtk::Box::builder()
.orientation(Orientation::Horizontal)
.halign(Align::Center)
.valign(Align::End)
.vexpand(true)
.hexpand(true)
.margin_end(15)
.margin_start(15)
.margin_bottom(15)
.margin_top(15)
.spacing(80)
.build();
let first_setup_internet_button_content_box = gtk::Box::builder()
.orientation(Orientation::Vertical)
.build();
let first_setup_internet_button_content_text = gtk::Label::builder()
.label(t!("first_setup_internet_button_content_text_label"))
.build();
let first_setup_internet_button_content = adw::ButtonContent::builder()
.label(t!("first_setup_internet_button_content_label"))
.icon_name("network-wired")
.build();
let first_setup_internet_button = gtk::Button::builder()
.child(&first_setup_internet_button_content_box)
.halign(Align::Center)
.valign(Align::Center)
.build();
internet_buttons_box.append(&internet_skip_button);
internet_buttons_box.append(&internet_next_button);
first_setup_internet_button_content_box.append(&first_setup_internet_button_content);
first_setup_internet_button_content_box.append(&first_setup_internet_button_content_text);
first_setup_carousel.append(&first_setup_internet_box);
first_setup_internet_box.append(&first_setup_internet_box_text);
first_setup_internet_box.append(&first_setup_internet_button);
first_setup_internet_box.append(&internet_buttons_box);
let first_setup_internet_skip_dialog = adw::MessageDialog::builder()
.heading(t!("first_setup_internet_skip_dialog_heading"))
.body(t!("first_setup_internet_skip_dialog_body"))
.transient_for(window)
.hide_on_close(true)
.build();
first_setup_internet_skip_dialog.add_response("skip_cancel", &t!("first_setup_internet_skip_dialog_skip_cancel_label"));
first_setup_internet_skip_dialog.add_response("skip_confirm", &t!("first_setup_internet_skip_dialog_skip_confirm_label"));
first_setup_internet_skip_dialog
.set_response_appearance("skip_confirm", adw::ResponseAppearance::Destructive);
let internet_connected_status = internet_connected.clone();
let internet_loop_context = MainContext::default();
// The main loop executes the asynchronous block
internet_loop_context.spawn_local(clone!(@weak internet_skip_button, @weak internet_next_button, @weak first_setup_internet_box_text => async move {
while let Ok(state) = internet_loop_receiver.recv().await {
if state == true {
internet_skip_button.set_sensitive(false);
internet_next_button.set_sensitive(true);
first_setup_internet_box_text.set_description(Some(&t!("first_setup_internet_box_text_description_true")));
first_setup_internet_box_text.set_icon_name(Some("network-cellular-signal-excellent"));
*internet_connected_status.borrow_mut()=true;
} else {
internet_next_button.set_sensitive(false);
internet_skip_button.set_sensitive(true);
first_setup_internet_box_text.set_description(Some(&t!("first_setup_internet_box_text_description_false")));
first_setup_internet_box_text.set_icon_name(Some("network-cellular-offline"));
*internet_connected_status.borrow_mut()=false;
}
}
}));
first_setup_internet_button.connect_clicked(move |_| {
let env_xdg_session_desktop = env::var("XDG_SESSION_DESKTOP").unwrap();
if env_xdg_session_desktop.contains("gnome") || env_xdg_session_desktop.contains("ubuntu") {
Command::new("gnome-control-center")
.arg("network")
.spawn()
.expect("gnome-control-center failed to start");
} else {
Command::new("nm-connection-editor")
.spawn()
.expect("nm-connection-editor failed to start");
}
});
internet_next_button.connect_clicked(clone!(@weak first_setup_carousel => move |_| {
first_setup_carousel.scroll_to(&first_setup_carousel.nth_page(2), true);
}));
internet_skip_button.connect_clicked(
clone!(@weak first_setup_carousel, @weak first_setup_internet_skip_dialog => move |_| {
first_setup_internet_skip_dialog.choose(None::<&gio::Cancellable>, move |choice| {
if choice == "skip_confirm" {
first_setup_carousel.scroll_to(&first_setup_carousel.nth_page(2), true);
}
});
}),
);
}

View File

@ -1,83 +0,0 @@
// GTK crates
use adw::prelude::*;
use adw::*;
use glib::*;
/// Use all gtk4 libraries (gtk4 -> gtk because cargo)
/// Use all libadwaita libraries (libadwaita -> adw because cargo)
//
use std::cell::RefCell;
use std::rc::Rc;
// carousel crates
mod initial_carousel;
mod internet_carousel;
mod user_carousel;
mod update_carousel;
mod driver_carousel;
mod codec_carousel;
mod gameutils_carousel;
mod final_carousel;
use initial_carousel::*;
use internet_carousel::*;
use user_carousel::*;
use update_carousel::*;
use driver_carousel::*;
use codec_carousel::*;
use gameutils_carousel::*;
use final_carousel::*;
pub fn first_setup(window: &adw::ApplicationWindow) {
let first_setup_carousel = adw::Carousel::builder()
.allow_long_swipes(false)
.allow_mouse_drag(false)
.allow_scroll_wheel(false)
.interactive(false)
.vexpand(true)
.hexpand(true)
.build();
let first_setup_carousel_indicator = adw::CarouselIndicatorDots::builder()
.carousel(&first_setup_carousel)
.build();
let first_setup_window_headerbar_back_button = gtk::Button::builder().label(t!("first_setup_window_headerbar_back_button_label")).build();
let first_setup_window_headerbar = adw::HeaderBar::builder()
.show_start_title_buttons(true)
.title_widget(&first_setup_carousel_indicator)
.build();
let first_setup_window_toolbarview = adw::ToolbarView::builder()
.top_bar_style(ToolbarStyle::Flat)
.content(&first_setup_carousel)
.build();
let internet_connected = Rc::new(RefCell::new(false));
first_setup_window_headerbar.pack_start(&first_setup_window_headerbar_back_button);
first_setup_window_toolbarview.add_top_bar(&first_setup_window_headerbar);
first_setup_window_headerbar_back_button.connect_clicked(clone!(@weak first_setup_carousel => move |_| {
let first_setup_prev_page = first_setup_carousel.position() - 1.0;
first_setup_carousel.scroll_to(&first_setup_carousel.nth_page(first_setup_prev_page as u32), true)
}));
// CAROUSELS
// Initial Carousel
initial_carousel(&first_setup_carousel);
internet_carousel(&first_setup_carousel, &internet_connected, &window);
user_carousel(&first_setup_carousel);
update_carousel(&first_setup_carousel, &internet_connected, &window);
driver_carousel(&first_setup_carousel, &internet_connected);
codec_carousel(&first_setup_carousel, &internet_connected, &window);
gameutils_carousel(&first_setup_carousel, &internet_connected, &window);
final_carousel(&first_setup_carousel);
// Add file to window
window.set_content(Some(&first_setup_window_toolbarview))
}

View File

@ -1,324 +0,0 @@
// GTK crates
use adw::prelude::*;
use adw::*;
use glib::*;
/// Use all gtk4 libraries (gtk4 -> gtk because cargo)
/// Use all libadwaita libraries (libadwaita -> adw because cargo)
use gtk::*;
//
use regex::Regex;
use std::cell::RefCell;
use std::rc::Rc;
use std::{thread, time};
use duct::cmd;
const USER_CREATE_PROG: &str = r###"
#! /bin/bash
USERNAME="$0"
PASSWORD="$1"
FULLNAME="$2"
HOSTNAME="$3"
adduser --quiet --disabled-password --shell /bin/bash --gecos "${FULLNAME}" "${USERNAME}"
echo "${USERNAME}":"${PASSWORD}" | chpasswd
usermod -a -G sudo "${USERNAME}"
mkdir -p /home/"${USERNAME}"
cp -rvf /etc/skel/.* /home/"${USERNAME}"/ || true
chown -R "${USERNAME}":"${USERNAME}" /home/"${USERNAME}"
usermod -a -G adm,cdrom,sudo,render,dip,video,plugdev,input,render,lpadmin "${USERNAME}"
rm -rf /etc/sddm.conf.d/zautologin.conf || true
hostnamectl set-hostname "${HOSTNAME}"
echo "127.0.0.1 ${HOSTNAME}" >> /etc/hosts
"###;
fn only_alphanumeric(input: &str) -> bool {
return input.chars().all(|c| c.is_alphanumeric());
}
fn uppercase_first_letter(s: &str) -> String {
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().chain(c).collect(),
}
}
pub fn user_carousel(first_setup_carousel: &adw::Carousel) {
let user_info_username_valid = Rc::new(RefCell::new(false));
let user_info_full_name_valid = Rc::new(RefCell::new(false));
let user_info_hostname_valid = Rc::new(RefCell::new(false));
let user_info_passwords_valid = Rc::new(RefCell::new(false));
let (user_loop_sender, user_loop_receiver) = async_channel::unbounded();
let user_loop_sender = user_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));
user_loop_sender
.send_blocking(true)
.expect("The channel needs to be open.");
});
let first_setup_user_box = gtk::Box::builder()
// that puts items vertically
.orientation(Orientation::Vertical)
.hexpand(true)
.vexpand(true)
.margin_end(15)
.margin_start(15)
.margin_bottom(15)
.margin_top(15)
.build();
let first_setup_user_box_text = adw::StatusPage::builder()
.title(t!("first_setup_user_box_text_title"))
.description(t!("first_setup_user_box_text_description"))
.hexpand(true)
.valign(Align::Start)
.build();
first_setup_user_box_text.add_css_class("compact");
let user_info_box = gtk::Box::builder()
.orientation(Orientation::Vertical)
.valign(Align::Center)
.vexpand(true)
.hexpand(true)
.build();
let user_info_box_clamp = adw::Clamp::builder()
.child(&user_info_box)
.maximum_size(500)
.build();
let user_info_username = adw::EntryRow::builder()
.hexpand(true)
.title(t!("user_info_username_title"))
.input_purpose(InputPurpose::Alpha)
.input_hints(InputHints::LOWERCASE)
.build();
let user_info_full_name = adw::EntryRow::builder()
.hexpand(true)
.title(t!("user_info_full_name_title"))
.input_purpose(InputPurpose::Name)
.build();
let user_info_password = adw::PasswordEntryRow::builder()
.hexpand(true)
.title(t!("user_info_password_title"))
.build();
let user_info_hostname = adw::EntryRow::builder()
.hexpand(true)
.title(t!("user_info_hostname_title"))
.build();
let user_info_password_verify = adw::PasswordEntryRow::builder()
.hexpand(true)
.title(t!("user_info_password_verify_title"))
.build();
let user_info_password_verify_revealer = gtk::Revealer::builder()
.child(&user_info_password_verify)
.reveal_child(false)
.transition_type(RevealerTransitionType::SwingDown)
.build();
let user_info_avatar = adw::Avatar::builder()
.show_initials(true)
.size(128)
.margin_top(15)
.margin_bottom(15)
.margin_start(15)
.margin_end(15)
.build();
let _user_info_avatar_full_name_binding = user_info_full_name
.bind_property("text", &user_info_avatar, "text")
.sync_create()
.build();
let user_info_listbox = gtk::ListBox::builder()
.margin_top(15)
.margin_bottom(15)
.margin_start(15)
.margin_end(15)
.build();
user_info_listbox.add_css_class("boxed-list");
let error_label = gtk::Label::builder()
.margin_top(15)
.margin_bottom(15)
.margin_start(15)
.margin_end(15)
.visible(false)
.build();
error_label.add_css_class("red-text");
let user_next_button = gtk::Button::builder()
.label(t!("internet_next_button_label"))
.sensitive(false)
.halign(Align::Center)
.valign(Align::End)
.vexpand(true)
.hexpand(true)
.build();
user_next_button.add_css_class("suggested-action");
user_next_button.add_css_class("pill");
first_setup_carousel.append(&first_setup_user_box);
user_info_listbox.append(&user_info_username);
user_info_listbox.append(&user_info_full_name);
user_info_listbox.append(&user_info_hostname);
user_info_listbox.append(&user_info_password);
user_info_listbox.append(&user_info_password_verify_revealer);
user_info_box.append(&user_info_avatar);
user_info_box.append(&user_info_listbox);
first_setup_user_box.append(&first_setup_user_box_text);
first_setup_user_box.append(&user_info_box_clamp);
first_setup_user_box.append(&error_label);
first_setup_user_box.append(&user_next_button);
// The main loop executes the asynchronous block
let user_loop_context = MainContext::default();
user_loop_context.spawn_local(clone!(@strong user_info_username_valid, @strong user_info_full_name_valid,@strong user_info_hostname_valid, @strong user_info_passwords_valid, @weak user_next_button => async move {
while let Ok(_state) = user_loop_receiver.recv().await {
if *user_info_username_valid.borrow_mut() == true && *user_info_full_name_valid.borrow_mut() == true && *user_info_hostname_valid.borrow_mut() && *user_info_passwords_valid.borrow_mut() == true {
user_next_button.set_sensitive(true);
} else {
user_next_button.set_sensitive(false);
}
}
}));
user_info_username.connect_changed(clone!(@strong user_info_username_valid, @weak user_info_username, @weak user_info_full_name, @weak error_label => move |_| {
let user_info_username_string = user_info_username.text().to_string();
user_info_full_name.set_text(&uppercase_first_letter(&user_info_username_string));
if user_info_username_string.len() > 32 {
user_info_username.set_text(&user_info_username_string[..32]);
user_info_username.set_position(-1);
}
if Regex::new(r"[A-Z]").unwrap().is_match(&user_info_username_string) {
user_info_username.set_text(&user_info_username_string.to_lowercase());
user_info_username.set_position(-1);
}
let mut _username_is_root = false;
let mut _username_is_pikaos = false;
let mut _username_is_special = false;
if user_info_username_string != "root" {
_username_is_root=false;
} else {
error_label.set_label(&t!("error_label_is_root_label"));
_username_is_root=true;
}
if user_info_username_string != "pikaos" {
_username_is_pikaos=false;
} else {
error_label.set_label(&t!("error_label_is_pikaos_label"));
_username_is_pikaos=true;
}
if only_alphanumeric(&user_info_username_string) {
_username_is_special=false;
} else {
error_label.set_label(&t!("error_label_username_is_special_label"));
_username_is_special=true;
}
if _username_is_root == false && _username_is_pikaos == false && _username_is_special == false {
error_label.set_visible(false);
if !user_info_username.text().is_empty() {
*user_info_username_valid.borrow_mut()=true;
}
} else {
*user_info_username_valid.borrow_mut()=false;
error_label.set_visible(true);
}
}));
user_info_full_name.connect_changed(clone!(@strong user_info_full_name_valid, @weak user_info_full_name, @weak error_label => move |_| {
let user_info_full_name_string = user_info_full_name.text().to_string();
if user_info_full_name_string.len() > 32 {
user_info_full_name.set_text(&user_info_full_name_string[..32]);
user_info_full_name.set_position(-1);
}
if user_info_full_name.text().is_empty() {
*user_info_full_name_valid.borrow_mut()=false;
} else {
*user_info_full_name_valid.borrow_mut()=true;
}
}));
user_info_hostname.connect_changed(clone!(@strong user_info_hostname_valid, @weak user_info_hostname, @weak user_info_full_name, @weak error_label => move |_| {
let user_info_hostname_string = user_info_hostname.text().to_string();
if user_info_hostname_string.len() > 32 {
user_info_hostname.set_text(&user_info_hostname_string[..32]);
user_info_hostname.set_position(-1);
}
let mut _hostname_is_special = false;
if Regex::new(r"^[A-Za-z0-9\.]*$").unwrap().is_match(&user_info_hostname_string) {
_hostname_is_special=false;
} else {
error_label.set_label(&t!("error_label_hostname_is_special_label"));
_hostname_is_special=true;
}
if _hostname_is_special == false {
error_label.set_visible(false);
if !user_info_hostname.text().is_empty() {
*user_info_hostname_valid.borrow_mut()=true;
}
} else {
*user_info_hostname_valid.borrow_mut()=false;
error_label.set_visible(true);
}
}));
user_info_password.connect_changed(clone!(@strong user_info_passwords_valid,@weak user_info_password_verify_revealer, @weak user_info_password, @weak user_info_password_verify, @weak error_label => move |_| {
if user_info_password.text().is_empty() {
user_info_password_verify_revealer.set_reveal_child(false)
} else {
user_info_password_verify_revealer.set_reveal_child(true)
}
if user_info_password.text() == user_info_password_verify.text() {
error_label.set_visible(false);
*user_info_passwords_valid.borrow_mut()=true;
} else {
*user_info_passwords_valid.borrow_mut()=false;
}
}));
user_info_password_verify.connect_changed(clone!(@strong user_info_passwords_valid, @weak user_info_password, @weak user_info_password_verify, @weak error_label => move |_| {
if user_info_password.text() == user_info_password_verify.text() {
error_label.set_visible(false);
*user_info_passwords_valid.borrow_mut()=true;
} else {
error_label.set_visible(true);
error_label.set_label(&t!("error_label_password_mismatch_label"));
*user_info_passwords_valid.borrow_mut()=false;
}
}));
user_next_button.connect_clicked(clone!(@weak first_setup_carousel, @weak user_info_username, @weak user_info_hostname, @weak user_info_password, @weak user_info_full_name, @weak user_info_hostname_valid => move |_| {
let result = cmd!("/usr/lib/pika/pika-welcome/scripts/pika-sudo.sh", "bash", "-c", USER_CREATE_PROG, &user_info_username.text(), &user_info_password.text(), &user_info_full_name.text(), &user_info_hostname.text()).read();
assert!(result.is_ok());
first_setup_carousel.scroll_to(&first_setup_carousel.nth_page(3), true);
}));
}

View File

@ -9,6 +9,8 @@ use gdk::Display;
/// Use all libadwaita libraries (libadwaita -> adw because cargo) /// Use all libadwaita libraries (libadwaita -> adw because cargo)
use gtk::*; use gtk::*;
use single_instance::SingleInstance; use single_instance::SingleInstance;
use glib::*;
use glib::prelude::*;
use std::boxed::Box; use std::boxed::Box;
use users::*; use users::*;
@ -17,8 +19,9 @@ use config::{APP_ID};
// application crates // application crates
mod build_ui; mod build_ui;
use crate::build_ui::build_ui; use crate::build_ui::build_ui;
mod save_window_size;
/// first setup crates /// first setup crates
mod first_setup; mod welcome_content_page;
// Init translations for current crate. // Init translations for current crate.
#[macro_use] #[macro_use]

View File

@ -0,0 +1,14 @@
use adw::ffi::AdwApplicationWindow;
use adw::{gio, glib};
use adw::prelude::SettingsExt;
use adw::subclass::window;
use gtk::prelude::GtkWindowExt;
use glib::*;
use glib::prelude::*;
pub fn save_window_size(window: &adw::ApplicationWindow, glib_settings: &gio::Settings) {
let size = window.default_size();
let _ = glib_settings.set_int("window-width", size.0);
let _ = glib_settings.set_int("window-height", size.1);
let _ = glib_settings.set_boolean("is-maximized", window.is_maximized());
}

View File

@ -0,0 +1,131 @@
// GTK crates
use adw::prelude::*;
use adw::*;
use glib::*;
/// Use all gtk4 libraries (gtk4 -> gtk because cargo)
/// Use all libadwaita libraries (libadwaita -> adw because cargo)
//
use std::cell::RefCell;
use std::process::Command;
use std::rc::Rc;
use adw::glib::gobject_ffi::GValue;
use gtk::Orientation::Horizontal;
// carousel crates
mod update_carousel;
use update_carousel::*;
use crate::config::{APP_GITHUB, APP_ICON, VERSION};
pub fn welcome_content_page(window: &adw::ApplicationWindow, content_box: &gtk::Box) {
let internet_connected = Rc::new(RefCell::new(false));
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 {
//match check_internet_connection() {
// Ok(_) => {
// internet_loop_sender.send_blocking(true).expect("The channel needs to be open.");
// }
// Err(_) => {
// internet_loop_sender.send_blocking(false).expect("The channel needs to be open.");
// }
//}
let check_internet_connection_cli = Command::new("ping")
.arg("ppa.pika-os.com")
.arg("-c 1")
.output()
.expect("failed to execute process");
if check_internet_connection_cli.status.success() {
internet_loop_sender
.send_blocking(true)
.expect("The channel needs to be open.");
} else {
internet_loop_sender
.send_blocking(false)
.expect("The channel needs to be open.");
}
}
});
let window_title_bar = gtk::HeaderBar::builder().show_title_buttons(true).build();
let credits_button = gtk::Button::builder()
.icon_name("dialog-information-symbolic")
.build();
let credits_window = adw::AboutWindow::builder()
.application_icon(APP_ICON)
.application_name(t!("app_name"))
.transient_for(window)
.version(VERSION)
.hide_on_close(true)
.developer_name(t!("app_dev"))
.issue_url(APP_GITHUB.to_owned() + "/issues")
.build();
content_box.append(&window_title_bar);
let welcome_content_page_stack = gtk::Stack::builder()
.vexpand(true)
.hexpand(true)
.build();
let welcome_content_page_stack_sidebar = gtk::StackSidebar::builder()
.vexpand(true)
.hexpand(true)
.stack(&welcome_content_page_stack)
.build();
let welcome_content_page_split_view = adw::OverlaySplitView::builder()
.vexpand(true)
.hexpand(true)
.content(&welcome_content_page_stack)
.sidebar(&welcome_content_page_stack_sidebar)
.max_sidebar_width(300.0)
.min_sidebar_width(300.0)
.enable_hide_gesture(true)
.enable_show_gesture(true)
.build();
let sidebar_toggle_button = gtk::ToggleButton::builder()
.icon_name("view-right-pane-symbolic")
.build();
let _sidebar_toggle_button_binding = welcome_content_page_split_view
.bind_property("show_sidebar", &sidebar_toggle_button, "active")
.sync_create()
.bidirectional()
.build();
let welcome_content_page_split_view_breakpoint = adw::Breakpoint::new(BreakpointCondition::new_length(BreakpointConditionLengthType::MaxWidth, 400.0, LengthUnit::Px));
welcome_content_page_split_view_breakpoint.add_setter(&welcome_content_page_split_view, "show_sidebar", &false.to_value());
window.add_breakpoint(welcome_content_page_split_view_breakpoint);
window_title_bar.pack_end(&credits_button);
window_title_bar.pack_start(&sidebar_toggle_button);
content_box.append(&welcome_content_page_split_view);
credits_button
.connect_clicked(clone!(@weak credits_button => move |_| credits_window.present()));
let internet_connected_status = internet_connected.clone();
let internet_loop_context = MainContext::default();
// The main loop executes the asynchronous block
internet_loop_context.spawn_local(clone!(@weak window => async move {
while let Ok(state) = internet_loop_receiver.recv().await {
if state == true {
*internet_connected_status.borrow_mut()=true;
} else {
*internet_connected_status.borrow_mut()=false;
}
}
}));
}