Skip to content

Commit 5530462

Browse files
authored
MainView: use two lists (#246)
1 parent ae05489 commit 5530462

File tree

3 files changed

+112
-67
lines changed

3 files changed

+112
-67
lines changed

data/screenshot.png

-16.6 KB
Loading

src/MainView.vala

Lines changed: 90 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
public 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
}

src/Services/Device.vala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,26 @@ public interface Bluetooth.Services.Device : Object {
4242
public abstract string name { owned get; }
4343
public abstract uint16 appearance { owned get; }
4444
public abstract uint32 @class { owned get; }
45+
46+
public static int compare (Device device1, Device device2) {
47+
if (device1.connected && !device2.connected) {
48+
return -1;
49+
}
50+
51+
if (!device1.connected && device2.connected) {
52+
return 1;
53+
}
54+
55+
if (device1.name != null && device2.name == null) {
56+
return -1;
57+
}
58+
59+
if (device1.name == null && device2.name != null) {
60+
return 1;
61+
}
62+
63+
var name1 = device1.name ?? device1.address;
64+
var name2 = device2.name ?? device2.address;
65+
return name1.collate (name2);
66+
}
4567
}

0 commit comments

Comments
 (0)