99public class Bluetooth.MainView : Switchboard .SettingsPage {
1010 public signal void quit_plug ();
1111
12+ private Gtk . SortListModel nearby_model;
13+ private Gtk . SortListModel paired_model;
1214 private GLib . ListStore device_model;
13- private Granite . OverlayBar overlaybar ;
15+ private Gtk . Spinner discovery_spinner ;
1416 private Services . ObjectManager manager;
1517
1618 public MainView () {
@@ -23,39 +25,82 @@ public class Bluetooth.MainView : Switchboard.SettingsPage {
2325 construct {
2426 device_model = new GLib .ListStore (typeof (Services . Device ));
2527
28+ paired_model = new Gtk .SortListModel (
29+ new Gtk .FilterListModel (device_model, new Gtk .CustomFilter ((obj) = > {
30+ var device = (Services . Device ) obj;
31+ return device. paired;
32+ })),
33+ new Gtk .CustomSorter ((GLib . CompareDataFunc<GLib . Object > ) Services . Device . compare)
34+ );
35+
36+ nearby_model = new Gtk .SortListModel (
37+ new Gtk .FilterListModel (device_model, new Gtk .CustomFilter ((obj) = > {
38+ var device = (Services . Device ) obj;
39+
40+ if (device. name == null && device. icon == null ) {
41+ return false ;
42+ }
43+
44+ return ! device. paired;
45+ })),
46+ new Gtk .CustomSorter ((GLib . CompareDataFunc<GLib . Object > ) Services . Device . compare)
47+ );
48+
49+ var paired_placeholder = new Granite .Placeholder (_(" No Paired Devices" )) {
50+ description = _ ("Bluetooth devices will appear here when paired with this device .")
51+ };
52+
53+ var paired_list = new Gtk .ListBox () {
54+ activate_on_single_click = false ,
55+ overflow = HIDDEN ,
56+ selection_mode = BROWSE
57+ };
58+ paired_list.add_css_class (Granite .STYLE_CLASS_RICH_LIST );
59+ paired_list.add_css_class (Granite .STYLE_CLASS_CARD );
60+ paired_list.add_css_class (Granite .STYLE_CLASS_ROUNDED );
61+ paired_list.bind_model (paired_model , create_widget_func );
62+ paired_list.set_placeholder (paired_placeholder );
63+
2664 var empty_alert = new Granite .Placeholder (_(" No Devices Found" )) {
2765 description = _ ("Please ensure that your devices are visible and ready for pairing .")
2866 };
2967
3068 var list_box = new Gtk .ListBox () {
3169 activate_on_single_click = false ,
70+ overflow = HIDDEN ,
3271 selection_mode = BROWSE
3372 };
3473 list_box.add_css_class (Granite .STYLE_CLASS_RICH_LIST );
35- list_box.bind_model (device_model , create_widget_func );
36- list_box.set_header_func ((Gtk .ListBoxUpdateHeaderFunc ) title_rows);
74+ list_box.add_css_class (Granite .STYLE_CLASS_CARD );
75+ list_box.add_css_class (Granite .STYLE_CLASS_ROUNDED );
76+ list_box.bind_model (nearby_model , create_widget_func );
3777 list_box.set_placeholder (empty_alert );
3878
39- var scrolled = new Gtk .ScrolledWindow () {
40- child = list_box,
41- hexpand = true ,
42- vexpand = true
79+ var paired_header = new Granite .HeaderLabel (_(" Paired Devices" )) {
80+ margin_bottom = 6 ,
81+ mnemonic_widget = paired_list
4382 };
4483
45- var overlay = new Gtk . Overlay ( ) {
46- child = scrolled
84+ var nearby_header = new Granite . HeaderLabel (_( " Nearby Devices " ) ) {
85+ mnemonic_widget = list_box
4786 };
4887
49- overlaybar = new Granite .OverlayBar (overlay) {
50- label = _ ("Discovering "),
51- active = true
52- };
88+ discovery_spinner = new Gtk .Spinner ();
5389
54- var frame = new Gtk .Frame (null ) {
55- child = overlay
90+ var nearby_box = new Gtk .Box (HORIZONTAL , 6 ) {
91+ margin_top = 24 ,
92+ margin_bottom = 6 ,
5693 };
94+ nearby_box.append (nearby_header );
95+ nearby_box.append (discovery_spinner );
96+
97+ var box = new Gtk .Box (VERTICAL , 0 );
98+ box.append (paired_header );
99+ box.append (paired_list );
100+ box.append (nearby_box );
101+ box.append (list_box );
57102
58- child = frame ;
103+ child = box ;
59104
60105 manager = Bluetooth.Services.ObjectManager.get_default ();
61106 if (manager .retrieve_finished ) {
@@ -107,7 +152,7 @@ public class Bluetooth.MainView : Switchboard.SettingsPage {
107152 update_description ();
108153 });
109154
110- manager. bind_property (" is-discovering" , overlaybar , " visible " , GLib . BindingFlags . DEFAULT );
155+ manager. bind_property (" is-discovering" , discovery_spinner , " spinning " , DEFAULT );
111156 manager. bind_property (" is-powered" , status_switch, " active" , GLib . BindingFlags . DEFAULT );
112157 }
113158
@@ -119,12 +164,36 @@ public class Bluetooth.MainView : Switchboard.SettingsPage {
119164
120165 ((DBusProxy ) device). g_properties_changed. connect (on_device_changed);
121166
122- device_model. insert_sorted (device, compare_func );
167+ device_model. append (device);
123168 }
124169
125- // Exists as separate function so we can disconnect when devices are removed
126- private void on_device_changed () {
127- device_model. sort (compare_func);
170+ private void on_device_changed (Variant changed , string [] invalidated ) {
171+ var paired = changed. lookup_value (" Paired" , new VariantType (" b" ));
172+ if (paired != null ) {
173+ var nearby_filter = ((Gtk . FilterListModel ) nearby_model. model). filter;
174+ var paired_filter = ((Gtk . FilterListModel ) paired_model. model). filter;
175+
176+ if (paired. get_boolean ()) {
177+ nearby_filter. changed (MORE_STRICT );
178+ paired_filter. changed (LESS_STRICT );
179+ } else {
180+ nearby_filter. changed (LESS_STRICT );
181+ paired_filter. changed (MORE_STRICT );
182+ }
183+
184+ return ;
185+ }
186+
187+ var connected = changed. lookup_value (" Connected" , new VariantType (" b" ));
188+ if (connected != null ) {
189+ paired_model. sorter. changed (DIFFERENT );
190+ return ;
191+ }
192+
193+ var name = changed. lookup_value (" Name" , new VariantType (" s" ));
194+ if (name != null ) {
195+ paired_model. sorter. changed (DIFFERENT );
196+ }
128197 }
129198
130199 private void on_device_removed (Services .Device device ) {
@@ -157,53 +226,7 @@ public class Bluetooth.MainView : Switchboard.SettingsPage {
157226 }
158227 }
159228
160- private int compare_func (Object obj1 , Object obj2 ) {
161- unowned var device1 = (Services . Device ) obj1;
162- unowned var device2 = (Services . Device ) obj2;
163- if (device1. paired && ! device2. paired) {
164- return - 1 ;
165- }
166-
167- if (! device1. paired && device2. paired) {
168- return 1 ;
169- }
170-
171- if (device1. connected && ! device2. connected) {
172- return - 1 ;
173- }
174-
175- if (! device1. connected && device2. connected) {
176- return 1 ;
177- }
178-
179- if (device1. name != null && device2. name == null ) {
180- return - 1 ;
181- }
182-
183- if (device1. name == null && device2. name != null ) {
184- return 1 ;
185- }
186-
187- var name1 = device1. name ?? device1. address;
188- var name2 = device2. name ?? device2. address;
189- return name1. collate (name2);
190- }
191-
192229 private Gtk .Widget create_widget_func (Object obj ) {
193230 return new DeviceRow ((Services . Device ) obj);
194231 }
195-
196- [CCode (instance_pos = -1 )]
197- private void title_rows (DeviceRow row1 , DeviceRow ? row2 ) {
198- if (row2 == null && row1. device. paired) {
199- var label = new Granite .HeaderLabel (_(" Paired Devices" ));
200- row1. set_header (label);
201- } else if (row2 == null || row1. device. paired != row2. device. paired) {
202- /* This header may not appear, so cannot contain discovery spinner */
203- var label = new Granite .HeaderLabel (_(" Nearby Devices" ));
204- row1. set_header (label);
205- } else {
206- row1. set_header (null );
207- }
208- }
209232}
0 commit comments