This commit is contained in:
Ward from fusion-voyager-3 2024-06-29 01:03:47 +03:00
parent f1b7de69a7
commit a9034a3f36
16 changed files with 430 additions and 226 deletions

5
.idea/.gitignore vendored
View File

@ -1,5 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -2,7 +2,7 @@
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/.idea/project-leoali.iml" filepath="$PROJECT_DIR$/.idea/project-leoali.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/pika-idk-manager.iml" filepath="$PROJECT_DIR$/.idea/pika-idk-manager.iml" />
</modules> </modules>
</component> </component>
</project> </project>

View File

@ -2,5 +2,6 @@
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" /> <mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/target/debug/build/rust-apt-bdd275358b00de07/out/cxxbridge/crate/rust-apt" vcs="Git" />
</component> </component>
</project> </project>

122
.idea/workspace.xml Normal file
View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="ALL" />
</component>
<component name="CargoProjects">
<cargoProject FILE="$PROJECT_DIR$/Cargo.toml" />
</component>
<component name="ChangeListManager">
<list default="true" id="df2ca9e1-e07d-43f4-bc68-0a6113fc1fa2" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/locales/en_US.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.gitignore" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/modules.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/project-leoali.iml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/vcs.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/apt_package_row/imp.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/apt_package_row/imp.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/apt_package_row/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/apt_package_row/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/apt_update_page/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/apt_update_page/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/build_ui/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/build_ui/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/config.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/config.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/main.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/style.css" beforeDir="false" afterPath="$PROJECT_DIR$/src/style.css" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MacroExpansionManager">
<option name="directoryName" value="rqc3l2bj" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 8
}</component>
<component name="ProjectId" id="2iTBzsng9KVBd9K88mZWsKzuiQ1" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;Cargo.Run apt_update.executor&quot;: &quot;Run&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.rust.reset.selective.auto.import&quot;: &quot;true&quot;,
&quot;git-widget-placeholder&quot;: &quot;master&quot;,
&quot;last_opened_file_path&quot;: &quot;/home/ward/RustroverProjects/pika-idk-manager&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;org.rust.cargo.project.model.PROJECT_DISCOVERY&quot;: &quot;true&quot;,
&quot;org.rust.first.attach.projects&quot;: &quot;true&quot;
}
}</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/src" />
<recent name="$PROJECT_DIR$/data" />
</key>
</component>
<component name="RunManager" selected="Cargo.Run apt_update">
<configuration name="Run apt_update" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="run --package pika-idk-manager --bin pika-idk-manager" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<envs />
<option name="emulateTerminal" value="true" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
<configuration name="Test pika-idk-manager" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="test --workspace" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<envs />
<option name="emulateTerminal" value="true" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
<component name="RustProjectSettings">
<option name="toolchainHomeDirectory" value="$USER_HOME$/.cargo/bin" />
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="df2ca9e1-e07d-43f4-bc68-0a6113fc1fa2" name="Changes" comment="" />
<created>1719504951223</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1719504951223</updated>
<workItem from="1719504952240" duration="1363000" />
<workItem from="1719510804090" duration="7000" />
<workItem from="1719609702948" duration="2234000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
</project>

34
Cargo.lock generated
View File

@ -1138,6 +1138,23 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pika-idk-manager"
version = "0.1.0"
dependencies = [
"async-channel",
"async-trait",
"futures 0.3.30",
"gtk4",
"libadwaita",
"rust-apt",
"rust-i18n",
"serde",
"serde_json",
"tokio",
"tokio-uds",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.14" version = "0.2.14"
@ -1208,23 +1225,6 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "project-leoali"
version = "0.1.0"
dependencies = [
"async-channel",
"async-trait",
"futures 0.3.30",
"gtk4",
"libadwaita",
"rust-apt",
"rust-i18n",
"serde",
"serde_json",
"tokio",
"tokio-uds",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.36" version = "1.0.36"

View File

@ -1,13 +1,9 @@
[package] [package]
name = "project-leoali" name = "pika-idk-manager"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "gui"
path = "src/gui/main.rs"
[lib] [lib]
name = "pika_unixsocket_tools" name = "pika_unixsocket_tools"
path = "src/pika_unixsocket_tools/lib.rs" path = "src/pika_unixsocket_tools/lib.rs"

6
locales/en_US.json Normal file
View File

@ -0,0 +1,6 @@
{
"application_name": "Pika IDK yet Manager",
"installed_version_badge_text": "Installed",
"candidate_version_badge_text": "Upgradable",
"arch_label_label": "Arch"
}

260
src/apt_package_row/imp.rs Normal file
View File

@ -0,0 +1,260 @@
use std::{cell::RefCell, default, sync::OnceLock};
use adw::*;
use adw::{prelude::*, subclass::prelude::*};
use glib::{subclass::Signal, Properties, clone};
use gtk::{Align, glib, Orientation, SizeGroupMode, SelectionMode, Widget};
use gtk::Orientation::Horizontal;
use crate::apt_update_page::AptPackageSocket;
use std::env;
// 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::ExpanderRow;
}
// 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) {
let current_locale = match env::var_os("LANG") {
Some(v) => v.into_string().unwrap().chars()
.take_while(|&ch| ch != '.')
.collect::<String>(),
None => panic!("$LANG is not set"),
};
rust_i18n::set_locale(&current_locale);
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::Vertical, 0);
let expandable_box = gtk::Box::new(Orientation::Vertical, 0);
expandable_box.add_css_class("linked");
obj.connect_package_name_notify(clone!(@weak prefix_box, @weak expandable_box, @strong obj => move |obj| {
remove_all_children(&prefix_box);
remove_all_children(&expandable_box);
//
let package_name = obj.package_name();
let package_arch = obj.package_arch();
let package_installed_version= obj.package_installed_version();
let package_candidate_version= obj.package_candidate_version();
//
let package_label = gtk::Label::builder()
.halign(Align::Start)
.margin_start(5)
.margin_end(5)
.margin_bottom(5)
.margin_top(5)
.label(package_name)
.build();
package_label.add_css_class("size-20-bold-text");
let version_box = gtk::Box::new(Orientation::Horizontal, 0);
version_box.append(&create_version_badge(package_installed_version, package_candidate_version));
version_box.append(&create_arch_badge(package_arch));
prefix_box.append(&package_label);
prefix_box.append(&version_box);
//
let expandable_page_selection_box = gtk::Box::builder()
.orientation(Orientation::Horizontal)
.hexpand(false)
.vexpand(false)
.halign(Align::Start)
.valign(Align::Start)
.build();
expandable_page_selection_box.add_css_class("linked");
let description_page_button = gtk::ToggleButton::builder()
.label("Description")
.active(true)
.build();
let changelog_page_button = gtk::ToggleButton::builder()
.label("Changelog")
.group(&description_page_button)
.build();
expandable_page_selection_box.append(&description_page_button);
expandable_page_selection_box.append(&changelog_page_button);
expandable_box.append(&expandable_page_selection_box);
}));
obj.add_prefix(&prefix_box);
obj.add_row(&expandable_box);
//let obj = self.obj();
//obj.bind_property("package-name", &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 ExpanderRowImpl 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()
.halign(Align::Start)
.hexpand(false)
.orientation(Orientation::Horizontal)
.margin_start(5)
.margin_end(5)
.margin_bottom(5)
.margin_top(5)
.build();
let installed_version_box = gtk::Box::builder()
.halign(Align::Start)
.hexpand(false)
.orientation(Orientation::Horizontal)
.tooltip_text(t!("installed_version_badge_text"))
.build();
let installed_version_base_version_label = gtk::Label::builder()
.label(format!("{}: {}", t!("installed_version_badge_text"), &base_version))
.valign(Align::Center)
.halign(Align::Start)
.hexpand(false)
.vexpand(true)
.build();
let installed_diff_label = gtk::Label::builder()
.label(installed_diff)
.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);
let label_separator = gtk::Separator::builder()
.margin_start(5)
.margin_end(5)
.build();
let candidate_version_box = gtk::Box::builder()
.halign(Align::Start)
.hexpand(false)
.orientation(Orientation::Horizontal)
.tooltip_text(t!("candidate_version_badge_text"))
.build();
let candidate_version_base_version_label = gtk::Label::builder()
.label(format!("{}: {}", t!("candidate_version_badge_text"), &base_version))
.valign(Align::Center)
.halign(Align::Start)
.hexpand(false)
.vexpand(true)
.build();
let candidate_diff_label = gtk::Label::builder()
.label(candidate_diff)
.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);
badge_box.append(&installed_version_box);
badge_box.append(&label_separator);
badge_box.append(&candidate_version_box);
let boxedlist = gtk::ListBox::builder()
.selection_mode(SelectionMode::None)
.halign(Align::Start)
.valign(Align::End)
.margin_start(5)
.margin_end(5)
.margin_bottom(10)
.build();
boxedlist.add_css_class("boxed-list");
boxedlist.append(&badge_box);
boxedlist
}
fn create_arch_badge(arch: String) -> gtk::ListBox {
let arch_label = gtk::Label::builder()
.halign(Align::Start)
.hexpand(false)
.label(format!("{}: {}", t!("arch_label_label"), arch))
.margin_start(5)
.margin_end(5)
.margin_bottom(5)
.margin_top(5)
.build();
let boxedlist = gtk::ListBox::builder()
.selection_mode(SelectionMode::None)
.halign(Align::Start)
.valign(Align::End)
.margin_start(5)
.margin_end(5)
.margin_bottom(10)
.build();
boxedlist.add_css_class("boxed-list");
boxedlist.append(&arch_label);
boxedlist
}
fn remove_all_children(parent: &impl IsA<Widget>) where impl IsA<Widget>: libadwaita::prelude::IsA<ActionRow>, impl IsA<Widget>: libadwaita::prelude::IsA<CellArea>, impl IsA<Widget>: libadwaita::prelude::IsA<EntryRow>, impl IsA<Widget>: libadwaita::prelude::IsA<ExpanderRow>, impl IsA<Widget>: libadwaita::prelude::IsA<MultiFilter>, impl IsA<Widget>: libadwaita::prelude::IsA<PreferencesGroup>, impl IsA<Widget>: libadwaita::prelude::IsA<PreferencesPage>, impl IsA<Widget>: libadwaita::prelude::IsA<PreferencesWindow>, impl IsA<Widget>: libadwaita::prelude::IsA<TextView>, impl IsA<Widget>: libadwaita::prelude::IsA<gtk4::Box>, impl IsA<Widget>: libadwaita::prelude::IsA<gtk4::Fixed>, impl IsA<Widget>: libadwaita::prelude::IsA<gtk4::Grid> {
while let Some(child) = parent.last_child() {
parent.remove(&child);
}
}
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())
}

View File

@ -6,7 +6,7 @@ use crate::apt_update_page::AptPackageSocket;
glib::wrapper! { glib::wrapper! {
pub struct AptPackageRow(ObjectSubclass<imp::AptPackageRow>) pub struct AptPackageRow(ObjectSubclass<imp::AptPackageRow>)
@extends adw::ActionRow, gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow, @extends adw::ExpanderRow, gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow,
@implements gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget; @implements gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget;
} }

View File

@ -38,7 +38,7 @@ pub fn apt_update_page(window: adw::ApplicationWindow) -> gtk::Box {
}); });
Command::new("pkexec") Command::new("pkexec")
.args(["/home/ward/RustroverProjects/project-leoali/target/debug/apt_update"]) .args(["/home/ward/RustroverProjects/pika-idk-manager/target/debug/apt_update"])
.spawn(); .spawn();
let main_box = gtk::Box::builder() let main_box = gtk::Box::builder()
@ -66,13 +66,6 @@ pub fn apt_update_page(window: adw::ApplicationWindow) -> gtk::Box {
packages_boxedlist.add_css_class("boxed-list"); packages_boxedlist.add_css_class("boxed-list");
let rows_size_group = gtk::SizeGroup::new(SizeGroupMode::Both); 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() let packages_viewport = gtk::ScrolledWindow::builder()
.hscrollbar_policy(PolicyType::Never) .hscrollbar_policy(PolicyType::Never)
.vexpand(true) .vexpand(true)
@ -94,14 +87,16 @@ pub fn apt_update_page(window: adw::ApplicationWindow) -> gtk::Box {
.hexpand(true) .hexpand(true)
.build(); .build();
apt_update_dialog_child_box.append(&gtk::Spinner::builder() let apt_update_dialog_spinner = gtk::Spinner::builder()
.hexpand(true) .hexpand(true)
.valign(Align::Start) .valign(Align::Start)
.halign(Align::Center) .halign(Align::Center)
.spinning(true) .spinning(true)
.height_request(128) .height_request(128)
.width_request(128) .width_request(128)
.build()); .build();
apt_update_dialog_child_box.append(&apt_update_dialog_spinner);
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()
@ -147,10 +142,14 @@ pub fn apt_update_page(window: adw::ApplicationWindow) -> gtk::Box {
let update_status_server_context = MainContext::default(); let update_status_server_context = MainContext::default();
// The main loop executes the asynchronous block // The main loop executes the asynchronous block
update_status_server_context.spawn_local(clone!(@weak apt_update_dialog => async move { update_status_server_context.spawn_local(clone!(@weak apt_update_dialog, @weak apt_update_dialog_spinner => async move {
while let Ok(state) = update_status_receiver.recv().await { while let Ok(state) = update_status_receiver.recv().await {
match state.as_ref() { match state.as_ref() {
"FN_OVERRIDE_SUCCESSFUL" => {} "FN_OVERRIDE_SUCCESSFUL" => {}
"FN_OVERRIDE_FAILED" => {
apt_update_dialog_spinner.set_spinning(false);
apt_update_dialog.set_body(&t!("apt_update_dialog_status_failed").to_string())
}
_ => apt_update_dialog.set_body(&state) _ => apt_update_dialog.set_body(&state)
} }
} }
@ -158,9 +157,14 @@ pub fn apt_update_page(window: adw::ApplicationWindow) -> gtk::Box {
let get_upgradable_server_context = MainContext::default(); let get_upgradable_server_context = MainContext::default();
// 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 packages_boxedlist => async move {
while let Ok(state) = get_upgradable_receiver.recv().await { while let Ok(state) = get_upgradable_receiver.recv().await {
println!("{}", state.name) packages_boxedlist.append(&AptPackageRow::new(AptPackageSocket {
name: state.name,
arch: state.arch,
installed_version: state.installed_version,
candidate_version: state.candidate_version
}));
} }
})); }));

View File

@ -1,182 +0,0 @@
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 gtk::Orientation::Horizontal;
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 package_name = obj.package_name();
let package_arch = obj.package_arch();
let package_installed_version= obj.package_installed_version();
let package_candidate_version= obj.package_candidate_version();
println!("tetst {}" package_name);
let prefix_box = gtk::Box::new(Orientation::Vertical, 0);
let package_label = gtk::Label::builder()
.build();
package_label.add_css_class("size-20-bold-text");
prefix_box.append(&package_label);
prefix_box.append(&create_version_badge(package_installed_version, package_candidate_version));
obj.add_prefix(&prefix_box);
let obj = self.obj();
obj.bind_property("package-name", &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()
.halign(Align::Start)
.hexpand(false)
.orientation(Orientation::Horizontal)
.margin_start(5)
.margin_end(5)
.margin_bottom(5)
.margin_top(5)
.build();
let installed_version_box = gtk::Box::builder()
.halign(Align::Start)
.hexpand(false)
.orientation(Orientation::Horizontal)
.tooltip_text(t!("installed_version_box_tooltip_text"))
.build();
let installed_version_base_version_label = gtk::Label::builder()
.label(&base_version)
.valign(Align::Center)
.halign(Align::Start)
.hexpand(false)
.vexpand(true)
.build();
let installed_diff_label = gtk::Label::builder()
.label(installed_diff)
.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);
let label_separator = gtk::Separator::builder()
.margin_start(5)
.margin_end(5)
.build();
let candidate_version_box = gtk::Box::builder()
.halign(Align::Start)
.hexpand(false)
.orientation(Orientation::Horizontal)
.tooltip_text(t!("candidate_version_box_tooltip_text"))
.build();
let candidate_version_base_version_label = gtk::Label::builder()
.label(base_version)
.valign(Align::Center)
.halign(Align::Start)
.hexpand(false)
.vexpand(true)
.build();
let candidate_diff_label = gtk::Label::builder()
.label(candidate_diff)
.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);
badge_box.append(&installed_version_box);
badge_box.append(&label_separator);
badge_box.append(&candidate_version_box);
let boxedlist = gtk::ListBox::builder()
.selection_mode(SelectionMode::None)
.halign(Align::Start)
.valign(Align::End)
.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())
}

View File

@ -21,10 +21,12 @@ i18n!("locales", fallback = "en_US");
/// main function /// main function
fn main() { fn main() {
let current_locale = match env::var_os("LANG") { let current_locale = match env::var_os("LANG") {
Some(v) => v.into_string().unwrap(), Some(v) => v.into_string().unwrap().chars()
.take_while(|&ch| ch != '.')
.collect::<String>(),
None => panic!("$LANG is not set"), None => panic!("$LANG is not set"),
}; };
rust_i18n::set_locale(current_locale.strip_suffix(".UTF-8").unwrap()); rust_i18n::set_locale(&current_locale);
let application = adw::Application::new( let application = adw::Application::new(
Some(APP_ID), Some(APP_ID),
Default::default(), Default::default(),