azalea_shell/window/taskbar/widget/network/
mod.rs1use azalea_service::{LocalListenerHandle, StaticServiceManager};
2use gtk::prelude::*;
3use relm4::{
4 Component, ComponentParts, ComponentSender, RelmWidgetExt, component, prelude::FactoryVecDeque,
5};
6
7use crate::{
8 factory, icon,
9 service::dbus::network_manager::{
10 self,
11 proxy::{NMConnectivityState, NMState},
12 },
13};
14
15crate::init! {
16 Model {
17 enabled: bool,
18 state_connectivity: (NMState, NMConnectivityState),
19 _nm_handle: LocalListenerHandle,
20 devices_menu: FactoryVecDeque<factory::network::device::Model>,
21 connections_menu: FactoryVecDeque<factory::network::connection::Model>,
22 }
23
24 Config {}
25}
26
27#[derive(Debug)]
28pub enum Input {
29 Enable(bool),
30 NetworkManager(network_manager::Output),
31}
32
33#[component(pub)]
34impl Component for Model {
35 type Init = Init;
36 type Input = Input;
37 type Output = ();
38 type CommandOutput = ();
39
40 view! {
41 gtk::MenuButton {
42 set_hexpand: false,
43 set_vexpand: false,
44 set_valign: gtk::Align::Center,
45
46 #[watch]
47 set_icon_name: match model.state_connectivity {
48 (NMState::NMStateUnknown , _) => icon::WIFI_QUESTION_MARK,
49 (NMState::NMStateAsleep , _)=> icon::WIFI_SLEEP,
50 (NMState::NMStateDisconnected , _)=> icon::WIFI_X,
51 (NMState::NMStateDisconnecting , _)=> icon::WIFI_DOTS,
52 (NMState::NMStateConnecting , _)=> icon::WIFI_DOTS,
53 (NMState::NMStateConnectedLocal , _)=> icon::WIFI_NONE,
54 (NMState::NMStateConnectedSite , _)=> icon::WIFI_NONE,
55 (NMState::NMStateConnectedGlobal, NMConnectivityState::NMConnectivityFull)=> icon::WIFI_3,
56 (NMState::NMStateConnectedGlobal, NMConnectivityState::NMConnectivityLimited)=> icon::WIFI_2,
57 (NMState::NMStateConnectedGlobal, _)=> icon::WIFI_0,
58 },
59
60 #[wrap(Some)]
61 set_popover = >k::Popover {
62 set_position: gtk::PositionType::Right,
63
64 gtk::Box {
65 set_spacing: 12,
66 set_orientation: gtk::Orientation::Vertical,
67
68 gtk::Box {
69 set_spacing: 12,
70
71 gtk::Label::new(Some("Network")) {
72 inline_css: r#"
73 font-weight: bold;
74 "#,
75
76 #[watch]
77 set_css_classes: if model.enabled {
78 &[ "azalea-primary-fg" ]
79 } else {
80 &[]
81 },
82 set_halign: gtk::Align::Start,
83 set_hexpand: true,
84 },
85
86 gtk::Switch {
87 set_halign: gtk::Align::End,
88
89 #[watch]
90 #[block_signal(toggle_state)]
91 set_active: model.enabled,
92
93 connect_state_set[sender] => move |_, on| {
94 sender.input(Input::Enable(on));
95 false.into()
96 } @toggle_state,
97 },
98 },
99
100 gtk::Separator {},
116
117 gtk::Label::new(Some("Connections")) {
118 set_css_classes: &[ "azalea-primary-fg" ],
119 set_halign: gtk::Align::Start,
120 set_hexpand: true,
121 },
122
123 #[local_ref]
124 connections_widget -> gtk::Box {
125 set_orientation: gtk::Orientation::Vertical,
126 set_spacing: 5,
127 }
128 },
129 },
130 },
131 }
132
133 fn init(
134 _init: Self::Init,
135 _root: Self::Root,
136 sender: ComponentSender<Self>,
137 ) -> ComponentParts<Self> {
138 let model = Model {
139 enabled: true,
140 state_connectivity: Default::default(),
141 _nm_handle: network_manager::Service::forward_local(
142 sender.input_sender().clone(),
143 Input::NetworkManager,
144 ),
145 devices_menu: FactoryVecDeque::builder()
146 .launch(gtk::Box::default())
147 .detach(),
148 connections_menu: FactoryVecDeque::builder()
149 .launch(gtk::Box::default())
150 .detach(),
151 };
152
153 network_manager::Service::send(network_manager::Input::Update);
154
155 let connections_widget = model.connections_menu.widget();
156 let widgets = view_output!();
157
158 ComponentParts { model, widgets }
159 }
160
161 fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>, _root: &Self::Root) {
162 use network_manager::Output;
163 match message {
164 Input::NetworkManager(nm_msg) => match nm_msg {
165 Output::NetworkingEnabledChanged(on) => self.enabled = on,
166 Output::StateChanged(nmstate) => self.state_connectivity.0 = nmstate,
167 Output::ConnectivityChanged(nmconnectivity_state) => {
168 self.state_connectivity.1 = nmconnectivity_state
169 }
170 Output::Devices(devices) => {
171 let mut guard = self.devices_menu.guard();
172
173 guard.clear();
174
175 for device in devices {
176 guard.push_back(device);
177 }
178 }
179 Output::Connections(connections) => {
180 let mut guard = self.connections_menu.guard();
181
182 guard.clear();
183
184 for connection in connections {
185 guard.push_back(connection);
186 }
187 }
188 },
189 Input::Enable(on) => {
190 network_manager::Service::send(network_manager::Input::Enable(on));
191 }
192 }
193 }
194
195 fn update_cmd(
196 &mut self,
197 _message: Self::CommandOutput,
198 _sender: ComponentSender<Self>,
199 _root: &Self::Root,
200 ) {
201 }
202}