[geary/wip/728002-webkit2: 68/96] Add an OSD prgress bar for remote image loading.



commit c669d2d6177dd1e6447a78a90fd468b6b17ac888
Author: Michael James Gratton <mike vee net>
Date:   Tue Jan 3 20:30:49 2017 +1100

    Add an OSD prgress bar for remote image loading.
    
    * src/client/conversation-viewer/conversation-message.vala
      (ConversationMessage): Chase body container type and name change,
      update call sites. Add in a Progress bar and update it using callbacks
      from the web view, handling both initial load and the user subsequently
      giving permission to load remote images.
    
    * src/client/components/client-web-view.vala (ClientWebView): Provide a
      form of the internal URL scheme prefix.
    
    * ui/conversation-message.ui: Convert body container from being a GtkBox
      to a GtkGrid, add in a GtkProgressBar.

 src/client/components/client-web-view.vala         |    8 ++-
 .../conversation-viewer/conversation-email.vala    |    6 +-
 .../conversation-viewer/conversation-list-box.vala |    2 +-
 .../conversation-viewer/conversation-message.vala  |   79 ++++++++++++++++++--
 ui/conversation-message.ui                         |   51 ++++++++++---
 5 files changed, 120 insertions(+), 26 deletions(-)
---
diff --git a/src/client/components/client-web-view.vala b/src/client/components/client-web-view.vala
index 6723578..60313ff 100644
--- a/src/client/components/client-web-view.vala
+++ b/src/client/components/client-web-view.vala
@@ -17,11 +17,15 @@
 public class ClientWebView : WebKit.WebView {
 
 
+    /** URI Scheme and delimiter for internal resource loads. */
+    public const string INTERNAL_URL_PREFIX = "geary:";
+
+    /** URI for internal message body page loads. */
+    public const string INTERNAL_URL_BODY = INTERNAL_URL_PREFIX + "body";
+
     /** URI Scheme and delimiter for images loaded by Content-ID. */
     public const string CID_URL_PREFIX = "cid:";
 
-    private const string INTERNAL_URL_BODY = "geary:body";
-
     private const string PREFERRED_HEIGHT_MESSAGE = "preferredHeightChanged";
     private const string REMOTE_IMAGE_LOAD_BLOCKED_MESSAGE = "remoteImageLoadBlocked";
     private const string SELECTION_CHANGED_MESSAGE = "selectionChanged";
diff --git a/src/client/conversation-viewer/conversation-email.vala 
b/src/client/conversation-viewer/conversation-email.vala
index b588a4d..7ee1e71 100644
--- a/src/client/conversation-viewer/conversation-email.vala
+++ b/src/client/conversation-viewer/conversation-email.vala
@@ -488,9 +488,7 @@ public class ConversationEmail : Gtk.Box {
 
         Gee.List<Geary.RFC822.Message> sub_messages = message.get_sub_messages();
         if (sub_messages.size > 0) {
-            this.primary_message.body.pack_start(
-                this.sub_messages, false, false, 0
-            );
+            this.primary_message.body_container.add(this.sub_messages);
         }
         foreach (Geary.RFC822.Message sub_message in sub_messages) {
             ConversationMessage attached_message =
@@ -714,7 +712,7 @@ public class ConversationEmail : Gtk.Box {
         if (!this.displayed_attachments.is_empty) {
             this.attachments_button.show();
             this.attachments_button.set_sensitive(!this.is_collapsed);
-            this.primary_message.body.add(this.attachments);
+            this.primary_message.body_container.add(this.attachments);
 
             if (this.displayed_attachments.size > 1) {
                 this.select_all_attachments.show();
diff --git a/src/client/conversation-viewer/conversation-list-box.vala 
b/src/client/conversation-viewer/conversation-list-box.vala
index 2625d94..3ad1bfb 100644
--- a/src/client/conversation-viewer/conversation-list-box.vala
+++ b/src/client/conversation-viewer/conversation-list-box.vala
@@ -778,7 +778,7 @@ public class ConversationListBox : Gtk.ListBox {
             });
 
         ConversationMessage conversation_message = view.primary_message;
-        conversation_message.body.button_release_event.connect_after((event) => {
+        conversation_message.body_container.button_release_event.connect_after((event) => {
                 // Consume all non-consumed clicks so the row is not
                 // inadvertently activated after clicking on the
                 // email body.
diff --git a/src/client/conversation-viewer/conversation-message.vala 
b/src/client/conversation-viewer/conversation-message.vala
index ff7f236..09a4ac5 100644
--- a/src/client/conversation-viewer/conversation-message.vala
+++ b/src/client/conversation-viewer/conversation-message.vala
@@ -204,7 +204,9 @@ public class ConversationMessage : Gtk.Grid {
     [GtkChild]
     private Gtk.Revealer body_revealer;
     [GtkChild]
-    public Gtk.Box body; // WebKit.WebView crashes when added to a Grid
+    public Gtk.Grid body_container;
+    [GtkChild]
+    public Gtk.ProgressBar body_progress;
 
     [GtkChild]
     private Gtk.Popover link_popover;
@@ -240,6 +242,16 @@ public class ConversationMessage : Gtk.Grid {
 
     private int next_replaced_buffer_number = 0;
 
+    // Is the view set to allow remote image loads?
+    private bool is_loading_images;
+
+    private int remote_resources_requested = 0;
+
+    private int remote_resources_loaded = 0;
+
+    // Timer for hiding the progress bar when complete
+    private Geary.TimeoutManager body_progress_timer = null;
+
 
     /** Fired when the user clicks a link in the email. */
     public signal void link_activated(string link);
@@ -268,6 +280,7 @@ public class ConversationMessage : Gtk.Grid {
                                Configuration config,
                                bool load_remote_images) {
         this.message = message;
+        this.is_loading_images = load_remote_images;
 
 #if !GTK_3_20
         // GTK < 3.20+ style workarounds. Keep this in sync with
@@ -372,21 +385,29 @@ public class ConversationMessage : Gtk.Grid {
         this.web_view.link_activated.connect((link) => {
                 link_activated(link);
             });
+        this.web_view.load_changed.connect(on_load_changed);
         this.web_view.mouse_target_changed.connect(on_mouse_target_changed);
-        this.web_view.resource_load_started.connect((view, res, req) => {
-                this.resources[res.get_uri()] = res;
+        this.web_view.notify["estimated-load-progress"].connect(() => {
+                this.body_progress.set_fraction(this.web_view.estimated_load_progress);
             });
+        this.web_view.resource_load_started.connect(on_resource_load_started);
         this.web_view.remote_image_load_blocked.connect(() => {
                 this.remote_images_infobar.show();
             });
         this.web_view.selection_changed.connect(on_selection_changed);
+        this.web_view.set_hexpand(true);
+        this.web_view.set_vexpand(true);
         this.web_view.show();
 
-        this.body.set_has_tooltip(true); // Used to show link URLs
-        this.body.pack_start(this.web_view, true, true, 0);
+        this.body_container.set_has_tooltip(true); // Used to show link URLs
+        this.body_container.add(this.web_view);
+        this.body_progress_timer = new Geary.TimeoutManager.seconds(
+            1, () => { this.body_progress.hide(); }
+        );
     }
 
     public override void destroy() {
+        this.body_progress_timer.reset();
         this.resources.clear();
         this.searchable_addresses.clear();
         base.destroy();
@@ -696,6 +717,7 @@ public class ConversationMessage : Gtk.Grid {
     }
 
     private void show_images(bool remember) {
+        this.is_loading_images = true;
         this.web_view.load_remote_images();
         if (remember) {
             flag_remote_images();
@@ -782,6 +804,49 @@ public class ConversationMessage : Gtk.Grid {
         revealer.set_transition_type(transition);
     }
 
+    private void on_load_changed(WebKit.LoadEvent load_event) {
+        if (load_event != WebKit.LoadEvent.FINISHED) {
+            this.body_progress_timer.reset();
+            this.body_progress.pulse();
+        } else {
+            this.body_progress_timer.start();
+        }
+    }
+
+    private void on_resource_load_started(WebKit.WebView view,
+                                          WebKit.WebResource res,
+                                          WebKit.URIRequest req) {
+        // We only want to show the body loading progress meter if we
+        // are loading images, so do it here rather than
+        // on_load_changed.
+        if (this.is_loading_images &&
+            !res.get_uri().has_prefix(ClientWebView.INTERNAL_URL_PREFIX)) {
+            this.body_progress.show();
+            this.body_progress.pulse();
+            if (!this.web_view.is_loading) {
+                // The initial page load has finished, so we must be
+                // loading a remote image, but can't rely on the
+                // load_changed signal to stop the timer or
+                // estimated-load-progress changing. So manually
+                // manage it here.
+                this.remote_resources_requested++;
+                res.finished.connect(() => {
+                        this.remote_resources_loaded++;
+                        this.body_progress.set_fraction(
+                            (this.remote_resources_loaded /
+                             this.remote_resources_requested) +
+                            this.body_progress.get_pulse_step()
+                        );
+                        if (this.remote_resources_loaded >=
+                            this.remote_resources_requested) {
+                            this.body_progress_timer.start();
+                        }
+                    });
+            }
+            this.resources[res.get_uri()] = res;
+        }
+    }
+
     [GtkCallback]
     private void on_address_box_child_activated(Gtk.FlowBox box,
                                                 Gtk.FlowBoxChild child) {
@@ -863,8 +928,8 @@ public class ConversationMessage : Gtk.Grid {
                                          WebKit.HitTestResult hit_test,
                                          uint modifiers) {
         if (hit_test.context_is_link()) {
-            this.body.set_tooltip_text(hit_test.get_link_uri());
-            this.body.trigger_tooltip_query();
+            this.body_container.set_tooltip_text(hit_test.get_link_uri());
+            this.body_container.trigger_tooltip_query();
         }
     }
 
diff --git a/ui/conversation-message.ui b/ui/conversation-message.ui
index cf65392..d635b08 100644
--- a/ui/conversation-message.ui
+++ b/ui/conversation-message.ui
@@ -5,7 +5,6 @@
   <template class="ConversationMessage" parent="GtkGrid">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
-    <property name="hexpand">True</property>
     <property name="orientation">vertical</property>
     <child>
       <object class="GtkGrid" id="summary">
@@ -475,13 +474,10 @@
       <object class="GtkRevealer" id="body_revealer">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="hexpand">True</property>
         <child>
-          <object class="GtkBox" id="body">
+          <object class="GtkGrid">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="hexpand">True</property>
-            <property name="orientation">vertical</property>
             <child>
               <object class="GtkGrid" id="infobars">
                 <property name="visible">True</property>
@@ -582,6 +578,9 @@
                       <action-widget response="1">button1</action-widget>
                       <action-widget response="2">button2</action-widget>
                     </action-widgets>
+                    <child>
+                      <placeholder/>
+                    </child>
                   </object>
                   <packing>
                     <property name="left_attach">0</property>
@@ -590,14 +589,42 @@
                 </child>
               </object>
               <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkOverlay">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkGrid" id="body_container">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <style>
+                      <class name="geary-message-body"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="index">-1</property>
+                  </packing>
+                </child>
+                <child type="overlay">
+                  <object class="GtkProgressBar" id="body_progress">
+                    <property name="can_focus">False</property>
+                    <property name="valign">start</property>
+                    <style>
+                      <class name="osd"/>
+                      <class name="top"/>
+                    </style>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
               </packing>
             </child>
-            <style>
-              <class name="geary-message-body"/>
-            </style>
           </object>
         </child>
       </object>
@@ -612,7 +639,7 @@
   </template>
   <object class="GtkPopover" id="link_popover">
     <property name="can_focus">False</property>
-    <property name="relative_to">body</property>
+    <property name="relative_to">body_container</property>
     <property name="position">bottom</property>
     <child>
       <object class="GtkGrid">


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]