[banshee] Implement navigation, reloading, HTML5 spinner



commit ecddca5f6f60a1a95342bfc16eb94454d01bf88d
Author: Aaron Bockover <abockover novell com>
Date:   Sat Jul 10 18:45:44 2010 -0400

    Implement navigation, reloading, HTML5 spinner
    
    Also added a loading spinner that will spin until the actual store gets
    loaded. This is really exciting to me. My thought process went something
    like this:
    
       "Okay, I'll just connect to the LoadStatusChanged event, and listen
       for when the store page begins to render; until then, I'll render
       some kind of spinner in Cairo by overriding the OssiferWebView
       OnExposeEvent virtual method; I'll of course need to use the
       animation facilities we have in Banshee to render the animation."
    
    That probably would have been the usual 150 lines of code to put some
    pixels on the screen. I'm used to this.
    
    Then I was all like, "Whoa wait..."
    
      "The store is delivered using a perfectly capable WebKit HTML5
      browser, so I think this is a great excuse to write my first thingy
      using HTML5 Canvas."
    
    And so I did. And it was easy. And it was fast. And it was pretty.

 .../Banshee.WebBrowser/NavigationControl.cs        |   68 +++++++++++++++++++-
 .../Banshee.WebBrowser/OssiferWebView.cs           |   56 +++++++++++++++-
 .../libossifer/ossifer-web-view.c                  |   42 ++++++++++++
 .../Banshee.AmazonMp3.Store.csproj                 |    4 +
 .../Banshee.AmazonMp3.Store/StoreView.cs           |   25 ++++++--
 .../Banshee.AmazonMp3.Store/WebBrowserShell.cs     |    1 +
 src/Extensions/Banshee.AmazonMp3.Store/Makefile.am |    4 +-
 .../Banshee.AmazonMp3.Store/Resources/loading.html |   31 +++++++++
 .../Banshee.AmazonMp3/Banshee.AmazonMp3.csproj     |   10 ++--
 9 files changed, 225 insertions(+), 16 deletions(-)
---
diff --git a/src/Core/Banshee.WebBrowser/Banshee.WebBrowser/NavigationControl.cs b/src/Core/Banshee.WebBrowser/Banshee.WebBrowser/NavigationControl.cs
index ebf9d9d..a052e1b 100644
--- a/src/Core/Banshee.WebBrowser/Banshee.WebBrowser/NavigationControl.cs
+++ b/src/Core/Banshee.WebBrowser/Banshee.WebBrowser/NavigationControl.cs
@@ -27,6 +27,7 @@
 using System;
 
 using Gtk;
+using Hyena.Gui;
 
 namespace Banshee.WebBrowser
 {
@@ -37,19 +38,84 @@ namespace Banshee.WebBrowser
         private Button reload_button = new Button (new Image (Stock.Refresh, IconSize.Button)) { Relief = ReliefStyle.None };
         private Button home_button = new Button (new Image (Stock.Home, IconSize.Button)) { Relief = ReliefStyle.None };
 
+        public event EventHandler GoHomeEvent;
+
         public NavigationControl ()
         {
+            back_button.Clicked += (o, e) => {
+                if (web_view != null && web_view.CanGoBack) {
+                    web_view.GoBack ();
+                }
+            };
+
+            forward_button.Clicked += (o, e) => {
+                if (web_view != null && web_view.CanGoForward) {
+                    web_view.GoForward ();
+                }
+            };
+
+            reload_button.Clicked += (o, e) => {
+                if (web_view != null) {
+                    web_view.Reload (!GtkUtilities.NoImportantModifiersAreSet ());
+                }
+            };
+
+            home_button.Clicked += (o, e) => {
+                var handler = GoHomeEvent;
+                if (handler != null) {
+                    handler (this, EventArgs.Empty);
+                }
+            };
+
+            UpdateNavigation ();
+
             PackStart (back_button, false, false, 0);
             PackStart (forward_button, false, false, 0);
             PackStart (reload_button, false, false, 5);
             PackStart (home_button, false, false, 0);
+
             ShowAll ();
         }
 
         private OssiferWebView web_view;
         public OssiferWebView WebView {
             get { return web_view; }
-            set { web_view = value; }
+            set {
+                if (web_view == value) {
+                    return;
+                } else if (web_view != null) {
+                    web_view.LoadStatusChanged -= OnOssiferWebViewLoadStatusChanged;
+                }
+
+                web_view = value;
+
+                if (web_view != null) {
+                    web_view.LoadStatusChanged += OnOssiferWebViewLoadStatusChanged;
+                }
+
+                UpdateNavigation ();
+            }
+        }
+
+        public void UpdateNavigation ()
+        {
+            if (web_view == null) {
+                Sensitive = false;
+                return;
+            }
+
+            Sensitive = true;
+
+            back_button.Sensitive = web_view.CanGoBack;
+            forward_button.Sensitive = web_view.CanGoForward;
+        }
+
+        private void OnOssiferWebViewLoadStatusChanged (object o, EventArgs args)
+        {
+            if (web_view.LoadStatus == OssiferLoadStatus.Committed ||
+                web_view.LoadStatus == OssiferLoadStatus.Failed) {
+                UpdateNavigation ();
+            }
         }
     }
 }
diff --git a/src/Core/Banshee.WebBrowser/Banshee.WebBrowser/OssiferWebView.cs b/src/Core/Banshee.WebBrowser/Banshee.WebBrowser/OssiferWebView.cs
index de004c4..3513e6c 100644
--- a/src/Core/Banshee.WebBrowser/Banshee.WebBrowser/OssiferWebView.cs
+++ b/src/Core/Banshee.WebBrowser/Banshee.WebBrowser/OssiferWebView.cs
@@ -177,23 +177,73 @@ namespace Banshee.WebBrowser
         }
 
         [DllImport (LIBOSSIFER)]
+        private static extern bool ossifer_web_view_can_go_forward (IntPtr ossifer);
+
+        public virtual bool CanGoForward {
+            get { return ossifer_web_view_can_go_forward (Handle); }
+        }
+
+        [DllImport (LIBOSSIFER)]
+        private static extern bool ossifer_web_view_can_go_back (IntPtr ossifer);
+
+        public virtual bool CanGoBack {
+            get { return ossifer_web_view_can_go_back (Handle); }
+        }
+
+        [DllImport (LIBOSSIFER)]
+        private static extern void ossifer_web_view_go_forward (IntPtr ossifer);
+
+        public virtual void GoForward ()
+        {
+            ossifer_web_view_go_forward (Handle);
+        }
+
+        [DllImport (LIBOSSIFER)]
+        private static extern void ossifer_web_view_go_back (IntPtr ossifer);
+
+        public virtual void GoBack ()
+        {
+            ossifer_web_view_go_back (Handle);
+        }
+
+        [DllImport (LIBOSSIFER)]
+        private static extern void ossifer_web_view_reload (IntPtr ossifer);
+
+        [DllImport (LIBOSSIFER)]
+        private static extern void ossifer_web_view_reload_bypass_cache (IntPtr ossifer);
+
+        public virtual void Reload (bool bypassCache)
+        {
+            if (bypassCache) {
+                ossifer_web_view_reload_bypass_cache (Handle);
+            } else {
+                ossifer_web_view_reload (Handle);
+            }
+        }
+
+        public void Reload ()
+        {
+            Reload (false);
+        }
+
+        [DllImport (LIBOSSIFER)]
         private static extern IntPtr ossifer_web_view_get_uri (IntPtr ossifer);
 
-        public string Uri {
+        public virtual string Uri {
             get { return GLib.Marshaller.Utf8PtrToString (ossifer_web_view_get_uri (Handle)); }
         }
 
         [DllImport (LIBOSSIFER)]
         private static extern IntPtr ossifer_web_view_get_title (IntPtr ossifer);
 
-        public string Title {
+        public virtual string Title {
             get { return GLib.Marshaller.Utf8PtrToString (ossifer_web_view_get_title (Handle)); }
         }
 
         [DllImport (LIBOSSIFER)]
         private static extern OssiferLoadStatus ossifer_web_view_get_load_status (IntPtr ossifer);
 
-        public OssiferLoadStatus LoadStatus {
+        public virtual OssiferLoadStatus LoadStatus {
             get { return ossifer_web_view_get_load_status (Handle); }
         }
 
diff --git a/src/Core/Banshee.WebBrowser/libossifer/ossifer-web-view.c b/src/Core/Banshee.WebBrowser/libossifer/ossifer-web-view.c
index 3b8e0ad..2e33707 100644
--- a/src/Core/Banshee.WebBrowser/libossifer/ossifer-web-view.c
+++ b/src/Core/Banshee.WebBrowser/libossifer/ossifer-web-view.c
@@ -299,4 +299,46 @@ ossifer_web_view_get_load_status (OssiferWebView *ossifer)
 {
     g_return_val_if_fail (OSSIFER_WEB_VIEW (ossifer), WEBKIT_LOAD_FAILED);
     return webkit_web_view_get_load_status (WEBKIT_WEB_VIEW (ossifer));
+}
+
+gboolean
+ossifer_web_view_can_go_back (OssiferWebView *ossifer)
+{
+    g_return_val_if_fail (OSSIFER_WEB_VIEW (ossifer), FALSE);
+    return webkit_web_view_can_go_back (WEBKIT_WEB_VIEW (ossifer));
+}
+
+gboolean
+ossifer_web_view_can_go_forward (OssiferWebView *ossifer)
+{
+    g_return_val_if_fail (OSSIFER_WEB_VIEW (ossifer), FALSE);
+    return webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW (ossifer));
+}
+
+void
+ossifer_web_view_go_back (OssiferWebView *ossifer)
+{
+    g_return_if_fail (OSSIFER_WEB_VIEW (ossifer));
+    return webkit_web_view_go_back (WEBKIT_WEB_VIEW (ossifer));
+}
+
+void
+ossifer_web_view_go_forward (OssiferWebView *ossifer)
+{
+    g_return_if_fail (OSSIFER_WEB_VIEW (ossifer));
+    return webkit_web_view_go_forward (WEBKIT_WEB_VIEW (ossifer));
+}
+
+void
+ossifer_web_view_reload (OssiferWebView *ossifer)
+{
+    g_return_if_fail (OSSIFER_WEB_VIEW (ossifer));
+    return webkit_web_view_reload (WEBKIT_WEB_VIEW (ossifer));
+}
+
+void
+ossifer_web_view_reload_bypass_cache (OssiferWebView *ossifer)
+{
+    g_return_if_fail (OSSIFER_WEB_VIEW (ossifer));
+    return webkit_web_view_reload_bypass_cache (WEBKIT_WEB_VIEW (ossifer));
 }
\ No newline at end of file
diff --git a/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store.csproj b/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store.csproj
index 362807c..4f2a432 100644
--- a/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store.csproj
+++ b/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store.csproj
@@ -54,9 +54,13 @@
     <EmbeddedResource Include="Banshee.AmazonMp3.Store.addin.xml">
       <LogicalName>Banshee.AmazonMp3.Store.addin.xml</LogicalName>
     </EmbeddedResource>
+    <EmbeddedResource Include="Resources\loading.html">
+      <LogicalName>loading.html</LogicalName>
+    </EmbeddedResource>
   </ItemGroup>
   <ItemGroup>
     <Folder Include="Banshee.AmazonMp3.Store\" />
+    <Folder Include="Resources\" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
diff --git a/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store/StoreView.cs b/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store/StoreView.cs
index e33403f..e1fd8b2 100644
--- a/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store/StoreView.cs
+++ b/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store/StoreView.cs
@@ -42,11 +42,24 @@ namespace Banshee.AmazonMp3.Store
     {
         public StoreView ()
         {
+            // Ensure that Amazon knows a valid downloader is available,
+            // otherwise the purchase experience is interrupted with a
+            // confusing message about downloading and installing software.
             SetCookie ("dmusic_download_manager_enabled",
                 AmzMp3Downloader.AmazonMp3DownloaderCompatVersion,
                 ".amazon.com", "/", TimeSpan.FromDays (365.2422));
 
-            LoadUri ("http://www.amazon.com/mp3/";);
+            // This is an HTML5 Canvas/JS spinner icon. It is awesome
+            // and renders immediately, going away when the store loads.
+            LoadString (AssemblyResource.GetFileContents ("loading.html"),
+                "text/html", "UTF-8", null);
+
+            // We defer this to another main loop iteration, otherwise
+            // our load placeholder document will never be rendered.
+            GLib.Idle.Add (delegate {
+                GoHome ();
+                return false;
+            });
         }
 
         protected override OssiferNavigationResponse OnMimeTypePolicyDecisionRequested (string mimetype)
@@ -63,11 +76,6 @@ namespace Banshee.AmazonMp3.Store
             }
         }
 
-        protected override void OnLoadStatusChanged (OssiferLoadStatus status)
-        {
-            Console.WriteLine ("LOAD STATUS: {0} -> {1} ({2}, {3})", status, LoadStatus, Uri, Title);
-        }
-
         protected override string OnDownloadRequested (string mimetype, string uri, string suggestedFilename)
         {
             switch (mimetype) {
@@ -100,5 +108,10 @@ namespace Banshee.AmazonMp3.Store
                     break;
             }
         }
+
+        public void GoHome ()
+        {
+            LoadUri ("http://amz-proxy.banshee.fm/";);
+        }
     }
 }
\ No newline at end of file
diff --git a/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store/WebBrowserShell.cs b/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store/WebBrowserShell.cs
index 786daa6..ae63a9c 100644
--- a/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store/WebBrowserShell.cs
+++ b/src/Extensions/Banshee.AmazonMp3.Store/Banshee.AmazonMp3.Store/WebBrowserShell.cs
@@ -41,6 +41,7 @@ namespace Banshee.AmazonMp3.Store
         public WebBrowserShell () : base (2, 1, false)
         {
             navigation_control.WebView = store_view;
+            navigation_control.GoHomeEvent += (o, e) => store_view.GoHome ();
 
             Attach (navigation_control, 0, 1, 0, 1,
                 AttachOptions.Expand | AttachOptions.Fill,
diff --git a/src/Extensions/Banshee.AmazonMp3.Store/Makefile.am b/src/Extensions/Banshee.AmazonMp3.Store/Makefile.am
index 9153efd..d9356ac 100644
--- a/src/Extensions/Banshee.AmazonMp3.Store/Makefile.am
+++ b/src/Extensions/Banshee.AmazonMp3.Store/Makefile.am
@@ -8,7 +8,9 @@ SOURCES =  \
 	Banshee.AmazonMp3.Store/StoreView.cs \
 	Banshee.AmazonMp3.Store/WebBrowserShell.cs 
 
-RESOURCES = Banshee.AmazonMp3.Store.addin.xml
+RESOURCES =  \
+	Banshee.AmazonMp3.Store.addin.xml \
+	Resources/loading.html
 
 if HAVE_LIBWEBKIT
 include $(top_srcdir)/build/build.mk
diff --git a/src/Extensions/Banshee.AmazonMp3.Store/Resources/loading.html b/src/Extensions/Banshee.AmazonMp3.Store/Resources/loading.html
new file mode 100644
index 0000000..16fc85a
--- /dev/null
+++ b/src/Extensions/Banshee.AmazonMp3.Store/Resources/loading.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    window.onload = function () {
+        var canvas = document.getElementById ("spinner");
+        var context = canvas.getContext ("2d");
+        context.translate (32, 32);
+        context.lineWidth = 5;
+        context.lineCap = "round";
+        setInterval (function () {
+            var density = 12;
+            context.clearRect (-32, -32, 64, 64);
+            context.rotate (Math.PI * 2 / density);
+            for (var i = 0; i < density; i++) {
+                context.rotate (Math.PI * 2 / density);
+                context.strokeStyle = "rgba(0,0,0," + i / density + ")";
+                context.beginPath ();
+                context.moveTo (0, 15);
+                context.lineTo (0, 25);
+                context.stroke ();
+            }
+        }, 75);
+    };
+  </script>
+</head>
+<body>
+<canvas id="spinner" width="64" height="64"
+    style="position:absolute; top:35%; left:50%; margin-left:-32px;"/>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3.csproj b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3.csproj
index 28b697d..8598da4 100644
--- a/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3.csproj
+++ b/src/Extensions/Banshee.AmazonMp3/Banshee.AmazonMp3.csproj
@@ -76,15 +76,15 @@
       <Project>{B28354F0-BA87-44E8-989F-B864A3C7C09F}</Project>
       <Name>Banshee.Services</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\Libraries\Hyena.Gui\Hyena.Gui.csproj">
-      <Project>{C856EFD8-E812-4E61-8B76-E3583D94C233}</Project>
-      <Name>Hyena.Gui</Name>
-    </ProjectReference>
     <ProjectReference Include="..\..\Core\Banshee.ThickClient\Banshee.ThickClient.csproj">
       <Project>{AC839523-7BDF-4AB6-8115-E17921B96EC6}</Project>
       <Name>Banshee.ThickClient</Name>
     </ProjectReference>
-    <ProjectReference Include="..\..\Libraries\Hyena\Hyena.csproj">
+    <ProjectReference Include="..\..\Hyena\Hyena.Gui\Hyena.Gui.csproj">
+      <Project>{C856EFD8-E812-4E61-8B76-E3583D94C233}</Project>
+      <Name>Hyena.Gui</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\Hyena\Hyena\Hyena.csproj">
       <Project>{95374549-9553-4C1E-9D89-667755F90E12}</Project>
       <Name>Hyena</Name>
     </ProjectReference>



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