[gnome-clocks/wip/cityimages: 32/40] Use an ImageProvider interface



commit 75720ca82f2890f96af3627ecb43f7dd9e3bbcda
Author: Evgeny Bobkin <evgen ibqn gmail com>
Date:   Fri Sep 13 16:17:20 2013 +0200

    Use an ImageProvider interface
    
    Do not show a warning message, when image files are not found
    
    Untabify providers.vala file
    
    Add scrolled window
    
    Add non working yet Flickr provider
    
    Add a flickr client and integrate it into flickr provider
    
    Do not monitor the flickr folder, pass name of changed file to signal
    
    Clean up code
    
    Remove unused variable
    
    Simplify code and hide comments

 Makefile.am        |    3 +
 configure.ac       |    2 +
 src/providers.vala |  260 +++++++++++++++++++++++++++++++++++++++++++++++-----
 src/world.vala     |   22 +++--
 4 files changed, 256 insertions(+), 31 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 6b1a249..10cc49a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -94,6 +94,9 @@ AM_VALAFLAGS = \
        --pkg libcanberra \
        --pkg libnotify \
        --pkg geocode-glib-1.0 \
+       --pkg libsoup-2.4 \
+       --pkg json-glib-1.0 \
+       --thread \
        --gresources  $(top_srcdir)/data/gnome-clocks.gresource.xml
 
 bin_PROGRAMS = gnome-clocks
diff --git a/configure.ac b/configure.ac
index 3d9e291..e5b7806 100644
--- a/configure.ac
+++ b/configure.ac
@@ -58,6 +58,8 @@ PKG_CHECK_MODULES(CLOCKS, [
     libnotify >= 0.7.0
     geocode-glib-1.0 >= 0.99.3
     geoclue-2.0 >= 1.99.3
+    json-glib-1.0
+    libsoup-2.4
 ])
 
 YELP_HELP_INIT
diff --git a/src/providers.vala b/src/providers.vala
index 29ae6ae..8522e9c 100644
--- a/src/providers.vala
+++ b/src/providers.vala
@@ -24,7 +24,7 @@ public interface ImageProvider : GLib.Object {
         return null;
     }
 
-    public signal void image_updated ();
+    public signal void image_updated (string name);
 }
 
 // This is the default fallback provider
@@ -32,7 +32,7 @@ public class DefaultProvider : GLib.Object, ImageProvider {
     private static Gdk.Pixbuf? day_image;
     private static Gdk.Pixbuf? night_image;
 
-       public virtual Gdk.Pixbuf? get_image (string name) {
+    public virtual Gdk.Pixbuf? get_image (string name) {
         if (name.has_suffix ("-day")) {
             return day_image;
         } else if (name.has_suffix ("-night")) {
@@ -58,19 +58,27 @@ public class LocalImageProvider : GLib.Object, ImageProvider {
 
         File folder = File.new_for_path (folder_path);
 
+        if (!folder.query_exists ()) {
+            try {
+                folder.make_directory_with_parents ();
+            } catch (Error e) {
+                warning ("Could not create a city-images directory: %s", e.message);
+            }
+        }
+
         try {
             monitor = folder.monitor_directory (FileMonitorFlags.NONE, null);
-            stdout.printf ("Monitoring: %s\n", folder.get_path ());
 
             monitor.changed.connect ((src, dest, event) => {
+            /*
                 if (dest != null) {
                     stdout.printf ("%s: %s, %s\n", event.to_string (),
                                    src.get_path (), dest.get_path ());
                 } else {
                     stdout.printf ("%s: %s\n", event.to_string (), src.get_path ());
                 }
-
-                image_updated ();
+            */
+                image_updated (src.get_path ());
             });
         } catch (Error err) {
             warning ("Monitoring image files: %s\n", err.message);
@@ -84,42 +92,248 @@ public class LocalImageProvider : GLib.Object, ImageProvider {
             var path = GLib.Path.build_path (GLib.Path.DIR_SEPARATOR_S, folder_path, name + ".jpg");
 
             image = new Gdk.Pixbuf.from_file (path);
-               } catch (Error e) {
-            warning ("Loading image file: %s", e.message);
+        } catch (Error e) {
+            // warning ("Loading image file: %s", e.message);
+            image = null;
+        }
+
+        return image;
+    }
+}
+
+private class FlickrClient : GLib.Object {
+    private static const string api_key = "8fe23980339fd51887815d106d3d3498";
+    private static const string url = "http://www.flickr.com/groups/gnome-clocks/";;
+
+    private Soup.SessionAsync session;
+    private string query_message;
+
+    public string server { get; set; }
+    public string group_id { get; set; default = null; }
+
+    public FlickrClient () {
+        server = "http://api.flickr.com/services/rest/?format=json&nojsoncallback=1";;
+        query_message = @"$server&api_key=$api_key";
+
+        session = new Soup.SessionAsync ();
+        session.use_thread_context = true;
+    }
+
+    private async Json.Object? get_root_object (string message) {
+        GLib.InputStream stream;
+
+        string msg = query_message + message;
+        var query = new Soup.Message ("GET", msg);
+
+        try {
+            stream = yield session.send_async (query);
+        } catch (Error e) {
+            warning ("Unable to sent message: %s", e.message);
+            return null;
+        }
+
+        var parser = new Json.Parser ();
+
+        try {
+            yield parser.load_from_stream_async (stream);
+        } catch (Error e) {
+            warning ("Failed to load data from stream: %s", e.message);
+            return null;
+        }
+
+        var root_object = parser.get_root ().get_object ();
+
+        if (root_object.has_member ("stat")) {
+            string stat = root_object.get_string_member ("stat");
+
+            if (stat != "ok") {
+                warning ("Response from the server contains an error");
+                return null;
+            }
+        }
+
+        return root_object;
+    }
+
+    public async void seek_group_id () {
+        string msg = @"&method=flickr.urls.lookupGroup&url=$url";
+
+        var object = yield get_root_object (msg);
+
+        if (object == null) {
+            return;
+        }
+
+        if (object.has_member ("group")) {
+            var group = object.get_object_member ("group");
+            if (group.has_member ("id")) {
+                group_id = group.get_string_member ("id");
+            }
+        }
+    }
+
+    public async string? seek_image_id (string name) {
+        string msg = @"&method=flickr.groups.pools.getPhotos&group_id=$group_id";
+
+        var object = yield get_root_object (msg);
+
+        if (object == null) {
+            return null;
+        }
+
+        if (object.has_member ("photos")) {
+            var photos = object.get_object_member ("photos");
+            var node_list = photos.get_array_member ("photo").get_elements ();
+
+            foreach (var node in node_list) {
+                var photo = node.get_object ();
+                string title = photo.get_string_member ("title");
+                //stdout.printf (@"$title\n");
+                if (name == title) {
+                    string image_id = photo.get_string_member ("id");
+                    return image_id;
+                }
+            }
+        }
+        return null;
+    }
+
+    public async string? seek_image_uri (string image_id) {
+        string msg = @"&method=flickr.photos.getSizes&photo_id=$image_id";
+
+        var object = yield get_root_object (msg);
+
+        if (object == null) {
+            return null;
+        }
+
+        if (object.has_member ("sizes")) {
+            var sizes = object.get_object_member ("sizes");
+            var node_list = sizes.get_array_member ("size").get_elements ();
+
+            foreach (var node in node_list) {
+                var image = node.get_object ();
+                string label = image.get_string_member ("label");
+                //stdout.printf (@"$label\n");
+                if (label == "Original") {
+                    string image_url = image.get_string_member ("source");
+                    return image_url;
+                }
+            }
+        }
+        return null;
+    }
+}
+
+public class FlickrImageProvider : GLib.Object, ImageProvider {
+    private string folder_path;
+    private FlickrClient flickr_client;
+
+    public FlickrImageProvider () {
+        folder_path = GLib.Path.build_path (GLib.Path.DIR_SEPARATOR_S,
+                                            GLib.Environment.get_user_data_dir (),
+                                            "gnome-clocks", "city-images", "flickr");
+
+        File folder = File.new_for_path (folder_path);
+
+        if (!folder.query_exists ()) {
+            try {
+                folder.make_directory_with_parents ();
+            } catch (Error e) {
+                warning ("Could not create a flickr directory: %s", e.message);
+            }
+        }
+
+        flickr_client = new FlickrClient ();
+    }
+
+    public Gdk.Pixbuf? get_image (string name) {
+        Gdk.Pixbuf? image = null;
+
+        try {
+            var path = GLib.Path.build_path (GLib.Path.DIR_SEPARATOR_S, folder_path, name + ".jpg");
+
+            image = new Gdk.Pixbuf.from_file (path);
+        } catch (Error e) {
+            image = null;
+
+            fetch_image (name, (obj, res) => {
+                fetch_image.end (res);
+            });
         }
 
         return image;
     }
+
+    private async void fetch_image (string name) {
+        if (flickr_client.group_id == null) {
+            yield flickr_client.seek_group_id ();
+        }
+
+        string? image_id = yield flickr_client.seek_image_id (name);
+
+        if (image_id == null) {
+            warning (@"Could not get image id for $name.");
+            return;
+        }
+
+        string? image_uri = yield flickr_client.seek_image_uri (image_id);
+
+        if (image_uri == null) {
+            warning (@"Could not get image uri for $name.");
+            return;
+        }
+
+        yield download_image (image_uri, name);
+    }
+
+    private async void download_image (string uri, string name) {
+        var target_path = GLib.Path.build_path (GLib.Path.DIR_SEPARATOR_S,
+                                                folder_path,
+                                                name + ".jpg");
+        var source = File.new_for_uri (uri);
+        var target = File.new_for_path (target_path);
+
+        try {
+            yield source.copy_async (target, FileCopyFlags.OVERWRITE);
+        } catch (Error e) {
+            warning ("Copying an image has failed: %s", e.message);
+            return;
+        }
+
+        image_updated (name);
+    }
 }
 
 public class AutomaticImageProvider : GLib.Object, ImageProvider {
-       private List<ImageProvider> providers;
+    private List<ImageProvider> providers;
 
     public AutomaticImageProvider () {
-               providers = new List<ImageProvider> ();
+        providers = new List<ImageProvider> ();
 
-               providers.prepend (new DefaultProvider ());
-               providers.prepend (new LocalImageProvider ());
+        providers.prepend (new DefaultProvider ());
+        providers.prepend (new FlickrImageProvider ());
+        providers.prepend (new LocalImageProvider ());
 
         foreach (var provider in providers) {
-            provider.image_updated.connect (() => {
-                image_updated ();
+            provider.image_updated.connect ((name) => {
+                image_updated (name);
             });
         }
-       }
+    }
 
-       public virtual Gdk.Pixbuf? get_image (string name) {
-               Gdk.Pixbuf? image = null;
+    public virtual Gdk.Pixbuf? get_image (string name) {
+        Gdk.Pixbuf? image = null;
 
-               foreach (ImageProvider provider in providers) {
-                       image = provider.get_image (name);
+        foreach (ImageProvider provider in providers) {
+            image = provider.get_image (name);
 
-                       if (image != null) {
-                               break;
-                       }
-               }
+            if (image != null) {
+                break;
+            }
+        }
 
-               return image;
+        return image;
     }
 }
 
diff --git a/src/world.vala b/src/world.vala
index 5745949..62fbe9f 100644
--- a/src/world.vala
+++ b/src/world.vala
@@ -19,7 +19,7 @@
 namespace Clocks {
 namespace World {
 
-private static AutomaticImageProvider image_provider;
+private static ImageProvider image_provider;
 
 private class Item : Object, ContentItem {
     public GWeather.Location location { get; set; }
@@ -149,17 +149,20 @@ private class Item : Object, ContentItem {
 
         image_provider.image_updated.connect (update_images);
 
-        update_images ();
+        update_images (file_name);
 
         tick ();
     }
 
-    public void update_images () {
-        day_pixbuf = image_provider.get_image (file_name + "-day");
-        scaled_day_pixbuf = day_pixbuf.scale_simple (256, 256, Gdk.InterpType.BILINEAR);
+    public void update_images (string name) {
+        if (file_name in name) {
+            //stdout.printf (@"YES--file name $file_name and name $name\n");
+            day_pixbuf = image_provider.get_image (file_name + "-day");
+            scaled_day_pixbuf = day_pixbuf.scale_simple (256, 256, Gdk.InterpType.BILINEAR);
 
-        night_pixbuf = image_provider.get_image (file_name + "-night");
-        scaled_night_pixbuf = night_pixbuf.scale_simple (256, 256, Gdk.InterpType.BILINEAR);
+            night_pixbuf = image_provider.get_image (file_name + "-night");
+            scaled_night_pixbuf = night_pixbuf.scale_simple (256, 256, Gdk.InterpType.BILINEAR);
+        }
     }
 
     public void tick () {
@@ -270,10 +273,13 @@ private class StandalonePanel : Gtk.EventBox {
         sunset_label = builder.get_object ("sunset_label") as Gtk.Label;
 
         var overlay = new Gtk.Overlay ();
+        var scrolled_window = new Gtk.ScrolledWindow (null, null);
+        scrolled_window.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER);
         city_image = new Gtk.Image ();
         city_image.halign = Gtk.Align.FILL;
         city_image.valign = Gtk.Align.FILL;
-        overlay.add (city_image);
+        scrolled_window.add (city_image);
+        overlay.add (scrolled_window);
         overlay.add_overlay (grid);
 
         city_image.size_allocate.connect (on_size_allocate);


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