Google plugin: report D-Bus errors
[cinaest] / src / plugins / google-plugin.vala
index 7f26ad1..600c407 100644 (file)
 using Gtk;
 using Hildon;
 
+public class GoogleMovie : Movie {
+       public string cinema_name;
+       public string cinema_phone;
+       public int runtime;
+       public string showtimes;
+}
+
 class GooglePlugin : Plugin {
        List<MovieSource> sources;
+       SList<string> locations;
+       string last_location;
+       GConf.Client gconf;
 
        public override void hello (Gtk.Window window, Osso.Context context) {
                stdout.printf ("Google Plugin Loaded.\n");
@@ -30,6 +40,15 @@ class GooglePlugin : Plugin {
                sources = new List<MovieSource> ();
                sources.append (source);
 
+               locations = null;
+               gconf = GConf.Client.get_default ();
+               try {
+                       source.location = last_location = gconf.get_string ("/apps/cinaest/location");
+                       locations = gconf.get_list ("/apps/cinaest/locations", GConf.ValueType.STRING);
+               } catch (Error e) {
+                       stdout.printf ("Error getting GConf option: %s\n", e.message);
+               }
+
                // FIXME - this forces the inclusion of config.h
                (void) Config.GETTEXT_PACKAGE;
        }
@@ -38,20 +57,95 @@ class GooglePlugin : Plugin {
                return sources;
        }
 
-       public override List<MovieAction> get_actions (Movie movie) {
+       public override List<MovieAction> get_actions (Movie _movie, Gtk.Window window) {
                List<MovieAction> list = null;
+               var movie = _movie as GoogleMovie;
+
+               if (movie != null) {
+                       list.append (new MovieAction (_("Add to calendar"), on_add_calendar_event, movie, window));
+                       if (movie.cinema_phone != null)
+                               list.append (new MovieAction (_("Call cinema"), on_call_cinema, movie, window));
+               }
 
                return list;
        }
 
+       private void on_add_calendar_event (Movie _movie, Gtk.Window window) {
+               var movie = (GoogleMovie) _movie;
+
+               var dialog = new PickerDialog (window);
+               dialog.set_title (_("Add showtime to calendar"));
+
+               var selector = new TouchSelector.text ();
+               var showtimes = movie.showtimes.split (", ");
+               foreach (string s in showtimes) {
+                       selector.append_text (s);
+               }
+               dialog.set_selector (selector);
+
+               var res = dialog.run ();
+               if (res == ResponseType.OK) {
+                       string s = selector.get_current_text ();
+                        int hour = s.to_int ();
+                        int min = s.str (":").offset (1).to_int ();
+
+                       var showtime = time_t ();
+                       var timeinfo = Time.local (showtime);
+                       timeinfo.second = 0;
+                       timeinfo.minute = min;
+                       timeinfo.hour = hour;
+                       showtime = timeinfo.mktime ();
+
+                       int runtime = movie.runtime;
+                       if (runtime == 0) {
+                               // Default to 120min if we failed to parse the runtime
+                               runtime = 7200;
+                       }
+
+                       res = Calendar.add_event (movie.title, _("Movie"), movie.cinema_name, showtime, showtime + runtime);
+                       var banner = (Banner) Banner.show_information_with_markup (window, null, (res == 0) ?
+                                                                                  _("Added calendar event at %d:%02d").printf (hour, min) :
+                                                                                  _("Failed to add calendar event"));
+                       banner.set_timeout (1500);
+               }
+               dialog.destroy ();
+       }
+
+       private void on_call_cinema (Movie _movie, Gtk.Window window) {
+               var movie = (GoogleMovie) _movie;
+               var url = "tel://" + movie.cinema_phone;
+
+               try {
+                       var action = Hildon.URIAction.get_default_action_by_uri (url);
+                       if (action != null) {
+                               action.open (url);
+                       } else {
+                               var banner = (Banner) Banner.show_information_with_markup (window, null, "Failed to get tel:// URI action");
+                               banner.set_timeout (1500);
+                       }
+               } catch (Error e) {
+                       if (e is Hildon.URIError) {
+                               stdout.printf ("Error: %s\n", e.message);
+                       }
+               }
+       }
+
        public override void settings_dialog (Gtk.Window window) {
                GoogleSource source = (GoogleSource) sources.data;
                var dialog = new Gtk.Dialog ();
                dialog.set_transient_for (window);
                dialog.set_title (_("Google plugin settings"));
+               try {
+                       source.location = gconf.get_string ("/apps/cinaest/location");
+                       locations = gconf.get_list ("/apps/cinaest/locations", GConf.ValueType.STRING);
+               } catch (Error e) {
+                       stdout.printf ("Error getting GConf option: %s\n", e.message);
+               }
 
                var selector = new TouchSelectorEntry.text ();
-               selector.append_text ("Berlin");
+               insert_location_sorted (source.location);
+               foreach (string l in locations)
+                       selector.append_text (l);
 
                var button = new PickerButton (SizeType.FINGER_HEIGHT, ButtonArrangement.HORIZONTAL);
                button.set_title (_("Location"));
@@ -61,16 +155,42 @@ class GooglePlugin : Plugin {
                var content = (VBox) dialog.get_content_area ();
                content.pack_start (button, true, true, 0);
 
-               dialog.add_button ("Done", ResponseType.ACCEPT);
+               dialog.add_button (_("Done"), ResponseType.ACCEPT);
 
                dialog.show_all ();
                int res = dialog.run ();
                if (res == ResponseType.ACCEPT) {
                        source.location = button.get_value ();
+                       try {
+                               if (insert_location_sorted (source.location))
+                                       gconf.set_list ("/apps/cinaest/locations", GConf.ValueType.STRING, locations);
+                               if (source.location != last_location)
+                                       gconf.set_string ("/apps/cinaest/location", source.location);
+                       } catch (Error e) {
+                               stdout.printf ("Error setting GConf option: %s\n", e.message);
+                       }
                }
                dialog.destroy ();
        }
 
+       private bool insert_location_sorted (string? location) {
+               if (location == null)
+                       return false;
+               if (locations != null) {
+                       for (unowned SList<string> l = locations; l != null; l = l.next) {
+                               if (l.data == location) {
+                                       return false;
+                               }
+                               if (l.data > location) {
+                                       l.insert (location, 0);
+                                       return true;
+                               }
+                       }
+               }
+               locations.append (location);
+               return true;
+       }
+
        public override unowned string get_name () {
                return "Google";
        }
@@ -79,19 +199,93 @@ class GooglePlugin : Plugin {
 class GoogleSource : MovieSource {
        public string location;
        public string description;
+       public MovieSource.ReceiveMovieFunction callback;
+       dynamic DBus.Object search;
+
+       public override bool active { get; set construct; }
+
+       public GoogleSource () {
+               GLib.Object (active: true);
+       }
+
+       SourceFunc get_movies_callback;
+       public override async int get_movies (MovieFilter filter, MovieSource.ReceiveMovieFunction _callback, int limit, Cancellable? cancellable) {
+               try {
+                       string search_path;
+                       dynamic DBus.Object server;
+                       var conn = DBus.Bus.get (DBus.BusType.SESSION);
+
+                       server = conn.get_object ("org.maemo.cinaest.GoogleShowtimes",
+                                                 "/org/maemo/cinaest/googleshowtimes",
+                                                 "org.maemo.cinaest.MovieService");
+                       server.NewSearch (out search_path);
+
+                       search = conn.get_object ("org.maemo.cinaest.GoogleShowtimes",
+                                                 search_path,
+                                                 "org.maemo.cinaest.MovieSearch");
+
+                       callback = _callback;
+                       search.MoviesFound.connect (on_movies_found);
+                       search.start (filter.title);
+               } catch (Error e1) {
+                       Banner.show_information (null, null, e1.message);
+                       return 0;
+               }
 
-       public override async void get_movies (MovieFilter filter, MovieSource.ReceiveMovieFunction callback, int limit, Cancellable? cancellable) {
-               var parser = new GoogleParser ();
+               get_movies_callback = get_movies.callback;
+               if (cancellable != null)
+                       cancellable.cancelled.connect (() => { search.abort (); Idle.add (get_movies_callback); });
+               yield;
 
-               yield parser.query (filter, location, callback, cancellable);
-               if (location == null) {
-                       location = parser.location;
+               var gc = GConf.Client.get_default ();
+               try {
+                       location = gc.get_string ("/apps/cinaest/location");
+               } catch (Error e) {
+                       stdout.printf ("Error getting GConf option: %s\n", e.message);
+               }
+
+               return 1 /*n*/;
+       }
+
+       private void on_movies_found (DBus.Object sender, string[] movies, bool finished) {
+               print ("found %d movies\n", movies.length);
+               var parser = new Json.Parser ();
+
+               for (int i = 0; i < movies.length; i++) {
+                       var movie = new GoogleMovie ();
+                       try {
+                               parser.load_from_data (movies[i], -1);
+                       } catch (Error e) {
+                               stderr.printf ("Error: %s\n%s\n", e.message, movies[i]);
+                       }
+
+                       var object = parser.get_root ().get_object ();
+                       movie.title = object.get_string_member ("title");
+                       movie.rating = (int) object.get_double_member ("rating");
+                       movie.cinema_name = object.get_string_member ("cinema_name");
+                       movie.cinema_phone = object.get_string_member ("cinema_phone");
+                       movie.runtime = (int) object.get_int_member ("runtime");
+                       movie.showtimes = object.get_string_member ("showtimes");
+                       if (movie.runtime > 0)
+                               movie.secondary = "%d min - %s - %s".printf (movie.runtime / 60, movie.cinema_name, movie.showtimes);
+                       else
+                               movie.secondary = movie.cinema_name + " - " + movie.showtimes;
+
+                       callback (movie);
+               }
+
+               if (finished) {
+                       search = null;
+                       Idle.add (get_movies_callback);
                }
        }
 
        public override void add_movie (Movie movie) {
        }
 
+       public override void delete_movie (Movie movie) {
+       }
+
        public override unowned string get_name () {
                return _("Google");
        }
@@ -111,7 +305,7 @@ class GoogleSource : MovieSource {
 }
 
 [ModuleInit]
-public Type register_plugin () {
+public Type register_plugin (TypeModule module) {
        // types are registered automatically
        return typeof (GooglePlugin);
 }