integrate client cli with server ui
This commit is contained in:
parent
3b7b69665b
commit
2e8b590ffd
12
Cargo.toml
12
Cargo.toml
@ -12,22 +12,10 @@ path = "src/gui/main.rs"
|
|||||||
name = "pika_unixsocket_tools"
|
name = "pika_unixsocket_tools"
|
||||||
path = "src/pika_unixsocket_tools/lib.rs"
|
path = "src/pika_unixsocket_tools/lib.rs"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "debug_server_update_percent"
|
|
||||||
path = "src/debug_server/update_percent.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "debug_server_update_status"
|
|
||||||
path = "src/debug_server/update_status.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "apt_update"
|
name = "apt_update"
|
||||||
path = "src/apt_update/main.rs"
|
path = "src/apt_update/main.rs"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "apt_get_upgradable"
|
|
||||||
path = "src/apt_get_upgradable/main.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
adw = { version = "0.5.3", package = "libadwaita", features = ["v1_4"] }
|
adw = { version = "0.5.3", package = "libadwaita", features = ["v1_4"] }
|
||||||
gtk = { version = "0.7.3", package = "gtk4", features = ["v4_12"] }
|
gtk = { version = "0.7.3", package = "gtk4", features = ["v4_12"] }
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
use rust_apt::new_cache;
|
|
||||||
use rust_apt::cache::*;
|
|
||||||
use tokio::net::{UnixStream};
|
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
||||||
|
|
||||||
use serde::{Serialize};
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct AptPackageSocket {
|
|
||||||
name: String,
|
|
||||||
arch: String,
|
|
||||||
installed_version: String,
|
|
||||||
candidate_version: String
|
|
||||||
}
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
// Create upgradable list cache
|
|
||||||
let upgradable_cache = new_cache!().unwrap();
|
|
||||||
|
|
||||||
// Create pack sort from upgradable_cache
|
|
||||||
let upgradable_sort = PackageSort::default().upgradable().names();
|
|
||||||
|
|
||||||
for pkg in upgradable_cache.packages(&upgradable_sort) {
|
|
||||||
let package_struct = AptPackageSocket {
|
|
||||||
name: pkg.name().to_string(),
|
|
||||||
arch: pkg.arch().to_string(),
|
|
||||||
installed_version: pkg.installed().unwrap().version().to_string(),
|
|
||||||
candidate_version: pkg.candidate().unwrap().version().to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Path to the Unix socket file
|
|
||||||
let socket_path = "/tmp/pika_apt_get_upgradable.sock";
|
|
||||||
|
|
||||||
// Connect to the Unix socket
|
|
||||||
let mut stream = UnixStream::connect(socket_path).await.expect("Could not connect to server");
|
|
||||||
|
|
||||||
let message = serde_json::to_string(&package_struct).unwrap();
|
|
||||||
// Send the message to the server
|
|
||||||
stream.write_all(message.as_bytes()).await.expect("Failed to write to stream");
|
|
||||||
|
|
||||||
// Buffer to store the server's response
|
|
||||||
let mut buffer = [0; 2024];
|
|
||||||
|
|
||||||
// Read the response from the server
|
|
||||||
match stream.read(&mut buffer).await {
|
|
||||||
Ok(size) => {
|
|
||||||
// Print the received response
|
|
||||||
//println!("Response from Server on GTK4: {}", String::from_utf8_lossy(&buffer[..size]));
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// Print error message if reading fails
|
|
||||||
//eprintln!("Failed to read Server on GTK4 with Error: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
use tokio::net::{UnixListener, UnixStream};
|
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
||||||
use tokio::task;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
// Entry point of the server binary
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
// Path to the Unix socket file
|
|
||||||
let pika_apt_update_socket_path = "/tmp/pika_apt_get_upgradable.sock";
|
|
||||||
|
|
||||||
// Remove the socket file if it already exists
|
|
||||||
if Path::new(pika_apt_update_socket_path).exists() {
|
|
||||||
fs::remove_file(pika_apt_update_socket_path).expect("Could not remove existing socket file");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the Unix listener to the socket path
|
|
||||||
let pika_apt_update_listener = UnixListener::bind(pika_apt_update_socket_path).expect("Could not bind");
|
|
||||||
|
|
||||||
println!("Server listening on {}", pika_apt_update_socket_path);
|
|
||||||
|
|
||||||
// Loop to accept incoming connections
|
|
||||||
loop {
|
|
||||||
// Accept an incoming connection
|
|
||||||
match pika_apt_update_listener.accept().await {
|
|
||||||
Ok((stream, _)) => {
|
|
||||||
// Handle the connection in a separate task
|
|
||||||
task::spawn(handle_client(stream));
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// Print error message if a connection fails
|
|
||||||
eprintln!("pika_apt_update: Connection failed: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to handle a single client connection
|
|
||||||
async fn handle_client(mut stream: UnixStream) {
|
|
||||||
// Buffer to store incoming data
|
|
||||||
let mut buffer = [0; 1024];
|
|
||||||
|
|
||||||
// Read data from the stream
|
|
||||||
match stream.read(&mut buffer).await {
|
|
||||||
Ok(size) => {
|
|
||||||
// Print the received message
|
|
||||||
println!("pika_apt_update: Received: {}", String::from_utf8_lossy(&buffer[..size]));
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// Print error message if reading fails
|
|
||||||
eprintln!("Failed to read from stream: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
use tokio::net::{UnixListener, UnixStream};
|
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
||||||
use tokio::task;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
// Entry point of the server binary
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
// Path to the Unix socket file
|
|
||||||
let pika_apt_update_socket_path = "/tmp/pika_apt_update_percent.sock";
|
|
||||||
|
|
||||||
// Remove the socket file if it already exists
|
|
||||||
if Path::new(pika_apt_update_socket_path).exists() {
|
|
||||||
fs::remove_file(pika_apt_update_socket_path).expect("Could not remove existing socket file");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the Unix listener to the socket path
|
|
||||||
let pika_apt_update_listener = UnixListener::bind(pika_apt_update_socket_path).expect("Could not bind");
|
|
||||||
|
|
||||||
println!("Server listening on {}", pika_apt_update_socket_path);
|
|
||||||
|
|
||||||
// Loop to accept incoming connections
|
|
||||||
loop {
|
|
||||||
// Accept an incoming connection
|
|
||||||
match pika_apt_update_listener.accept().await {
|
|
||||||
Ok((stream, _)) => {
|
|
||||||
// Handle the connection in a separate task
|
|
||||||
task::spawn(handle_client(stream));
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// Print error message if a connection fails
|
|
||||||
eprintln!("pika_apt_update: Connection failed: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to handle a single client connection
|
|
||||||
async fn handle_client(mut stream: UnixStream) {
|
|
||||||
// Buffer to store incoming data
|
|
||||||
let mut buffer = [0; 1024];
|
|
||||||
|
|
||||||
// Read data from the stream
|
|
||||||
match stream.read(&mut buffer).await {
|
|
||||||
Ok(size) => {
|
|
||||||
// Print the received message
|
|
||||||
println!("pika_apt_update: Received: {}", String::from_utf8_lossy(&buffer[..size]));
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// Print error message if reading fails
|
|
||||||
eprintln!("Failed to read from stream: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
use tokio::net::{UnixListener, UnixStream};
|
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
||||||
use tokio::task;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
// Entry point of the server binary
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
// Path to the Unix socket file
|
|
||||||
let pika_apt_update_socket_path = "/tmp/pika_apt_update_status.sock";
|
|
||||||
|
|
||||||
// Remove the socket file if it already exists
|
|
||||||
if Path::new(pika_apt_update_socket_path).exists() {
|
|
||||||
fs::remove_file(pika_apt_update_socket_path).expect("Could not remove existing socket file");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the Unix listener to the socket path
|
|
||||||
let pika_apt_update_listener = UnixListener::bind(pika_apt_update_socket_path).expect("Could not bind");
|
|
||||||
|
|
||||||
println!("Server listening on {}", pika_apt_update_socket_path);
|
|
||||||
|
|
||||||
// Loop to accept incoming connections
|
|
||||||
loop {
|
|
||||||
// Accept an incoming connection
|
|
||||||
match pika_apt_update_listener.accept().await {
|
|
||||||
Ok((stream, _)) => {
|
|
||||||
// Handle the connection in a separate task
|
|
||||||
task::spawn(handle_client(stream));
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// Print error message if a connection fails
|
|
||||||
eprintln!("pika_apt_update: Connection failed: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to handle a single client connection
|
|
||||||
async fn handle_client(mut stream: UnixStream) {
|
|
||||||
// Buffer to store incoming data
|
|
||||||
let mut buffer = [0; 1024];
|
|
||||||
|
|
||||||
// Read data from the stream
|
|
||||||
match stream.read(&mut buffer).await {
|
|
||||||
Ok(size) => {
|
|
||||||
// Print the received message
|
|
||||||
println!("pika_apt_update: Received: {}", String::from_utf8_lossy(&buffer[..size]));
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// Print error message if reading fails
|
|
||||||
eprintln!("Failed to read from stream: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
173
src/gui/apt_package_row/imp.rs
Normal file
173
src/gui/apt_package_row/imp.rs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
use std::{cell::RefCell, default, sync::OnceLock};
|
||||||
|
|
||||||
|
use adw::*;
|
||||||
|
use adw::{prelude::*, subclass::prelude::*};
|
||||||
|
use glib::{subclass::Signal, Properties};
|
||||||
|
use gtk::{Align, glib, Orientation, SizeGroupMode, SelectionMode};
|
||||||
|
use crate::apt_update_page::AptPackageSocket;
|
||||||
|
|
||||||
|
// ANCHOR: custom_button
|
||||||
|
// Object holding the state
|
||||||
|
#[derive(Properties, Default)]
|
||||||
|
#[properties(wrapper_type = super::AptPackageRow)]
|
||||||
|
pub struct AptPackageRow {
|
||||||
|
#[property(get, set)]
|
||||||
|
package_name: RefCell<String>,
|
||||||
|
#[property(get, set)]
|
||||||
|
package_arch: RefCell<String>,
|
||||||
|
#[property(get, set)]
|
||||||
|
package_installed_version: RefCell<String>,
|
||||||
|
#[property(get, set)]
|
||||||
|
package_candidate_version: RefCell<String>
|
||||||
|
}
|
||||||
|
// ANCHOR_END: custom_button
|
||||||
|
|
||||||
|
// The central trait for subclassing a GObject
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for AptPackageRow {
|
||||||
|
const NAME: &'static str = "AptPackageRow";
|
||||||
|
type Type = super::AptPackageRow;
|
||||||
|
type ParentType = adw::ActionRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ANCHOR: object_impl
|
||||||
|
// Trait shared by all GObjects
|
||||||
|
#[glib::derived_properties]
|
||||||
|
impl ObjectImpl for AptPackageRow {
|
||||||
|
fn signals() -> &'static [Signal] {
|
||||||
|
static SIGNALS: OnceLock<Vec<Signal>> = OnceLock::new();
|
||||||
|
SIGNALS.get_or_init(|| vec![Signal::builder("row-deleted").build()])
|
||||||
|
}
|
||||||
|
fn constructed(&self) {
|
||||||
|
self.parent_constructed();
|
||||||
|
|
||||||
|
// Bind label to number
|
||||||
|
// `SYNC_CREATE` ensures that the label will be immediately set
|
||||||
|
let obj = self.obj();
|
||||||
|
|
||||||
|
let prefix_box = gtk::Box::new(Orientation::Horizontal, 0);
|
||||||
|
obj.add_prefix(&prefix_box);
|
||||||
|
|
||||||
|
obj.add_prefix(&create_version_badge("1.0-100-pika1".to_string(), "1.1-101-pika1".to_string()));
|
||||||
|
|
||||||
|
// Bind label to number
|
||||||
|
// `SYNC_CREATE` ensures that the label will be immediately set
|
||||||
|
//let obj = self.obj();
|
||||||
|
//obj.bind_property("package", &basic_expander_row_package_label, "label")
|
||||||
|
// .sync_create()
|
||||||
|
// .bidirectional()
|
||||||
|
// .build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Trait shared by all widgets
|
||||||
|
impl WidgetImpl for AptPackageRow {}
|
||||||
|
|
||||||
|
// Trait shared by all buttons
|
||||||
|
// Trait shared by all buttons
|
||||||
|
|
||||||
|
impl ListBoxRowImpl for AptPackageRow {}
|
||||||
|
impl PreferencesRowImpl for AptPackageRow {}
|
||||||
|
impl ActionRowImpl for AptPackageRow {}
|
||||||
|
|
||||||
|
fn create_version_badge(installed_version: String, candidate_version: String) -> gtk::ListBox {
|
||||||
|
let (base_version, installed_diff, candidate_diff) = get_diff_by_prefix(installed_version, candidate_version);
|
||||||
|
|
||||||
|
let badge_box = gtk::Box::builder().build();
|
||||||
|
|
||||||
|
let group_size = gtk::SizeGroup::new(SizeGroupMode::Both);
|
||||||
|
|
||||||
|
let installed_version_box = gtk::Box::new(Orientation::Horizontal, 0);
|
||||||
|
|
||||||
|
let installed_version_base_version_label = gtk::Label::builder()
|
||||||
|
.label(&base_version)
|
||||||
|
.margin_start(5)
|
||||||
|
.margin_end(5)
|
||||||
|
.margin_bottom(1)
|
||||||
|
.margin_top(1)
|
||||||
|
.valign(Align::Center)
|
||||||
|
.halign(Align::Start)
|
||||||
|
.hexpand(false)
|
||||||
|
.vexpand(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let installed_diff_label = gtk::Label::builder()
|
||||||
|
.label(installed_diff)
|
||||||
|
.margin_start(5)
|
||||||
|
.margin_end(5)
|
||||||
|
.margin_bottom(1)
|
||||||
|
.margin_top(1)
|
||||||
|
.valign(Align::Center)
|
||||||
|
.halign(Align::Start)
|
||||||
|
.hexpand(false)
|
||||||
|
.vexpand(true)
|
||||||
|
.build();
|
||||||
|
installed_diff_label.add_css_class("destructive-color-text");
|
||||||
|
|
||||||
|
installed_version_box.append(&installed_version_base_version_label.clone());
|
||||||
|
installed_version_box.append(&installed_diff_label);
|
||||||
|
group_size.add_widget(&installed_version_box);
|
||||||
|
|
||||||
|
let label_seprator = gtk::Separator::builder().build();
|
||||||
|
|
||||||
|
let candidate_version_box = gtk::Box::new(Orientation::Horizontal, 0);
|
||||||
|
|
||||||
|
let candidate_version_base_version_label = gtk::Label::builder()
|
||||||
|
.label(base_version)
|
||||||
|
.margin_start(5)
|
||||||
|
.margin_end(5)
|
||||||
|
.margin_bottom(1)
|
||||||
|
.margin_top(1)
|
||||||
|
.valign(Align::Center)
|
||||||
|
.halign(Align::Start)
|
||||||
|
.hexpand(false)
|
||||||
|
.vexpand(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let candidate_diff_label = gtk::Label::builder()
|
||||||
|
.label(candidate_diff)
|
||||||
|
.margin_start(5)
|
||||||
|
.margin_end(5)
|
||||||
|
.margin_bottom(1)
|
||||||
|
.margin_top(1)
|
||||||
|
.valign(Align::Center)
|
||||||
|
.halign(Align::Start)
|
||||||
|
.hexpand(false)
|
||||||
|
.vexpand(true)
|
||||||
|
.build();
|
||||||
|
candidate_diff_label.add_css_class("success-color-text");
|
||||||
|
|
||||||
|
candidate_version_box.append(&candidate_version_base_version_label);
|
||||||
|
candidate_version_box.append(&candidate_diff_label);
|
||||||
|
group_size.add_widget(&candidate_diff_label);
|
||||||
|
|
||||||
|
badge_box.append(&installed_version_box);
|
||||||
|
badge_box.append(&label_seprator);
|
||||||
|
badge_box.append(&candidate_version_box);
|
||||||
|
|
||||||
|
let boxedlist = gtk::ListBox::builder()
|
||||||
|
.selection_mode(SelectionMode::None)
|
||||||
|
.halign(Align::Center)
|
||||||
|
.valign(Align::End)
|
||||||
|
.margin_start(5)
|
||||||
|
.margin_end(5)
|
||||||
|
.margin_bottom(5)
|
||||||
|
.margin_top(5)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
boxedlist.add_css_class("boxed-list");
|
||||||
|
boxedlist.append(&badge_box);
|
||||||
|
boxedlist
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_diff_by_prefix(xs: String, ys: String) -> (String, String, String) {
|
||||||
|
let mut count = String::new();
|
||||||
|
for (x,y) in xs.chars().zip(ys.chars()) {
|
||||||
|
if x == y {
|
||||||
|
count.push(x)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let count_clone0 = count.clone();
|
||||||
|
return(count_clone0, xs.trim_start_matches(&count.as_str()).to_string(), ys.trim_start_matches(&count.as_str()).to_string())
|
||||||
|
}
|
34
src/gui/apt_package_row/mod.rs
Normal file
34
src/gui/apt_package_row/mod.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
mod imp;
|
||||||
|
|
||||||
|
use glib::Object;
|
||||||
|
use gtk::glib;
|
||||||
|
use crate::apt_update_page::AptPackageSocket;
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct AptPackageRow(ObjectSubclass<imp::AptPackageRow>)
|
||||||
|
@extends adw::ActionRow, gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow,
|
||||||
|
@implements gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AptPackageRow {
|
||||||
|
pub fn new(package: AptPackageSocket) -> Self {
|
||||||
|
Object::builder()
|
||||||
|
.property("package-name", package.name)
|
||||||
|
.property("package-arch", package.arch)
|
||||||
|
.property("package-installed-version", package.installed_version)
|
||||||
|
.property("package-candidate-version", package.candidate_version)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ANCHOR_END: mod
|
||||||
|
|
||||||
|
impl Default for AptPackageRow {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new(AptPackageSocket{
|
||||||
|
name: "name".to_string(),
|
||||||
|
arch: "arch".to_string(),
|
||||||
|
installed_version: "0.0".to_string(),
|
||||||
|
candidate_version: "0.0".to_string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -4,25 +4,29 @@ use rust_apt::*;
|
|||||||
use rust_apt::cache::*;
|
use rust_apt::cache::*;
|
||||||
use rust_apt::new_cache;
|
use rust_apt::new_cache;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use gtk::glib::prelude::*;
|
use gtk::glib::*;
|
||||||
use gtk::glib::{clone, MainContext};
|
|
||||||
use gtk::prelude::*;
|
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use gtk::*;
|
use gtk::*;
|
||||||
use adw::*;
|
|
||||||
use gtk::Orientation::Vertical;
|
|
||||||
use tokio::net::{UnixListener, UnixStream};
|
use tokio::net::{UnixListener, UnixStream};
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use pika_unixsocket_tools::*;
|
use pika_unixsocket_tools::*;
|
||||||
|
use crate::apt_package_row::AptPackageRow;
|
||||||
|
|
||||||
pub fn apt_update_page(window: &adw::ApplicationWindow) -> gtk::Box {
|
pub struct AptPackageSocket {
|
||||||
|
pub name: String,
|
||||||
|
pub arch: String,
|
||||||
|
pub installed_version: String,
|
||||||
|
pub candidate_version: String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apt_update_page(window: adw::ApplicationWindow) -> gtk::Box {
|
||||||
let (update_percent_sender, update_percent_receiver) = async_channel::unbounded::<String>();
|
let (update_percent_sender, update_percent_receiver) = async_channel::unbounded::<String>();
|
||||||
let update_percent_sender = update_percent_sender.clone();
|
let update_percent_sender = update_percent_sender.clone();
|
||||||
let (update_status_sender, update_status_receiver) = async_channel::unbounded::<String>();
|
let (update_status_sender, update_status_receiver) = async_channel::unbounded::<String>();
|
||||||
let update_status_sender = update_status_sender.clone();
|
let update_status_sender = update_status_sender.clone();
|
||||||
let (get_upgradable_sender, get_upgradable_receiver) = async_channel::unbounded::<String>();
|
let (get_upgradable_sender, get_upgradable_receiver) = async_channel::unbounded();
|
||||||
let get_upgradable_sender = get_upgradable_sender.clone();
|
let get_upgradable_sender = get_upgradable_sender.clone();
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
@ -33,16 +37,56 @@ pub fn apt_update_page(window: &adw::ApplicationWindow) -> gtk::Box {
|
|||||||
Runtime::new().unwrap().block_on(update_status_socket_server(update_status_sender));
|
Runtime::new().unwrap().block_on(update_status_socket_server(update_status_sender));
|
||||||
});
|
});
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
Runtime::new().unwrap().block_on(get_upgradable_socket_server(get_upgradable_sender));
|
|
||||||
});
|
|
||||||
|
|
||||||
Command::new("pkexec")
|
Command::new("pkexec")
|
||||||
.args(["/home/ward/RustroverProjects/project-leoali/target/debug/apt_update"])
|
.args(["/home/ward/RustroverProjects/project-leoali/target/debug/apt_update"])
|
||||||
.spawn();
|
.spawn();
|
||||||
|
|
||||||
|
let main_box = gtk::Box::builder()
|
||||||
|
.hexpand(true)
|
||||||
|
.vexpand(true)
|
||||||
|
.orientation(Orientation::Vertical)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let searchbar = gtk::SearchEntry::builder()
|
||||||
|
.search_delay(500)
|
||||||
|
.margin_bottom(15)
|
||||||
|
.margin_start(15)
|
||||||
|
.margin_end(30)
|
||||||
|
.margin_start(30)
|
||||||
|
.build();
|
||||||
|
searchbar.add_css_class("rounded-all-25");
|
||||||
|
|
||||||
|
let packages_boxedlist = gtk::ListBox::builder()
|
||||||
|
.selection_mode(SelectionMode::None)
|
||||||
|
.margin_bottom(15)
|
||||||
|
.margin_start(15)
|
||||||
|
.margin_end(15)
|
||||||
|
.margin_start(15)
|
||||||
|
.build();
|
||||||
|
packages_boxedlist.add_css_class("boxed-list");
|
||||||
|
let rows_size_group = gtk::SizeGroup::new(SizeGroupMode::Both);
|
||||||
|
|
||||||
|
packages_boxedlist.append(&AptPackageRow::new(AptPackageSocket{
|
||||||
|
name: "name".to_string(),
|
||||||
|
arch: "arch".to_string(),
|
||||||
|
installed_version: "0.0".to_string(),
|
||||||
|
candidate_version: "0.0".to_string()
|
||||||
|
}));
|
||||||
|
|
||||||
|
let packages_viewport = gtk::ScrolledWindow::builder()
|
||||||
|
.hscrollbar_policy(PolicyType::Never)
|
||||||
|
.vexpand(true)
|
||||||
|
.hexpand(true)
|
||||||
|
.margin_bottom(15)
|
||||||
|
.margin_start(15)
|
||||||
|
.margin_end(15)
|
||||||
|
.margin_start(15)
|
||||||
|
.height_request(390)
|
||||||
|
.child(&packages_boxedlist)
|
||||||
|
.build();
|
||||||
|
|
||||||
let apt_update_dialog_child_box = gtk::Box::builder()
|
let apt_update_dialog_child_box = gtk::Box::builder()
|
||||||
.orientation(Vertical)
|
.orientation(Orientation::Vertical)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let apt_update_dialog_progress_bar = gtk::ProgressBar::builder()
|
let apt_update_dialog_progress_bar = gtk::ProgressBar::builder()
|
||||||
@ -61,7 +105,7 @@ pub fn apt_update_page(window: &adw::ApplicationWindow) -> gtk::Box {
|
|||||||
apt_update_dialog_child_box.append(&apt_update_dialog_progress_bar);
|
apt_update_dialog_child_box.append(&apt_update_dialog_progress_bar);
|
||||||
|
|
||||||
let apt_update_dialog = adw::MessageDialog::builder()
|
let apt_update_dialog = adw::MessageDialog::builder()
|
||||||
.transient_for(window)
|
.transient_for(&window)
|
||||||
.extra_child(&apt_update_dialog_child_box)
|
.extra_child(&apt_update_dialog_child_box)
|
||||||
.heading(t!("apt_update_dialog_heading"))
|
.heading(t!("apt_update_dialog_heading"))
|
||||||
.hide_on_close(true)
|
.hide_on_close(true)
|
||||||
@ -70,11 +114,29 @@ pub fn apt_update_page(window: &adw::ApplicationWindow) -> gtk::Box {
|
|||||||
|
|
||||||
let update_percent_server_context = MainContext::default();
|
let update_percent_server_context = MainContext::default();
|
||||||
// The main loop executes the asynchronous block
|
// The main loop executes the asynchronous block
|
||||||
update_percent_server_context.spawn_local(clone!(@weak apt_update_dialog_progress_bar, @weak apt_update_dialog => async move {
|
update_percent_server_context.spawn_local(clone!(@weak apt_update_dialog_progress_bar, @weak apt_update_dialog, @strong get_upgradable_sender => async move {
|
||||||
while let Ok(state) = update_percent_receiver.recv().await {
|
while let Ok(state) = update_percent_receiver.recv().await {
|
||||||
match state.as_ref() {
|
match state.as_ref() {
|
||||||
"FN_OVERRIDE_SUCCESSFUL" => {
|
"FN_OVERRIDE_SUCCESSFUL" => {
|
||||||
apt_update_dialog.close()
|
let get_upgradable_sender = get_upgradable_sender.clone();
|
||||||
|
thread::spawn( move || {
|
||||||
|
// Create upgradable list cache
|
||||||
|
let upgradable_cache = new_cache!().unwrap();
|
||||||
|
|
||||||
|
// Create pack sort from upgradable_cache
|
||||||
|
let upgradable_sort = PackageSort::default().upgradable().names();
|
||||||
|
|
||||||
|
for pkg in upgradable_cache.packages(&upgradable_sort) {
|
||||||
|
let package_struct = AptPackageSocket {
|
||||||
|
name: pkg.name().to_string(),
|
||||||
|
arch: pkg.arch().to_string(),
|
||||||
|
installed_version: pkg.installed().unwrap().version().to_string(),
|
||||||
|
candidate_version: pkg.candidate().unwrap().version().to_string()
|
||||||
|
};
|
||||||
|
get_upgradable_sender.send_blocking(package_struct).unwrap()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
apt_update_dialog.close();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
apt_update_dialog_progress_bar.set_fraction(state.parse::<f64>().unwrap()/100.0)
|
apt_update_dialog_progress_bar.set_fraction(state.parse::<f64>().unwrap()/100.0)
|
||||||
@ -98,13 +160,16 @@ pub fn apt_update_page(window: &adw::ApplicationWindow) -> gtk::Box {
|
|||||||
// The main loop executes the asynchronous block
|
// The main loop executes the asynchronous block
|
||||||
get_upgradable_server_context.spawn_local(clone!(@weak window => async move {
|
get_upgradable_server_context.spawn_local(clone!(@weak window => async move {
|
||||||
while let Ok(state) = get_upgradable_receiver.recv().await {
|
while let Ok(state) = get_upgradable_receiver.recv().await {
|
||||||
println!("{}", state)
|
println!("{}", state.name)
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
main_box.append(&searchbar);
|
||||||
|
main_box.append(&packages_viewport);
|
||||||
|
|
||||||
apt_update_dialog.present();
|
apt_update_dialog.present();
|
||||||
gtk::Box::new(Vertical, 0)
|
main_box
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,16 +1,72 @@
|
|||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use adw::*;
|
use adw::*;
|
||||||
use gtk::Orientation;
|
use gtk::{Orientation, License};
|
||||||
use crate::apt_update_page;
|
use crate::apt_update_page;
|
||||||
use crate::apt_update_page::apt_update_page;
|
use crate::apt_update_page::apt_update_page;
|
||||||
use crate::config::{APP_ICON, APP_ID};
|
use crate::config::{APP_ICON, APP_ID, APP_GITHUB, VERSION};
|
||||||
|
use gtk::glib::{clone, MainContext};
|
||||||
|
use std::thread;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
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 window_child = gtk::Box::new(Orientation::Vertical, 0);
|
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();
|
||||||
|
|
||||||
|
std::thread::spawn(move || loop {
|
||||||
|
match Command::new("ping").arg("google.com").arg("-c 1").output() {
|
||||||
|
Ok(t) if t.status.success() => internet_loop_sender
|
||||||
|
.send_blocking(true)
|
||||||
|
.expect("The channel needs to be open"),
|
||||||
|
_ => internet_loop_sender
|
||||||
|
.send_blocking(false)
|
||||||
|
.expect("The channel needs to be open"),
|
||||||
|
};
|
||||||
|
thread::sleep(std::time::Duration::from_secs(5));
|
||||||
|
});
|
||||||
|
|
||||||
|
let window_banner = adw::Banner::builder().revealed(false).build();
|
||||||
|
|
||||||
|
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_banner => async move {
|
||||||
|
while let Ok(state) = internet_loop_receiver.recv().await {
|
||||||
|
let banner_text = t!("banner_text_no_internet").to_string();
|
||||||
|
if state == true {
|
||||||
|
*internet_connected_status.borrow_mut()=true;
|
||||||
|
if window_banner.title() == banner_text {
|
||||||
|
window_banner.set_revealed(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*internet_connected_status.borrow_mut()=false;
|
||||||
|
if window_banner.title() != t!("banner_text_url_error").to_string() {
|
||||||
|
window_banner.set_title(&banner_text);
|
||||||
|
window_banner.set_revealed(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
let window_headerbar = adw::HeaderBar::builder()
|
||||||
|
.title_widget(
|
||||||
|
&adw::WindowTitle::builder()
|
||||||
|
.title(t!("application_name"))
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let window_toolbar = adw::ToolbarView::builder().build();
|
||||||
|
|
||||||
|
window_toolbar.add_top_bar(&window_headerbar);
|
||||||
|
window_toolbar.add_top_bar(&window_banner);
|
||||||
|
|
||||||
// create the main Application window
|
// create the main Application window
|
||||||
let window = adw::ApplicationWindow::builder()
|
let window = adw::ApplicationWindow::builder()
|
||||||
@ -24,15 +80,33 @@ pub fn build_ui(app: &adw::Application) {
|
|||||||
// Minimum Size/Default
|
// Minimum Size/Default
|
||||||
.width_request(700)
|
.width_request(700)
|
||||||
.height_request(500)
|
.height_request(500)
|
||||||
.content(&window_child)
|
.content(&window_toolbar)
|
||||||
.deletable(false)
|
|
||||||
// Startup
|
// Startup
|
||||||
.startup_id(APP_ID)
|
.startup_id(APP_ID)
|
||||||
// build the window
|
// build the window
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
window_child.append(&apt_update_page::apt_update_page(&window));
|
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!("application_name"))
|
||||||
|
.transient_for(&window)
|
||||||
|
.version(VERSION)
|
||||||
|
.hide_on_close(true)
|
||||||
|
.developer_name(t!("developer_name"))
|
||||||
|
.license_type(License::Gpl20)
|
||||||
|
.issue_url(APP_GITHUB.to_owned() + "/issues")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
window_headerbar.pack_end(&credits_button);
|
||||||
|
credits_button
|
||||||
|
.connect_clicked(clone!(@weak credits_button => move |_| credits_window.present()));
|
||||||
|
|
||||||
// show the window
|
// show the window
|
||||||
window.present()
|
window.present();
|
||||||
|
|
||||||
|
window_toolbar.set_content(Some(&apt_update_page::apt_update_page(window)));
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
pub const APP_ID: &str = "com.github.pikaos-linux.pikafirstsetup";
|
pub const APP_ID: &str = "com.github.pikaos-linux.pikafirstsetup";
|
||||||
pub const DISTRO_ICON: &str = "pika-logo";
|
pub const DISTRO_ICON: &str = "pika-logo";
|
||||||
//pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
pub const APP_ICON: &str = "com.github.pikaos-linux.pikawelcome";
|
pub const APP_ICON: &str = "com.github.pikaos-linux.pikawelcome";
|
||||||
//pub const APP_GITHUB: &str = "https://github.com/PikaOS-Linux/pkg-pika-welcome";
|
pub const APP_GITHUB: &str = "https://github.com/PikaOS-Linux/pkg-pika-welcome";
|
@ -2,6 +2,7 @@
|
|||||||
mod config;
|
mod config;
|
||||||
mod build_ui;
|
mod build_ui;
|
||||||
mod apt_update_page;
|
mod apt_update_page;
|
||||||
|
mod apt_package_row;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
.symbolic-accent-bg {
|
||||||
|
color: @accent_bg_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size-20-font {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rounded-all-25 {
|
||||||
|
border-radius: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.background-accent-bg {
|
||||||
|
background: @accent_bg_color;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.background-green-bg {
|
||||||
|
background: green;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.background-red-bg {
|
||||||
|
background: #ff2a03;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.round-border-only-top {
|
||||||
|
border-top-right-radius: 15px;
|
||||||
|
border-top-left-radius: 15px;
|
||||||
|
border-bottom-right-radius: 0px;
|
||||||
|
border-bottom-left-radius: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.round-border-only-bottom {
|
||||||
|
border-top-right-radius: 0px;
|
||||||
|
border-top-left-radius: 0px;
|
||||||
|
border-bottom-right-radius: 15px;
|
||||||
|
border-bottom-left-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.destructive-color-text {
|
||||||
|
color: @destructive_bg_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success-color-text {
|
||||||
|
color: @success_bg_color;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user