dev-2025-08-17T21:06:39+02:00
This commit is contained in:
parent
2fefc6ec65
commit
c9b07c92dc
12
src/components.rs
Normal file
12
src/components.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use adw::gdk::pango;
|
||||||
|
use gtk::ListBoxRow;
|
||||||
|
|
||||||
|
pub(crate) fn new_device(name: String) -> ListBoxRow {
|
||||||
|
let device_label = gtk::Label::builder()
|
||||||
|
.ellipsize(pango::EllipsizeMode::End)
|
||||||
|
.xalign(0.0)
|
||||||
|
.label(&name)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ListBoxRow::builder().child(&device_label).build()
|
||||||
|
}
|
@ -22,6 +22,7 @@
|
|||||||
mod application;
|
mod application;
|
||||||
mod config;
|
mod config;
|
||||||
mod window;
|
mod window;
|
||||||
|
mod components;
|
||||||
|
|
||||||
use self::application::AudioDeviceManagerApplication;
|
use self::application::AudioDeviceManagerApplication;
|
||||||
use self::window::AudioDeviceManagerWindow;
|
use self::window::AudioDeviceManagerWindow;
|
||||||
|
@ -6,15 +6,24 @@ template $AudioDeviceManagerWindow: Adw.ApplicationWindow {
|
|||||||
default-width: 800;
|
default-width: 800;
|
||||||
default-height: 600;
|
default-height: 600;
|
||||||
|
|
||||||
content: Adw.NavigationSplitView {
|
Adw.Breakpoint {
|
||||||
|
condition ("max-width: 500sp")
|
||||||
|
setters {
|
||||||
|
split_view.collapsed: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content: Adw.NavigationSplitView split_view {
|
||||||
|
min-sidebar-width: 200;
|
||||||
|
|
||||||
sidebar: Adw.NavigationPage {
|
sidebar: Adw.NavigationPage {
|
||||||
title: _("Sidebar");
|
title: _("Devices");
|
||||||
tag: "sidebar";
|
tag: "devices";
|
||||||
|
|
||||||
child: Adw.ToolbarView {
|
child: Adw.ToolbarView {
|
||||||
[top]
|
[top]
|
||||||
Adw.HeaderBar {
|
Adw.HeaderBar {
|
||||||
show-title: false;
|
show-title: true;
|
||||||
[start]
|
[start]
|
||||||
Gtk.ToggleButton {
|
Gtk.ToggleButton {
|
||||||
icon-name: "list-add-symbolic";
|
icon-name: "list-add-symbolic";
|
||||||
@ -33,14 +42,14 @@ template $AudioDeviceManagerWindow: Adw.ApplicationWindow {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
content: Adw.NavigationPage {
|
content: Adw.NavigationPage device_navigation_page {
|
||||||
title: _("Content");
|
title: _("");
|
||||||
tag: "content";
|
tag: "device navigation page";
|
||||||
|
|
||||||
child: Adw.ToolbarView {
|
child: Adw.ToolbarView {
|
||||||
[top]
|
[top]
|
||||||
Adw.HeaderBar {
|
Adw.HeaderBar {
|
||||||
show-title: false;
|
show-title: true;
|
||||||
[end]
|
[end]
|
||||||
MenuButton {
|
MenuButton {
|
||||||
primary: true;
|
primary: true;
|
||||||
@ -50,13 +59,15 @@ template $AudioDeviceManagerWindow: Adw.ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
content: Adw.StatusPage {
|
content: Gtk.ScrolledWindow {
|
||||||
title: _("Content");
|
child: Adw.Clamp device_page_clamp {
|
||||||
|
maximum-size: 640;
|
||||||
|
|
||||||
LinkButton {
|
Box {
|
||||||
label: _("API Reference");
|
orientation: vertical;
|
||||||
uri: "https://ada-baumann.de";
|
spacing: 24;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
121
src/window.rs
121
src/window.rs
@ -18,10 +18,13 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
|
use adw::glib::{clone, closure_local};
|
||||||
|
use adw::prelude::{AlertDialogExt, AlertDialogExtManual, NavigationPageExt};
|
||||||
|
use adw::ResponseAppearance;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use gtk::{gio, glib};
|
use gtk::{gio, glib, Button, ListBoxRow};
|
||||||
|
use crate::components::new_device;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -32,6 +35,10 @@ mod imp {
|
|||||||
// Template widgets
|
// Template widgets
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub devices_list: TemplateChild<gtk::ListBox>,
|
pub devices_list: TemplateChild<gtk::ListBox>,
|
||||||
|
#[template_child]
|
||||||
|
pub device_page_clamp: TemplateChild<adw::Clamp>,
|
||||||
|
#[template_child]
|
||||||
|
pub device_navigation_page: TemplateChild<adw::NavigationPage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
@ -48,7 +55,7 @@ mod imp {
|
|||||||
"win.new-device",
|
"win.new-device",
|
||||||
None,
|
None,
|
||||||
|window, _, _| async move {
|
|window, _, _| async move {
|
||||||
println!("New Device");
|
window.new_device().await;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -67,13 +74,115 @@ mod imp {
|
|||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct AudioDeviceManagerWindow(ObjectSubclass<imp::AudioDeviceManagerWindow>)
|
pub struct AudioDeviceManagerWindow(ObjectSubclass<imp::AudioDeviceManagerWindow>)
|
||||||
@extends gtk::Widget, gtk::Window, gtk::ApplicationWindow, adw::ApplicationWindow, @implements gio::ActionGroup, gio::ActionMap;
|
@extends gtk::Widget, gtk::Window, gtk::ApplicationWindow, adw::ApplicationWindow,
|
||||||
|
@implements gio::ActionGroup, gio::ActionMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AudioDeviceManagerWindow {
|
impl AudioDeviceManagerWindow {
|
||||||
pub fn new<P: IsA<gtk::Application>>(application: &P) -> Self {
|
pub fn new<P: IsA<gtk::Application>>(application: &P) -> Self {
|
||||||
glib::Object::builder()
|
let instance: AudioDeviceManagerWindow = glib::Object::builder()
|
||||||
.property("application", application)
|
.property("application", application)
|
||||||
.build()
|
.build();
|
||||||
|
|
||||||
|
instance.bind_signals();
|
||||||
|
|
||||||
|
instance
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_signals(&self) {
|
||||||
|
self.imp().devices_list.connect_row_activated(clone!(
|
||||||
|
#[weak(rename_to = window)]
|
||||||
|
self,
|
||||||
|
move |_, row| {
|
||||||
|
println!("Row selected {}, {:?}", row.index(), row);
|
||||||
|
let label: gtk::Label = row
|
||||||
|
.child()
|
||||||
|
.and_downcast()
|
||||||
|
.expect("No Label in Row");
|
||||||
|
window.select_device(label.text().to_string());
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn new_device(&self) {
|
||||||
|
let entry = gtk::Entry::builder()
|
||||||
|
.placeholder_text("Name")
|
||||||
|
.activates_default(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let cancel_response = "cancel";
|
||||||
|
let create_response = "create";
|
||||||
|
|
||||||
|
// Create new dialog
|
||||||
|
let dialog = adw::AlertDialog::builder()
|
||||||
|
.heading("New Device")
|
||||||
|
.close_response(cancel_response)
|
||||||
|
.default_response(create_response)
|
||||||
|
.extra_child(&entry)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
dialog.add_responses(&[(cancel_response, "Cancel"), (create_response, "Create")]);
|
||||||
|
|
||||||
|
// Make the dialog button insensitive initially
|
||||||
|
dialog.set_response_enabled(create_response, false);
|
||||||
|
dialog.set_response_appearance(create_response, ResponseAppearance::Suggested);
|
||||||
|
|
||||||
|
// Set entry's css class to "error", when there is no text in it
|
||||||
|
entry.connect_changed(clone!(
|
||||||
|
#[weak]
|
||||||
|
dialog,
|
||||||
|
move |entry| {
|
||||||
|
let text = entry.text();
|
||||||
|
let empty = text.is_empty();
|
||||||
|
|
||||||
|
dialog.set_response_enabled(create_response, !empty);
|
||||||
|
|
||||||
|
if empty {
|
||||||
|
entry.add_css_class("error");
|
||||||
|
} else {
|
||||||
|
entry.remove_css_class("error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
let response = dialog.choose_future(self).await;
|
||||||
|
|
||||||
|
// Return if the user chose 'cancel_response'
|
||||||
|
|
||||||
|
if response == cancel_response {
|
||||||
|
println!("Cancel");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let device = new_device(entry.text().to_string());
|
||||||
|
|
||||||
|
self.imp().devices_list.append(&device);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_device(&self, name: String) {
|
||||||
|
self.imp().device_navigation_page.set_title(&name);
|
||||||
|
|
||||||
|
let device_page = self.build_device_page(name);
|
||||||
|
|
||||||
|
self.imp().device_page_clamp.set_child(Some(&device_page));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_device_page(&self, name: String) -> gtk::Box {
|
||||||
|
let device_page = gtk::Box::builder()
|
||||||
|
.orientation(gtk::Orientation::Vertical)
|
||||||
|
.margin_start(12)
|
||||||
|
.margin_end(12)
|
||||||
|
.spacing(12)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let entry = gtk::Entry::builder()
|
||||||
|
.placeholder_text("Test")
|
||||||
|
.secondary_icon_name("list-add-symbolic")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
device_page.append(&entry);
|
||||||
|
|
||||||
|
device_page
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user