[baobab] Rejig 'devices and locations' UI
- From: Stefano Facchini <sfacchini src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [baobab] Rejig 'devices and locations' UI
- Date: Fri, 12 Aug 2016 15:11:17 +0000 (UTC)
commit dc5ecdc985c56f6b3cf419790ad4f7a394d6d5a5
Author: George Barrett <bob bob131 so>
Date: Fri Jul 29 01:50:53 2016 +1000
Rejig 'devices and locations' UI
This patch addresses some of the UX issues outlined by Allan Day in the
associated bug report[1] and updates the landing page UI according to
the provided wireframe.
The UX issues targeted by this patch are as follows:
* Home is almost always going to be the location the user is interested
in - why isn't it at the top?
* Isn't clear which locations are local devices and which are remote.
* "Devices and locations" should use title case: "Devices & Locations".
* The size bars are all different lengths. This looks messy, and it's
not clear whether the length is significant.
* The list doesn't look very good when it is very wide - everything is
spread out to the edges.
[1]: https://bugzilla.gnome.org/show_bug.cgi?id=762874
src/baobab-location-list.ui | 31 +++++++
src/baobab-location-list.vala | 178 ++++++++++++++++++++++++++++-------------
src/baobab-location-row.ui | 31 +++++---
src/baobab-location.vala | 37 ++++-----
src/baobab-main-window.ui | 22 ++++-
src/baobab-window.vala | 21 ++++--
src/baobab.gresource.xml | 1 +
7 files changed, 226 insertions(+), 95 deletions(-)
---
diff --git a/src/baobab-location-list.ui b/src/baobab-location-list.ui
new file mode 100644
index 0000000..d70eb66
--- /dev/null
+++ b/src/baobab-location-list.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <template class="BaobabBaseLocationListWidget" parent="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label_widget">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFrame">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkListBox" id="list">
+ <property name="visible">True</property>
+ <style>
+ <class name="view"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/baobab-location-list.vala b/src/baobab-location-list.vala
index 672d3f1..1b3acd6 100644
--- a/src/baobab-location-list.vala
+++ b/src/baobab-location-list.vala
@@ -29,7 +29,9 @@ namespace Baobab {
[GtkChild]
private Gtk.Label path_label;
[GtkChild]
- private Gtk.Label usage_label;
+ private Gtk.Label available_label;
+ [GtkChild]
+ private Gtk.Label total_size_label;
[GtkChild]
private Gtk.LevelBar usage_bar;
@@ -44,31 +46,51 @@ namespace Baobab {
name_label.label = "<b>%s</b>".printf (escaped);
escaped = location.file != null ? GLib.Markup.escape_text (location.file.get_parse_name (), -1)
: "";
- path_label.label = "<small>%s</small>".printf (escaped);
+ path_label.label = escaped;
+
+ // assume for local mounts the end of the mount path is the
+ // relevant information, and for remote mounts the beginning is
+ // more important
+ path_label.ellipsize = location.is_remote ? Pango.EllipsizeMode.END : Pango.EllipsizeMode.START;
+
+ if (location.is_volume || location.is_main_volume) {
+ if (location.size != null) {
+ total_size_label.label = "%s Total".printf (format_size (location.size));
+ total_size_label.show ();
- if (location.is_volume && location.used != null && location.size != null) {
- usage_label.label = "<small>%s / %s</small>".printf (format_size (location.used),
format_size (location.size));
- usage_label.show ();
+ if (location.used != null) {
+ available_label.label = "%s Available".printf (format_size (location.size -
location.used));
- usage_bar.max_value = location.size;
+ usage_bar.max_value = location.size;
- // Set critical color at 90% of the size
- usage_bar.add_offset_value (Gtk.LEVEL_BAR_OFFSET_LOW, 0.9 * location.size);
- usage_bar.value = location.used;
- usage_bar.show ();
+ // Set critical color at 90% of the size
+ usage_bar.add_offset_value (Gtk.LEVEL_BAR_OFFSET_LOW, 0.9 * location.size);
+ usage_bar.value = location.used;
+ usage_bar.show ();
+ } else {
+ available_label.label = "Unknown";
+ }
+ }
+
+ if (location.used != null) {
+ // useful for some remote mounts where we don't know the
+ // size but do have a usage figure
+ available_label.label = "%s Used".printf (format_size (location.used));
+ }
+
+ available_label.show ();
}
}
}
- public class LocationList : Gtk.ListBox {
+ public class LocationList : Object {
private const int MAX_RECENT_LOCATIONS = 5;
private VolumeMonitor monitor;
private List<Location> locations = null;
- public delegate void LocationAction (Location l);
- private LocationAction? location_action;
+ public signal void update ();
construct {
monitor = VolumeMonitor.get ();
@@ -79,28 +101,18 @@ namespace Baobab {
monitor.volume_removed.connect (volume_removed);
monitor.volume_added.connect (volume_added);
- selection_mode = Gtk.SelectionMode.NONE;
- set_header_func (update_header);
-
populate ();
}
- void update_header (Gtk.ListBoxRow row, Gtk.ListBoxRow? before_row) {
- if (before_row != null && row.get_header () == null) {
- row.set_header (new Gtk.Separator (Gtk.Orientation.HORIZONTAL));
- } else {
- row.set_header (null);
- }
+ public void append (Location location) {
+ locations.append(location);
}
- public override void row_activated (Gtk.ListBoxRow row) {
- if (location_action != null) {
- var location_widget = row as LocationRow;
- location_action (location_widget.location);
- }
+ public void @foreach (Func<Location> func) {
+ locations.foreach (func);
}
- bool already_present (File file) {
+ public bool already_present (File file) {
foreach (var l in locations) {
if (l.file != null && l.file.equal (file)) {
return true;
@@ -109,10 +121,6 @@ namespace Baobab {
return false;
}
- void append_to_volumes (Location location) {
- locations.insert_before (locations.find (Location.get_home_location ()), location);
- }
-
void volume_changed (Volume volume) {
update ();
}
@@ -129,7 +137,7 @@ namespace Baobab {
}
void volume_added (Volume volume) {
- append_to_volumes (new Location.from_volume (volume));
+ append (new Location.from_volume (volume));
update ();
}
@@ -151,7 +159,7 @@ namespace Baobab {
var volume = mount.get_volume ();
if (volume == null) {
if (!already_present (mount.get_root ())) {
- append_to_volumes (new Location.from_mount (mount));
+ append (new Location.from_mount (mount));
}
} else {
foreach (var location in locations) {
@@ -166,28 +174,17 @@ namespace Baobab {
}
void populate () {
- locations.append (new Location.for_main_volume ());
+ append (new Location.for_home_folder ());
+ append (new Location.for_main_volume ());
foreach (var volume in monitor.get_volumes ()) {
- var location = new Location.from_volume (volume);
- if (!location.is_home) {
- locations.append (location);
- }
+ volume_added (volume);
}
foreach (var mount in monitor.get_mounts ()) {
- if (mount.get_volume () == null) {
- var location = new Location.from_mount (mount);
- if (!location.is_home) {
- locations.append (location);
- }
- } else {
- // Already added as volume
- }
+ mount_added (mount);
}
- locations.append (Location.get_home_location ());
-
Gtk.RecentManager recent_manager = Gtk.RecentManager.get_default ();
List<Gtk.RecentInfo> recent_items = recent_manager.get_items ();
@@ -212,22 +209,79 @@ namespace Baobab {
recent_items.reverse ();
foreach (var info in recent_items) {
- locations.append (new Location.for_recent_info (info));
+ append (new Location.for_recent_info (info));
}
update ();
}
+ }
+
+ [GtkTemplate (ui = "/org/gnome/baobab/ui/baobab-location-list.ui")]
+ public abstract class BaseLocationListWidget : Gtk.Box {
+ [GtkChild]
+ private Gtk.Label label_widget;
+ [GtkChild]
+ private Gtk.ListBox list;
+
+ public abstract string label { get; }
+
+ private LocationList locations = null;
+ public void set_locations (LocationList locations) {
+ this.locations = locations;
+ locations.update.connect (update);
+ }
+
+ public delegate void LocationAction (Location l);
+ private LocationAction? location_action;
+
+ construct {
+ label_widget.label = _(label);
+ list.selection_mode = Gtk.SelectionMode.NONE;
+ list.set_header_func (update_header);
+ list.row_activated.connect (row_activated);
+ }
+
+ public abstract bool allow_display (Location location);
+
+ public override void show_all () {
+ base.show_all (); // set children to visible
+
+ if (list.get_children ().length () == 0) {
+ visible = false;
+ }
+ }
+
+ public void set_adjustment (Gtk.Adjustment adj) {
+ list.set_adjustment (adj);
+ }
+
+ void update_header (Gtk.ListBoxRow row, Gtk.ListBoxRow? before_row) {
+ if (before_row != null && row.get_header () == null) {
+ row.set_header (new Gtk.Separator (Gtk.Orientation.HORIZONTAL));
+ } else {
+ row.set_header (null);
+ }
+ }
+
+ void row_activated (Gtk.ListBoxRow row) {
+ if (location_action != null) {
+ var location_widget = row as LocationRow;
+ location_action (location_widget.location);
+ }
+ }
public void set_action (owned LocationAction? action) {
location_action = (owned)action;
}
public void update () {
- this.foreach ((widget) => { widget.destroy (); });
+ list.foreach ((widget) => { widget.destroy (); });
- foreach (var location in locations) {
- add (new LocationRow (location));
- }
+ locations.foreach((location) => {
+ if (allow_display (location)) {
+ list.add (new LocationRow (location));
+ }
+ });
show_all ();
}
@@ -237,7 +291,7 @@ namespace Baobab {
return;
}
- if (!already_present (location.file)) {
+ if (!locations.already_present (location.file)) {
locations.append (location);
}
@@ -257,4 +311,18 @@ namespace Baobab {
Gtk.RecentManager.get_default ().add_full (location.file.get_uri (), data);
}
}
+
+ public class LocalLocationList : BaseLocationListWidget {
+ public override string label { get { return "This Computer"; } }
+ public override bool allow_display (Location location) {
+ return !location.is_remote;
+ }
+ }
+
+ public class RemoteLocationList : BaseLocationListWidget {
+ public override string label { get { return "Remote Locations"; } }
+ public override bool allow_display (Location location) {
+ return location.is_remote;
+ }
+ }
}
diff --git a/src/baobab-location-row.ui b/src/baobab-location-row.ui
index 4f18bf7..ac8ecf0 100644
--- a/src/baobab-location-row.ui
+++ b/src/baobab-location-row.ui
@@ -30,6 +30,7 @@
<property name="valign">end</property>
<property name="hexpand">True</property>
<property name="use_markup">True</property>
+ <property name="ellipsize">end</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -58,13 +59,12 @@
</packing>
</child>
<child>
- <object class="GtkLabel" id="usage_label">
+ <object class="GtkLabel" id="available_label">
<property name="visible">False</property>
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="halign">end</property>
<property name="valign">end</property>
- <property name="use_markup">True</property>
</object>
<packing>
<property name="left_attach">2</property>
@@ -74,13 +74,15 @@
</packing>
</child>
<child>
- <object class="GtkLevelBar" id="usage_bar">
+ <object class="GtkLabel" id="total_size_label">
<property name="visible">False</property>
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
- <property name="halign">fill</property>
+ <property name="halign">end</property>
<property name="valign">start</property>
- <property name="hexpand">True</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
</object>
<packing>
<property name="left_attach">2</property>
@@ -90,14 +92,21 @@
</packing>
</child>
<child>
- <object class="GtkImage" id="arrow">
- <property name="icon_name">go-next-symbolic</property>
+ <object class="GtkLevelBar" id="usage_bar">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="halign">fill</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <property name="margin-top">6</property>
+ <property name="margin-bottom">6</property>
</object>
<packing>
- <property name="left_attach">3</property>
- <property name="top_attach">0</property>
- <property name="width">1</property>
- <property name="height">2</property>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">3</property>
+ <property name="height">1</property>
</packing>
</child>
</object>
diff --git a/src/baobab-location.vala b/src/baobab-location.vala
index 0722ddf..12ecbb2 100644
--- a/src/baobab-location.vala
+++ b/src/baobab-location.vala
@@ -41,13 +41,10 @@ namespace Baobab {
public Volume? volume { get; private set; }
public Mount? mount { get; private set; }
- public Scanner? scanner { get; private set; }
+ public bool is_main_volume { get; private set; default = false; }
+ public bool is_remote { get; private set; default = false; }
- public bool is_home {
- get {
- return home_location == this;
- }
- }
+ public Scanner? scanner { get; private set; }
private static const string FS_ATTRIBUTES =
FileAttribute.FILESYSTEM_SIZE + "," +
@@ -58,8 +55,6 @@ namespace Baobab {
FileAttribute.STANDARD_ICON + "," +
FileAttribute.STANDARD_TYPE;
- private static Location? home_location = null;
-
string get_hostname () throws Error {
HostnameIface hostname_iface;
hostname_iface = Bus.get_proxy_sync (BusType.SYSTEM,
@@ -76,11 +71,9 @@ namespace Baobab {
void make_this_home_location () {
name = _("Home folder");
icon = new ThemedIcon ("user-home");
-
- home_location = this;
}
- Location.for_home_folder () {
+ public Location.for_home_folder () {
is_volume = false;
file = File.new_for_path (GLib.Environment.get_home_dir ());
get_file_info ();
@@ -91,14 +84,6 @@ namespace Baobab {
scanner = new Scanner (file, ScanFlags.EXCLUDE_MOUNTS);
}
- public static Location get_home_location () {
- if (home_location == null) {
- home_location = new Location.for_home_folder ();
- }
-
- return home_location;
- }
-
public Location.from_volume (Volume volume_) {
volume = volume_;
volume.changed.connect((vol) => {
@@ -126,6 +111,7 @@ namespace Baobab {
file = File.new_for_path ("/");
get_file_info ();
icon = new ThemedIcon.with_default_fallbacks ("drive-harddisk-system");
+ is_main_volume = true;
get_fs_usage ();
@@ -170,6 +156,8 @@ namespace Baobab {
void update_volume_info () {
mount = volume.get_mount ();
+ is_remote = volume.get_identifier (VolumeIdentifier.CLASS) == "network";
+
if (mount != null) {
fill_from_mount ();
} else {
@@ -189,6 +177,11 @@ namespace Baobab {
file = mount.get_root ();
get_file_info ();
+ // a little hacky, but it gets around all those null returns
+ if ("folder-remote" in icon.to_string() && !is_volume) {
+ is_remote = true;
+ }
+
if (file != null && file.equal (File.new_for_path (Environment.get_home_dir ()))) {
make_this_home_location ();
}
@@ -224,6 +217,12 @@ namespace Baobab {
}
} catch (Error e) {
}
+ // this can happen sometimes with remote mounts. The result, if
+ // unchecked, is a uint64 underflow and the drive being presented
+ // with 18.4 EB free
+ if (size != null && used != null && used > size) {
+ size = null;
+ }
}
public async void mount_volume () throws Error {
diff --git a/src/baobab-main-window.ui b/src/baobab-main-window.ui
index 1e0cecd..4fbd809 100644
--- a/src/baobab-main-window.ui
+++ b/src/baobab-main-window.ui
@@ -187,12 +187,26 @@
<property name="visible">True</property>
<property name="vexpand">True</property>
<property name="hexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
<child>
- <object class="BaobabLocationList" id="location_list">
+ <object class="GtkBox">
<property name="visible">True</property>
- <style>
- <class name="view"/>
- </style>
+ <property name="orientation">vertical</property>
+ <property name="spacing">32</property>
+ <property name="margin">32</property>
+ <property name="border-width">12</property>
+ <property name="halign">center</property>
+ <property name="width-request">700</property>
+ <child>
+ <object class="BaobabLocalLocationList" id="local_location_list">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="BaobabRemoteLocationList" id="remote_location_list">
+ <property name="visible">True</property>
+ </object>
+ </child>
</object>
</child>
</object>
diff --git a/src/baobab-window.vala b/src/baobab-window.vala
index 1675a2e..e5f20aa 100644
--- a/src/baobab-window.vala
+++ b/src/baobab-window.vala
@@ -50,7 +50,9 @@ namespace Baobab {
[GtkChild]
private Gtk.ScrolledWindow location_scrolled_window;
[GtkChild]
- private LocationList location_list;
+ private LocalLocationList local_location_list;
+ [GtkChild]
+ private RemoteLocationList remote_location_list;
[GtkChild]
private Gtk.TreeView treeview;
[GtkChild]
@@ -127,9 +129,13 @@ namespace Baobab {
var action = ui_settings.create_action ("active-chart");
add_action (action);
- location_list.set_adjustment (location_scrolled_window.get_vadjustment ());
- location_list.set_action (on_scan_location_activate);
- location_list.update ();
+ var locations = new LocationList();
+ foreach (BaseLocationListWidget location_list in new BaseLocationListWidget[]
{local_location_list, remote_location_list}) {
+ location_list.set_locations (locations);
+ location_list.set_adjustment (location_scrolled_window.get_vadjustment ());
+ location_list.set_action (on_scan_location_activate);
+ location_list.update ();
+ }
setup_treeview ();
@@ -222,7 +228,10 @@ namespace Baobab {
active_location = location;
// Update the timestamp for GtkRecentManager
- location_list.add_location (location);
+ if (location.is_remote)
+ remote_location_list.add_location (location);
+ else
+ local_location_list.add_location (location);
}
void on_scan_location_activate (Location location) {
@@ -486,7 +495,7 @@ namespace Baobab {
if (child == home_page) {
var action = lookup_action ("reload") as SimpleAction;
action.set_enabled (false);
- header_bar.title = _("Devices and locations");
+ header_bar.title = _("Devices & Locations");
} else {
var action = lookup_action ("reload") as SimpleAction;
action.set_enabled (true);
diff --git a/src/baobab.gresource.xml b/src/baobab.gresource.xml
index 8cd82be..7cd35b0 100644
--- a/src/baobab.gresource.xml
+++ b/src/baobab.gresource.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/baobab/ui">
+ <file compressed="true">baobab-location-list.ui</file>
<file compressed="true">baobab-location-row.ui</file>
<file compressed="true">baobab-main-window.ui</file>
</gresource>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]