Compare commits
6 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e12312d26f | ||
|
|
6cde50daf3 | ||
|
|
1b98054024 | ||
|
|
f7f59fd24d | ||
|
|
29eedb7e9a | ||
|
|
7eec6e73c4 |
31 changed files with 1571 additions and 665 deletions
2
.github/workflows/build-flatpak.yml
vendored
2
.github/workflows/build-flatpak.yml
vendored
|
|
@ -15,5 +15,5 @@ jobs:
|
||||||
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||||
with:
|
with:
|
||||||
bundle: Burrow.flatpak
|
bundle: Burrow.flatpak
|
||||||
manifest-path: burrow-gtk/com.hackclub.burrow.devel.json
|
manifest-path: burrow-gtk/build-aux/com.hackclub.burrow.devel.json
|
||||||
cache-key: flatpak-builder-${{ github.sha }}
|
cache-key: flatpak-builder-${{ github.sha }}
|
||||||
|
|
|
||||||
2
burrow-gtk/.cargo/config.toml
Normal file
2
burrow-gtk/.cargo/config.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
[target.'cfg(unix)']
|
||||||
|
runner = "sh -c"
|
||||||
1259
burrow-gtk/Cargo.lock
generated
1259
burrow-gtk/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -6,7 +6,12 @@ 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
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
relm4 = { version = "0.6.2", features = ["libadwaita"] }
|
anyhow = "1.0"
|
||||||
relm4-components = "0.6.2"
|
relm4 = { features = ["libadwaita", "gnome_45"], git = "https://github.com/Relm4/Relm4" }
|
||||||
relm4-icons = { version = "0.6.0", features = ["plus"] }
|
|
||||||
burrow = { version = "*", path = "../burrow/" }
|
burrow = { version = "*", path = "../burrow/" }
|
||||||
|
tokio = { version = "1.35.0", features = ["time", "sync"] }
|
||||||
|
gettext-rs = { version = "0.7.0", features = ["gettext-system"] }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
|
glib-build-tools = "0.18.0"
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,12 @@
|
||||||
"name" : "burrow-gtk",
|
"name" : "burrow-gtk",
|
||||||
"builddir" : true,
|
"builddir" : true,
|
||||||
"subdir" : "burrow-gtk",
|
"subdir" : "burrow-gtk",
|
||||||
"buildsystem" : "simple",
|
"buildsystem" : "meson",
|
||||||
"build-commands": [
|
"config-opts": ["--buildtype=debug"],
|
||||||
"cargo build",
|
|
||||||
"install -Dm755 -t /app/bin target/debug/burrow-gtk"
|
|
||||||
],
|
|
||||||
"sources" : [
|
"sources" : [
|
||||||
{
|
{
|
||||||
"type": "dir",
|
"type": "dir",
|
||||||
"path": "../"
|
"path": "../../"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -40,15 +40,12 @@
|
||||||
"name" : "burrow-gtk",
|
"name" : "burrow-gtk",
|
||||||
"builddir" : true,
|
"builddir" : true,
|
||||||
"subdir" : "burrow-gtk",
|
"subdir" : "burrow-gtk",
|
||||||
"buildsystem" : "simple",
|
"buildsystem" : "meson",
|
||||||
"build-commands": [
|
"config-opts": ["--buildtype=release"],
|
||||||
"cargo build --release",
|
|
||||||
"install -Dm755 -t /app/bin target/release/burrow-gtk"
|
|
||||||
],
|
|
||||||
"sources" : [
|
"sources" : [
|
||||||
{
|
{
|
||||||
"type": "dir",
|
"type": "dir",
|
||||||
"path": "../"
|
"path": "../../"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
16
burrow-gtk/build.rs
Normal file
16
burrow-gtk/build.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
compile_gresources()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_gresources() -> Result<()> {
|
||||||
|
glib_build_tools::compile_resources(
|
||||||
|
&["data"],
|
||||||
|
"data/resources.gresource.xml",
|
||||||
|
"compiled.gresource",
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=Burrow
|
Name=@APP_NAME_CAPITALIZED@
|
||||||
Exec=burrow-gtk
|
Exec=@APP_NAME@
|
||||||
Icon=com.hackclub.burrow
|
Icon=@APP_ID@
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Categories=GTK;Network
|
Categories=GTK;Network
|
||||||
5
burrow-gtk/data/app.gschema.xml.in
Normal file
5
burrow-gtk/data/app.gschema.xml.in
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<schemalist gettext-domain="@APP_NAME@">
|
||||||
|
<schema id="@APP_ID" path="@APP_IDPATH@">
|
||||||
|
</schema>
|
||||||
|
</schemalist>
|
||||||
16
burrow-gtk/data/app.metainfo.xml.in
Normal file
16
burrow-gtk/data/app.metainfo.xml.in
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component type="desktop">
|
||||||
|
<id>@APP_ID@</id>
|
||||||
|
<metadata_license>CC0</metadata_license>
|
||||||
|
<project_license>GPL-3.0-or-later</project_license>
|
||||||
|
<name translatable="no">@APP_NAME_CAPITALIZED@</name>
|
||||||
|
<launchable type="desktop-id">@APP_ID@.desktop</launchable>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<p>No description</p>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<summary>
|
||||||
|
<p>No Summary</p>
|
||||||
|
</summary>
|
||||||
|
</component>
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<component type="desktop">
|
|
||||||
<id>com.hackclub.burrow.desktop</id>
|
|
||||||
<project_license>GPL-3.0-or-later</project_license>
|
|
||||||
<description>
|
|
||||||
<p>No description</p>
|
|
||||||
</description>
|
|
||||||
</component>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<schemalist gettext-domain="burrow-gtk">
|
|
||||||
<schema id="com.hackclub.burrow" path="/com/hackclub/burrow/">
|
|
||||||
</schema>
|
|
||||||
</schemalist>
|
|
||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2 KiB |
|
|
@ -1,13 +0,0 @@
|
||||||
application_id = 'com.hackclub.burrow'
|
|
||||||
|
|
||||||
scalable_dir = join_paths('hicolor', 'scalable', 'apps')
|
|
||||||
install_data(
|
|
||||||
join_paths(scalable_dir, ('@0@.svg').format(application_id)),
|
|
||||||
install_dir: join_paths(get_option('datadir'), 'icons', scalable_dir)
|
|
||||||
)
|
|
||||||
|
|
||||||
symbolic_dir = join_paths('hicolor', 'symbolic', 'apps')
|
|
||||||
install_data(
|
|
||||||
join_paths(symbolic_dir, ('@0@-symbolic.svg').format(application_id)),
|
|
||||||
install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir)
|
|
||||||
)
|
|
||||||
|
|
@ -1,39 +1,90 @@
|
||||||
|
# app.desktop.in.in
|
||||||
|
desktop_conf = configuration_data()
|
||||||
|
desktop_conf.set('APP_ID', app_id)
|
||||||
|
desktop_conf.set('APP_NAME', app_name)
|
||||||
|
desktop_conf.set('APP_NAME_CAPITALIZED', app_name_capitalized)
|
||||||
|
|
||||||
|
desktop_file_in = configure_file(
|
||||||
|
input: 'app.desktop.in.in',
|
||||||
|
output: '@BASENAME@',
|
||||||
|
configuration: desktop_conf,
|
||||||
|
)
|
||||||
|
|
||||||
desktop_file = i18n.merge_file(
|
desktop_file = i18n.merge_file(
|
||||||
input: 'com.hackclub.burrow.desktop.in',
|
input: desktop_file_in,
|
||||||
output: 'com.hackclub.burrow.desktop',
|
output: app_id + '.desktop',
|
||||||
type: 'desktop',
|
type: 'desktop',
|
||||||
po_dir: '../po',
|
po_dir: '../po',
|
||||||
install: true,
|
install: true,
|
||||||
install_dir: join_paths(get_option('datadir'), 'applications')
|
install_dir: datadir / 'applications',
|
||||||
)
|
)
|
||||||
|
|
||||||
desktop_utils = find_program('desktop-file-validate', required: false)
|
if desktop_file_validate.found()
|
||||||
if desktop_utils.found()
|
test(
|
||||||
test('Validate desktop file', desktop_utils, args: [desktop_file])
|
'validate-desktop',
|
||||||
|
desktop_file_validate,
|
||||||
|
args: [desktop_file],
|
||||||
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
appstream_file = i18n.merge_file(
|
# app.gschema.xml.in
|
||||||
input: 'com.hackclub.burrow.appdata.xml.in',
|
gschema_conf = configuration_data()
|
||||||
output: 'com.hackclub.burrow.appdata.xml',
|
gschema_conf.set('APP_ID', app_id)
|
||||||
|
gschema_conf.set('APP_NAME', app_name)
|
||||||
|
gschema_conf.set('APP_IDPATH', app_idpath)
|
||||||
|
gschema_file = configure_file(
|
||||||
|
input: 'app.gschema.xml.in',
|
||||||
|
output: app_id + '.gschema.xml',
|
||||||
|
configuration: gschema_conf,
|
||||||
|
install: true,
|
||||||
|
install_dir: datadir / 'glib-2.0' / 'schemas',
|
||||||
|
)
|
||||||
|
|
||||||
|
if glib_compile_schemas.found()
|
||||||
|
test(
|
||||||
|
'validate-gschema',
|
||||||
|
glib_compile_schemas,
|
||||||
|
args: [
|
||||||
|
'--dry-run',
|
||||||
|
datadir / 'glib-2.0' / 'schemas',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# app.metainfo.xml.in
|
||||||
|
appdata_conf = configuration_data()
|
||||||
|
appdata_conf.set('APP_ID', app_id)
|
||||||
|
appdata_conf.set('APP_NAME', app_name)
|
||||||
|
appdata_conf.set('APP_NAME_CAPITALIZED', app_name_capitalized)
|
||||||
|
appdata_file_in = configure_file(
|
||||||
|
input: 'app.metainfo.xml.in',
|
||||||
|
output: '@BASENAME@',
|
||||||
|
configuration: appdata_conf,
|
||||||
|
)
|
||||||
|
appdata_file = i18n.merge_file(
|
||||||
|
input: appdata_file_in,
|
||||||
|
output: app_id + '.metainfo.xml',
|
||||||
po_dir: '../po',
|
po_dir: '../po',
|
||||||
install: true,
|
install: true,
|
||||||
install_dir: join_paths(get_option('datadir'), 'appdata')
|
install_dir: datadir / 'metainfo',
|
||||||
)
|
)
|
||||||
|
|
||||||
appstream_util = find_program('appstream-util', required: false)
|
|
||||||
if appstream_util.found()
|
if appstream_util.found()
|
||||||
test('Validate appstream file', appstream_util, args: ['validate', appstream_file])
|
test(
|
||||||
|
'validate-appdata',
|
||||||
|
appstream_util,
|
||||||
|
args: ['validate', '--nonet', appdata_file],
|
||||||
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
install_data('com.hackclub.burrow.gschema.xml',
|
install_data(
|
||||||
install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas')
|
'icons/hicolor/scalable/apps/' + app_name + '.svg',
|
||||||
|
install_dir: datadir / 'icons' / 'hicolor' / 'scalable' / 'apps',
|
||||||
|
rename: app_id + '.svg',
|
||||||
)
|
)
|
||||||
|
|
||||||
compile_schemas = find_program('glib-compile-schemas', required: false)
|
install_data(
|
||||||
if compile_schemas.found()
|
'icons/hicolor/symbolic/apps/' + app_name + '-symbolic.svg',
|
||||||
test('Validate schema file',
|
install_dir: datadir / 'icons' / 'hicolor' / 'symbolic' / 'apps',
|
||||||
compile_schemas,
|
rename: app_id + '-symbolic.svg',
|
||||||
args: ['--strict', '--dry-run', meson.current_source_dir()])
|
)
|
||||||
endif
|
|
||||||
|
|
||||||
subdir('icons')
|
|
||||||
|
|
|
||||||
5
burrow-gtk/data/resources.gresource.xml
Normal file
5
burrow-gtk/data/resources.gresource.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/com/hackclub/burrow">
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
||||||
56
burrow-gtk/meson.build
Normal file
56
burrow-gtk/meson.build
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
project(
|
||||||
|
'burrow-gtk',
|
||||||
|
['rust'],
|
||||||
|
version: '0.0.1',
|
||||||
|
meson_version: '>= 1.0',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find Cargo
|
||||||
|
cargo_bin = find_program('cargo')
|
||||||
|
cargo_env = ['CARGO_HOME=' + meson.project_build_root()]
|
||||||
|
cargo_opt = ['--manifest-path', meson.project_source_root() / 'Cargo.toml']
|
||||||
|
cargo_opt += ['--target-dir', meson.project_build_root() / 'target']
|
||||||
|
|
||||||
|
# Config
|
||||||
|
prefix = get_option('prefix')
|
||||||
|
datadir = prefix / get_option('datadir')
|
||||||
|
localedir = prefix / get_option('localedir')
|
||||||
|
|
||||||
|
app_name = 'burrow-gtk'
|
||||||
|
app_name_capitalized = 'Burrow'
|
||||||
|
base_id = 'com.hackclub.burrow'
|
||||||
|
app_idpath = '/com/hackclub/' + app_name + '/'
|
||||||
|
if get_option('buildtype') == 'release'
|
||||||
|
cargo_opt += ['--release']
|
||||||
|
rust_target = 'release'
|
||||||
|
app_id = base_id
|
||||||
|
else
|
||||||
|
rust_target = 'debug'
|
||||||
|
app_id = base_id + '-' + 'devel'
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Imports
|
||||||
|
i18n = import('i18n')
|
||||||
|
gnome = import('gnome')
|
||||||
|
|
||||||
|
# External Dependencies
|
||||||
|
dependency('gtk4', version: '>= 4.12')
|
||||||
|
dependency('libadwaita-1', version: '>= 1.4')
|
||||||
|
|
||||||
|
glib_compile_resources = find_program('glib-compile-resources', required: true)
|
||||||
|
glib_compile_schemas = find_program('glib-compile-schemas', required: true)
|
||||||
|
desktop_file_validate = find_program('desktop-file-validate', required: false)
|
||||||
|
appstream_util = find_program('appstream-util', required: false)
|
||||||
|
fc_cache = find_program('fc-cache', required: false)
|
||||||
|
|
||||||
|
# Our Sources
|
||||||
|
subdir('po')
|
||||||
|
subdir('data')
|
||||||
|
subdir('src')
|
||||||
|
|
||||||
|
# Gnome Post Install
|
||||||
|
gnome.post_install(
|
||||||
|
glib_compile_schemas: true,
|
||||||
|
gtk_update_icon_cache: true,
|
||||||
|
update_desktop_database: true,
|
||||||
|
)
|
||||||
|
|
@ -1,4 +1 @@
|
||||||
data/com.hackclub.Burrow.desktop.in
|
data/app.desktop.in.in
|
||||||
data/com.hackclub.Burrow.appdata.xml.in
|
|
||||||
data/com.hackclub.Burrow.gschema.xml
|
|
||||||
src/window.ui
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
i18n.gettext('burrow-gtk', preset: 'glib')
|
i18n.gettext(app_name, preset: 'glib')
|
||||||
|
|
|
||||||
1
burrow-gtk/src/.gitignore
vendored
Normal file
1
burrow-gtk/src/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
config.rs
|
||||||
136
burrow-gtk/src/components/app.rs
Normal file
136
burrow-gtk/src/components/app.rs
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
use super::*;
|
||||||
|
use anyhow::Context;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
const RECONNECT_POLL_TIME: Duration = Duration::from_secs(5);
|
||||||
|
|
||||||
|
pub struct App {
|
||||||
|
daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
||||||
|
_settings_screen: Controller<settings_screen::SettingsScreen>,
|
||||||
|
switch_screen: AsyncController<switch_screen::SwitchScreen>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AppMsg {
|
||||||
|
None,
|
||||||
|
PostInit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
pub fn run() {
|
||||||
|
let app = RelmApp::new(config::ID);
|
||||||
|
Self::setup_gresources().unwrap();
|
||||||
|
Self::setup_i18n().unwrap();
|
||||||
|
|
||||||
|
app.run_async::<App>(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_i18n() -> Result<()> {
|
||||||
|
gettextrs::setlocale(gettextrs::LocaleCategory::LcAll, "");
|
||||||
|
gettextrs::bindtextdomain(config::GETTEXT_PACKAGE, config::LOCALEDIR)?;
|
||||||
|
gettextrs::bind_textdomain_codeset(config::GETTEXT_PACKAGE, "UTF-8")?;
|
||||||
|
gettextrs::textdomain(config::GETTEXT_PACKAGE)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_gresources() -> Result<()> {
|
||||||
|
gtk::gio::resources_register_include!("compiled.gresource")
|
||||||
|
.context("Failed to register and include compiled gresource.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::component(pub, async)]
|
||||||
|
impl AsyncComponent for App {
|
||||||
|
type Init = ();
|
||||||
|
type Input = AppMsg;
|
||||||
|
type Output = ();
|
||||||
|
type CommandOutput = ();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
adw::Window {
|
||||||
|
set_title: Some("Burrow"),
|
||||||
|
set_default_size: (640, 480),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn init(
|
||||||
|
_: Self::Init,
|
||||||
|
root: Self::Root,
|
||||||
|
sender: AsyncComponentSender<Self>,
|
||||||
|
) -> AsyncComponentParts<Self> {
|
||||||
|
let daemon_client = Arc::new(Mutex::new(DaemonClient::new().await.ok()));
|
||||||
|
|
||||||
|
let switch_screen = switch_screen::SwitchScreen::builder()
|
||||||
|
.launch(switch_screen::SwitchScreenInit {
|
||||||
|
daemon_client: Arc::clone(&daemon_client),
|
||||||
|
})
|
||||||
|
.forward(sender.input_sender(), |_| AppMsg::None);
|
||||||
|
|
||||||
|
let settings_screen = settings_screen::SettingsScreen::builder()
|
||||||
|
.launch(settings_screen::SettingsScreenInit {
|
||||||
|
daemon_client: Arc::clone(&daemon_client),
|
||||||
|
})
|
||||||
|
.forward(sender.input_sender(), |_| AppMsg::None);
|
||||||
|
|
||||||
|
let widgets = view_output!();
|
||||||
|
|
||||||
|
let view_stack = adw::ViewStack::new();
|
||||||
|
view_stack.add_titled(switch_screen.widget(), None, "Switch");
|
||||||
|
view_stack.add_titled(settings_screen.widget(), None, "Settings");
|
||||||
|
|
||||||
|
let view_switcher_bar = adw::ViewSwitcherBar::builder().stack(&view_stack).build();
|
||||||
|
view_switcher_bar.set_reveal(true);
|
||||||
|
|
||||||
|
let toolbar = adw::ToolbarView::new();
|
||||||
|
toolbar.add_top_bar(
|
||||||
|
&adw::HeaderBar::builder()
|
||||||
|
.title_widget(>k::Label::new(Some("Burrow")))
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
toolbar.add_bottom_bar(&view_switcher_bar);
|
||||||
|
toolbar.set_content(Some(&view_stack));
|
||||||
|
|
||||||
|
root.set_content(Some(&toolbar));
|
||||||
|
|
||||||
|
sender.input(AppMsg::PostInit);
|
||||||
|
|
||||||
|
let model = App {
|
||||||
|
daemon_client,
|
||||||
|
switch_screen,
|
||||||
|
_settings_screen: settings_screen,
|
||||||
|
};
|
||||||
|
|
||||||
|
AsyncComponentParts { model, widgets }
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update(
|
||||||
|
&mut self,
|
||||||
|
_msg: Self::Input,
|
||||||
|
_sender: AsyncComponentSender<Self>,
|
||||||
|
_root: &Self::Root,
|
||||||
|
) {
|
||||||
|
loop {
|
||||||
|
tokio::time::sleep(RECONNECT_POLL_TIME).await;
|
||||||
|
{
|
||||||
|
let mut daemon_client = self.daemon_client.lock().await;
|
||||||
|
let mut disconnected_daemon_client = false;
|
||||||
|
|
||||||
|
if let Some(daemon_client) = daemon_client.as_mut() {
|
||||||
|
if let Err(_e) = daemon_client.send_command(DaemonCommand::ServerInfo).await {
|
||||||
|
disconnected_daemon_client = true;
|
||||||
|
self.switch_screen
|
||||||
|
.emit(switch_screen::SwitchScreenMsg::DaemonDisconnect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if disconnected_daemon_client || daemon_client.is_none() {
|
||||||
|
*daemon_client = DaemonClient::new().await.ok();
|
||||||
|
if daemon_client.is_some() {
|
||||||
|
self.switch_screen
|
||||||
|
.emit(switch_screen::SwitchScreenMsg::DaemonReconnect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
burrow-gtk/src/components/mod.rs
Normal file
20
burrow-gtk/src/components/mod.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use super::*;
|
||||||
|
use adw::prelude::*;
|
||||||
|
use burrow::{DaemonClient, DaemonCommand, DaemonResponseData};
|
||||||
|
use gtk::Align;
|
||||||
|
use relm4::{
|
||||||
|
component::{
|
||||||
|
AsyncComponent, AsyncComponentController, AsyncComponentParts, AsyncComponentSender,
|
||||||
|
AsyncController,
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
mod app;
|
||||||
|
mod settings;
|
||||||
|
mod settings_screen;
|
||||||
|
mod switch_screen;
|
||||||
|
|
||||||
|
pub use app::*;
|
||||||
126
burrow-gtk/src/components/settings/diag_group.rs
Normal file
126
burrow-gtk/src/components/settings/diag_group.rs
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
use super::*;
|
||||||
|
use diag::{StatusTernary, SystemSetup};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DiagGroup {
|
||||||
|
daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
||||||
|
|
||||||
|
init_system: SystemSetup,
|
||||||
|
service_installed: StatusTernary,
|
||||||
|
socket_installed: StatusTernary,
|
||||||
|
socket_enabled: StatusTernary,
|
||||||
|
daemon_running: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DiagGroupInit {
|
||||||
|
pub daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagGroup {
|
||||||
|
async fn new(daemon_client: Arc<Mutex<Option<DaemonClient>>>) -> Result<Self> {
|
||||||
|
let setup = SystemSetup::new();
|
||||||
|
let daemon_running = daemon_client.lock().await.is_some();
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
service_installed: setup.is_service_installed()?,
|
||||||
|
socket_installed: setup.is_socket_installed()?,
|
||||||
|
socket_enabled: setup.is_socket_enabled()?,
|
||||||
|
daemon_running,
|
||||||
|
init_system: setup,
|
||||||
|
daemon_client,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DiagGroupMsg {
|
||||||
|
Refresh,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::component(pub, async)]
|
||||||
|
impl AsyncComponent for DiagGroup {
|
||||||
|
type Init = DiagGroupInit;
|
||||||
|
type Input = DiagGroupMsg;
|
||||||
|
type Output = ();
|
||||||
|
type CommandOutput = ();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
#[name(group)]
|
||||||
|
adw::PreferencesGroup {
|
||||||
|
set_title: "Diagnose",
|
||||||
|
set_description: Some("Diagnose Burrow"),
|
||||||
|
|
||||||
|
adw::ActionRow {
|
||||||
|
#[watch]
|
||||||
|
set_title: &format!("Init System: {}", model.init_system)
|
||||||
|
},
|
||||||
|
adw::ActionRow {
|
||||||
|
#[watch]
|
||||||
|
set_title: &format!(
|
||||||
|
"Service installed: {}",
|
||||||
|
status_ternary_to_str(model.service_installed)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
adw::ActionRow {
|
||||||
|
#[watch]
|
||||||
|
set_title: &format!(
|
||||||
|
"Socket installed: {}",
|
||||||
|
status_ternary_to_str(model.socket_installed)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
adw::ActionRow {
|
||||||
|
#[watch]
|
||||||
|
set_title: &format!(
|
||||||
|
"Socket enabled: {}",
|
||||||
|
status_ternary_to_str(model.socket_enabled)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
adw::ActionRow {
|
||||||
|
#[watch]
|
||||||
|
set_title: &format!(
|
||||||
|
"Daemon running: {}",
|
||||||
|
if model.daemon_running { "Yes" } else { "No" }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
gtk::Button {
|
||||||
|
set_label: "Refresh",
|
||||||
|
connect_clicked => DiagGroupMsg::Refresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn init(
|
||||||
|
init: Self::Init,
|
||||||
|
root: Self::Root,
|
||||||
|
sender: AsyncComponentSender<Self>,
|
||||||
|
) -> AsyncComponentParts<Self> {
|
||||||
|
// Should be impossible to panic here
|
||||||
|
let model = DiagGroup::new(init.daemon_client).await.unwrap();
|
||||||
|
|
||||||
|
let widgets = view_output!();
|
||||||
|
|
||||||
|
AsyncComponentParts { model, widgets }
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update(
|
||||||
|
&mut self,
|
||||||
|
msg: Self::Input,
|
||||||
|
_sender: AsyncComponentSender<Self>,
|
||||||
|
_root: &Self::Root,
|
||||||
|
) {
|
||||||
|
match msg {
|
||||||
|
DiagGroupMsg::Refresh => {
|
||||||
|
// Should be impossible to panic here
|
||||||
|
*self = Self::new(Arc::clone(&self.daemon_client)).await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status_ternary_to_str(status: StatusTernary) -> &'static str {
|
||||||
|
match status {
|
||||||
|
StatusTernary::True => "Yes",
|
||||||
|
StatusTernary::False => "No",
|
||||||
|
StatusTernary::NA => "N/A",
|
||||||
|
}
|
||||||
|
}
|
||||||
5
burrow-gtk/src/components/settings/mod.rs
Normal file
5
burrow-gtk/src/components/settings/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
mod diag_group;
|
||||||
|
|
||||||
|
pub use diag_group::{DiagGroup, DiagGroupInit};
|
||||||
44
burrow-gtk/src/components/settings_screen.rs
Normal file
44
burrow-gtk/src/components/settings_screen.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct SettingsScreen {
|
||||||
|
_diag_group: AsyncController<settings::DiagGroup>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SettingsScreenInit {
|
||||||
|
pub daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::component(pub)]
|
||||||
|
impl SimpleComponent for SettingsScreen {
|
||||||
|
type Init = SettingsScreenInit;
|
||||||
|
type Input = ();
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
#[name(preferences)]
|
||||||
|
adw::PreferencesPage {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(
|
||||||
|
init: Self::Init,
|
||||||
|
root: Self::Root,
|
||||||
|
sender: ComponentSender<Self>,
|
||||||
|
) -> ComponentParts<Self> {
|
||||||
|
let diag_group = settings::DiagGroup::builder()
|
||||||
|
.launch(settings::DiagGroupInit {
|
||||||
|
daemon_client: Arc::clone(&init.daemon_client),
|
||||||
|
})
|
||||||
|
.forward(sender.input_sender(), |_| ());
|
||||||
|
|
||||||
|
let widgets = view_output!();
|
||||||
|
widgets.preferences.add(diag_group.widget());
|
||||||
|
|
||||||
|
let model = SettingsScreen {
|
||||||
|
_diag_group: diag_group,
|
||||||
|
};
|
||||||
|
|
||||||
|
ComponentParts { model, widgets }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, _: Self::Input, _sender: ComponentSender<Self>) {}
|
||||||
|
}
|
||||||
158
burrow-gtk/src/components/switch_screen.rs
Normal file
158
burrow-gtk/src/components/switch_screen.rs
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct SwitchScreen {
|
||||||
|
daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
||||||
|
switch: gtk::Switch,
|
||||||
|
switch_screen: gtk::Box,
|
||||||
|
disconnected_banner: adw::Banner,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SwitchScreenInit {
|
||||||
|
pub daemon_client: Arc<Mutex<Option<DaemonClient>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum SwitchScreenMsg {
|
||||||
|
DaemonReconnect,
|
||||||
|
DaemonDisconnect,
|
||||||
|
Start,
|
||||||
|
Stop,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::component(pub, async)]
|
||||||
|
impl AsyncComponent for SwitchScreen {
|
||||||
|
type Init = SwitchScreenInit;
|
||||||
|
type Input = SwitchScreenMsg;
|
||||||
|
type Output = ();
|
||||||
|
type CommandOutput = ();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
gtk::Box {
|
||||||
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_valign: Align::BaselineFill,
|
||||||
|
|
||||||
|
gtk::Box {
|
||||||
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_spacing: 5,
|
||||||
|
set_margin_all: 5,
|
||||||
|
set_valign: Align::Start,
|
||||||
|
|
||||||
|
#[name(setup_banner)]
|
||||||
|
adw::Banner {
|
||||||
|
set_title: "Burrow is not running!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
#[name(switch_screen)]
|
||||||
|
gtk::Box {
|
||||||
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_spacing: 10,
|
||||||
|
set_margin_all: 5,
|
||||||
|
set_valign: Align::Center,
|
||||||
|
set_vexpand: true,
|
||||||
|
|
||||||
|
gtk::Label {
|
||||||
|
set_label: "Burrow Switch",
|
||||||
|
},
|
||||||
|
|
||||||
|
#[name(switch)]
|
||||||
|
gtk::Switch {
|
||||||
|
set_halign: Align::Center,
|
||||||
|
set_hexpand: false,
|
||||||
|
set_vexpand: false,
|
||||||
|
connect_active_notify => move |switch|
|
||||||
|
sender.input(if switch.is_active() { SwitchScreenMsg::Start } else { SwitchScreenMsg::Stop })
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn init(
|
||||||
|
init: Self::Init,
|
||||||
|
root: Self::Root,
|
||||||
|
sender: AsyncComponentSender<Self>,
|
||||||
|
) -> AsyncComponentParts<Self> {
|
||||||
|
let mut initial_switch_status = false;
|
||||||
|
let mut initial_daemon_server_down = false;
|
||||||
|
|
||||||
|
if let Some(daemon_client) = init.daemon_client.lock().await.as_mut() {
|
||||||
|
if let Ok(res) = daemon_client
|
||||||
|
.send_command(DaemonCommand::ServerInfo)
|
||||||
|
.await
|
||||||
|
.as_ref()
|
||||||
|
{
|
||||||
|
initial_switch_status = match res.result.as_ref() {
|
||||||
|
Ok(DaemonResponseData::None) => false,
|
||||||
|
Ok(DaemonResponseData::ServerInfo(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
initial_daemon_server_down = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
initial_daemon_server_down = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let widgets = view_output!();
|
||||||
|
|
||||||
|
widgets.switch.set_active(initial_switch_status);
|
||||||
|
|
||||||
|
if initial_daemon_server_down {
|
||||||
|
*init.daemon_client.lock().await = None;
|
||||||
|
widgets.switch.set_active(false);
|
||||||
|
widgets.switch_screen.set_sensitive(false);
|
||||||
|
widgets.setup_banner.set_revealed(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
let model = SwitchScreen {
|
||||||
|
daemon_client: init.daemon_client,
|
||||||
|
switch: widgets.switch.clone(),
|
||||||
|
switch_screen: widgets.switch_screen.clone(),
|
||||||
|
disconnected_banner: widgets.setup_banner.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
AsyncComponentParts { model, widgets }
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update(
|
||||||
|
&mut self,
|
||||||
|
msg: Self::Input,
|
||||||
|
_: AsyncComponentSender<Self>,
|
||||||
|
_root: &Self::Root,
|
||||||
|
) {
|
||||||
|
let mut disconnected_daemon_client = false;
|
||||||
|
|
||||||
|
if let Some(daemon_client) = self.daemon_client.lock().await.as_mut() {
|
||||||
|
match msg {
|
||||||
|
Self::Input::Start => {
|
||||||
|
if let Err(_e) = daemon_client
|
||||||
|
.send_command(DaemonCommand::Start(Default::default()))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
disconnected_daemon_client = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::Input::Stop => {
|
||||||
|
if let Err(_e) = daemon_client.send_command(DaemonCommand::Stop).await {
|
||||||
|
disconnected_daemon_client = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
disconnected_daemon_client = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg == Self::Input::DaemonReconnect {
|
||||||
|
self.disconnected_banner.set_revealed(false);
|
||||||
|
self.switch_screen.set_sensitive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if disconnected_daemon_client || msg == Self::Input::DaemonDisconnect {
|
||||||
|
*self.daemon_client.lock().await = None;
|
||||||
|
self.switch.set_active(false);
|
||||||
|
self.switch_screen.set_sensitive(false);
|
||||||
|
self.disconnected_banner.set_revealed(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
burrow-gtk/src/config.rs.in
Normal file
8
burrow-gtk/src/config.rs.in
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#[allow(unused)]
|
||||||
|
pub const ID: &str = @ID@;
|
||||||
|
#[allow(unused)]
|
||||||
|
pub const VERSION: &str = @VERSION@;
|
||||||
|
#[allow(unused)]
|
||||||
|
pub const LOCALEDIR: &str = @LOCALEDIR@;
|
||||||
|
#[allow(unused)]
|
||||||
|
pub const GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@;
|
||||||
80
burrow-gtk/src/diag.rs
Normal file
80
burrow-gtk/src/diag.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
use super::*;
|
||||||
|
use std::{fmt::Display, fs, process::Command};
|
||||||
|
|
||||||
|
const SYSTEMD_SOCKET_LOC: &str = "/etc/systemd/system/burrow.socket";
|
||||||
|
const SYSTEMD_SERVICE_LOC: &str = "/etc/systemd/system/burrow.service";
|
||||||
|
|
||||||
|
// I don't like this type very much.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum StatusTernary {
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
NA,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realistically, we may not explicitly "support" non-systemd platforms which would simply this
|
||||||
|
// code greatly.
|
||||||
|
// Along with replacing [`StatusTernary`] with good old [`bool`].
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum SystemSetup {
|
||||||
|
Systemd,
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemSetup {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
if Command::new("systemctl").arg("--version").output().is_ok() {
|
||||||
|
SystemSetup::Systemd
|
||||||
|
} else {
|
||||||
|
SystemSetup::Other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_service_installed(&self) -> Result<StatusTernary> {
|
||||||
|
match self {
|
||||||
|
SystemSetup::Systemd => Ok(fs::metadata(SYSTEMD_SERVICE_LOC).is_ok().into()),
|
||||||
|
SystemSetup::Other => Ok(StatusTernary::NA),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_socket_installed(&self) -> Result<StatusTernary> {
|
||||||
|
match self {
|
||||||
|
SystemSetup::Systemd => Ok(fs::metadata(SYSTEMD_SOCKET_LOC).is_ok().into()),
|
||||||
|
SystemSetup::Other => Ok(StatusTernary::NA),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_socket_enabled(&self) -> Result<StatusTernary> {
|
||||||
|
match self {
|
||||||
|
SystemSetup::Systemd => {
|
||||||
|
let output = Command::new("systemctl")
|
||||||
|
.arg("is-enabled")
|
||||||
|
.arg("burrow.socket")
|
||||||
|
.output()?
|
||||||
|
.stdout;
|
||||||
|
let output = String::from_utf8(output)?;
|
||||||
|
Ok((output == "enabled\n").into())
|
||||||
|
}
|
||||||
|
SystemSetup::Other => Ok(StatusTernary::NA),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for StatusTernary {
|
||||||
|
fn from(value: bool) -> Self {
|
||||||
|
if value {
|
||||||
|
StatusTernary::True
|
||||||
|
} else {
|
||||||
|
StatusTernary::False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SystemSetup {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
SystemSetup::Systemd => "Systemd",
|
||||||
|
SystemSetup::Other => "Other",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,87 +1,11 @@
|
||||||
use adw::prelude::*;
|
use anyhow::Result;
|
||||||
use burrow::{DaemonClient, DaemonCommand, DaemonStartOptions};
|
|
||||||
use gtk::Align;
|
|
||||||
use relm4::{
|
|
||||||
component::{AsyncComponent, AsyncComponentParts, AsyncComponentSender},
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct App {}
|
pub mod components;
|
||||||
|
mod diag;
|
||||||
|
|
||||||
#[derive(Debug)]
|
// Generated using meson
|
||||||
enum Msg {
|
mod config;
|
||||||
Start,
|
|
||||||
Stop,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[relm4::component(async)]
|
|
||||||
impl AsyncComponent for App {
|
|
||||||
type Init = ();
|
|
||||||
type Input = Msg;
|
|
||||||
type Output = ();
|
|
||||||
type CommandOutput = ();
|
|
||||||
|
|
||||||
view! {
|
|
||||||
adw::Window {
|
|
||||||
set_title: Some("Simple app"),
|
|
||||||
set_default_size: (640, 480),
|
|
||||||
|
|
||||||
gtk::Box {
|
|
||||||
set_orientation: gtk::Orientation::Vertical,
|
|
||||||
set_spacing: 5,
|
|
||||||
set_margin_all: 5,
|
|
||||||
set_valign: Align::Center,
|
|
||||||
|
|
||||||
gtk::Label {
|
|
||||||
set_label: "Burrow GTK Switch",
|
|
||||||
},
|
|
||||||
|
|
||||||
gtk::Switch {
|
|
||||||
set_halign: Align::Center,
|
|
||||||
set_hexpand: false,
|
|
||||||
set_vexpand: false,
|
|
||||||
connect_active_notify => move |switch|
|
|
||||||
sender.input(if switch.is_active() { Msg::Start } else { Msg::Stop })
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn init(
|
|
||||||
_: Self::Init,
|
|
||||||
root: Self::Root,
|
|
||||||
sender: AsyncComponentSender<Self>,
|
|
||||||
) -> AsyncComponentParts<Self> {
|
|
||||||
let model = App {};
|
|
||||||
|
|
||||||
let widgets = view_output!();
|
|
||||||
|
|
||||||
AsyncComponentParts { model, widgets }
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update(
|
|
||||||
&mut self,
|
|
||||||
msg: Self::Input,
|
|
||||||
_sender: AsyncComponentSender<Self>,
|
|
||||||
_root: &Self::Root,
|
|
||||||
) {
|
|
||||||
match msg {
|
|
||||||
Msg::Start => {
|
|
||||||
let mut client = DaemonClient::new().await.unwrap();
|
|
||||||
client
|
|
||||||
.send_command(DaemonCommand::Start(DaemonStartOptions::default()))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
Msg::Stop => {
|
|
||||||
let mut client = DaemonClient::new().await.unwrap();
|
|
||||||
client.send_command(DaemonCommand::Stop).await.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = RelmApp::new("com.hackclub.burrow");
|
components::App::run();
|
||||||
app.run_async::<App>(());
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
burrow-gtk/src/meson.build
Normal file
34
burrow-gtk/src/meson.build
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# config.rs.in
|
||||||
|
global_conf = configuration_data()
|
||||||
|
global_conf.set_quoted('ID', app_id)
|
||||||
|
global_conf.set_quoted('VERSION', meson.project_version())
|
||||||
|
global_conf.set_quoted('LOCALEDIR', localedir)
|
||||||
|
global_conf.set_quoted('GETTEXT_PACKAGE', app_name)
|
||||||
|
config = configure_file(
|
||||||
|
input: 'config.rs.in',
|
||||||
|
output: 'config.rs',
|
||||||
|
configuration: global_conf,
|
||||||
|
)
|
||||||
|
|
||||||
|
run_command(
|
||||||
|
'cp',
|
||||||
|
meson.project_build_root() / 'src' / 'config.rs',
|
||||||
|
meson.project_source_root() / 'src',
|
||||||
|
check: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cargo Build
|
||||||
|
cargo_build = custom_target(
|
||||||
|
'cargo-build',
|
||||||
|
build_by_default: true,
|
||||||
|
build_always_stale: true,
|
||||||
|
output: meson.project_name(),
|
||||||
|
console: true,
|
||||||
|
install: true,
|
||||||
|
install_dir: get_option('bindir'),
|
||||||
|
command: [
|
||||||
|
'env', cargo_env,
|
||||||
|
cargo_bin, 'build',
|
||||||
|
cargo_opt, '&&', 'cp', 'target' / rust_target / meson.project_name(), '@OUTPUT@',
|
||||||
|
]
|
||||||
|
)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue