Clickable calendar button: add lift to calendar
[beifahrer] / src / lift-detail-window.vala
1 /* This file is part of Beifahrer.
2  *
3  * Copyright (C) 2010 Philipp Zabel
4  *
5  * Beifahrer is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Beifahrer is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Beifahrer. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 using Gtk;
20 using Hildon;
21
22 public class LiftDetailWindow : StackableWindow {
23         private const string BROWSER_SERVICE = "com.nokia.osso_browser";
24         private const string BROWSER_PATH = "/com/nokia/osso_browser";
25         private const string BROWSER_IF = "com.nokia.osso_browser";
26
27         private const string CALENDAR_SERVICE = "com.nokia.calendar";
28         private const string CALENDAR_PATH = "/com/nokia/calendar";
29         private const string CALENDAR_IF = "com.nokia.calendar";
30
31         AdacMitfahrclub adac;
32         Lift lift;
33         OssoABook.Button button_route;
34         OssoABook.Button button_calendar;
35         Label label_driver;
36         OssoABook.Button button_phone;
37         OssoABook.Button button_sms;
38         Image image_smoke;
39         Label label;
40         string ics_filename = null;
41
42         public LiftDetailWindow (AdacMitfahrclub _adac, Lift _lift) {
43                 adac = _adac;
44                 lift = _lift;
45
46                 update_lift_details ();
47
48                 if (lift.description == null)
49                         get_lift_details.begin ();
50         }
51
52         construct {
53                 set_title ("Beifahrer");
54
55                 var menu = new AppMenu ();
56                 var add_contact = new Gtk.Button.with_label (_("New contact"));
57                 add_contact.show ();
58                 menu.append (add_contact);
59                 var goto_website = new Gtk.Button.with_label (_("Show website"));
60                 goto_website.show ();
61                 menu.append (goto_website);
62                 set_main_menu (menu);
63
64                 var pannable = new PannableArea ();
65                 pannable.hscrollbar_policy = PolicyType.NEVER;
66
67                 var vbox = new VBox (false, 0);
68
69                 button_route = new OssoABook.Button (SizeType.FINGER_HEIGHT);
70                 button_route.style = OssoABook.ButtonStyle.LABEL;
71
72                 var table = new Table (5, 2, false);
73
74                 button_calendar = new OssoABook.Button (SizeType.FINGER_HEIGHT);
75                 button_calendar.set_icon_name ("general_calendar");
76                 button_calendar.set_icon_visible (true);
77                 button_calendar.title = _("Departure time");
78
79                 label_driver = new Label (_("Driver:"));
80                 label_driver.set_alignment (0.0f, 0.5f);
81
82                 button_phone = new OssoABook.Button (SizeType.FINGER_HEIGHT);
83                 button_phone.set_icon_name ("general_call");
84                 button_phone.set_icon_visible (true);
85                 button_phone.title = _("Phone");
86
87                 button_sms = new OssoABook.Button (SizeType.FINGER_HEIGHT);
88                 button_sms.set_icon_name ("general_sms");
89                 button_sms.set_icon_visible (true);
90                 button_sms.title = _("SMS");
91
92                 image_smoke = new Image ();
93
94                 label = new Label ("");
95                 label.set_alignment (0.0f, 0.5f);
96                 label.set_line_wrap (true);
97
98                 table.attach (button_calendar, 1, 2, 0, 1, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
99                 table.attach (label_driver, 0, 1, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, MARGIN_DEFAULT, 0);
100                 table.attach (button_phone, 1, 2, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
101                 table.attach (button_sms, 1, 2, 2, 3, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
102                 table.attach (image_smoke, 1, 2, 3, 4, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
103                 table.attach (label, 0, 2, 4, 5, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, MARGIN_DEFAULT, 0);
104
105                 vbox.pack_start (button_route, true, true, 0);
106                 vbox.pack_start (table, true, true, 0);
107
108                 pannable.add_with_viewport (vbox);
109
110                 add (pannable);
111
112                 add_contact.clicked.connect (on_add_contact_clicked);
113                 goto_website.clicked.connect (on_goto_website_clicked);
114                 button_calendar.clicked.connect (on_button_calendar_clicked);
115                 button_phone.clicked.connect (on_button_phone_clicked);
116                 button_sms.clicked.connect (on_button_sms_clicked);
117                 destroy.connect (on_destroy);
118         }
119
120         private async void get_lift_details () {
121                 Hildon.gtk_window_set_progress_indicator (this, 1);
122                 yield adac.update_lift_details (lift);
123                 Hildon.gtk_window_set_progress_indicator (this, 0);
124
125                 update_lift_details ();
126         }
127
128         private void update_lift_details () {
129                 button_route.title = _("From %s to %s").printf (lift.city_from, lift.city_to);
130                 if (lift.city_via.length () > 0) {
131                         string route = _("via ");
132                         foreach (string via in lift.city_via)
133                                 route += via + " ";
134                         button_route.value = route;
135                 } else {
136                         button_route.value = "";
137                 }
138
139                 button_calendar.value = "%02d.%02d.%04d, %d:%02d".printf (lift.time.day, lift.time.month, lift.time.year, lift.time.hour, lift.time.minute);
140
141                 label_driver.set_text (_("Driver: ") + lift.name);
142                 if (lift.cell != null) {
143                         button_phone.title = _("Cell");
144                         string cell_number = E.normalize_phone_number (lift.cell);
145                         button_phone.value = cell_number;
146                         button_sms.value = cell_number;
147                 } else if (lift.phone != null) {
148                         button_phone.title = _("Phone");
149                         string phone_number = E.normalize_phone_number (lift.phone);
150                         button_phone.value = phone_number;
151                         button_sms.value = phone_number;
152                 }
153
154                 string lift_text = _("Free places: %d\n").printf (lift.places);
155                 lift_text += (lift.price != null) ? _("Price: %s\n").printf (lift.price) : _("(no price given)\n");
156                 if (LiftFlags.SMOKER in lift.flags) try {
157                         var pixbuf = IconTheme.get_default ().load_icon ("beifahrer_smoker", 32, IconLookupFlags.NO_SVG);
158                         image_smoke.pixbuf = pixbuf;
159                         lift_text += _("smoker ");
160                 } catch (Error e) {
161                 } else if (LiftFlags.NON_SMOKER in lift.flags) try {
162                         var pixbuf = IconTheme.get_default ().load_icon ("beifahrer_non_smoker", 32, IconLookupFlags.NO_SVG);
163                         image_smoke.pixbuf = pixbuf;
164                         lift_text += _("non-smoker ");
165                 } catch (Error e) {
166                 }
167                 if (LiftFlags.ADAC_MEMBER in lift.flags)
168                         lift_text += _("ADAC member ");
169                 if (LiftFlags.WOMEN_ONLY in lift.flags)
170                         lift_text += _("only women ");
171                 lift_text += "\n\n" + lift.description;
172
173                 if (lift.modified != null)
174                         lift_text += _("\nLast changed: ") + lift.modified;
175
176                 label.set_text (lift_text);
177         }
178
179         void on_button_calendar_clicked () {
180                 var ical = new StringBuilder ("BEGIN:VCALENDAR\nVERSION:2.0\nMETHOD:PUBLISH\nBEGIN:VEVENT\nUID:");
181                 ical.append ("beifahrer" + lift.href); // UID
182                 ical.append ("\nCLASS:PUBLIC\nSUMMARY:");
183                 ical.append_printf (_("From %s to %s with %s"), lift.city_from, lift.city_to, lift.name);
184                 ical.append ("\nDTSTART;TZID=Europe/Berlin:");
185                 ical.append_printf ("%04d%02d%02dT%02d%02d00", lift.time.year + 2000, lift.time.month, lift.time.day, lift.time.hour, lift.time.minute);
186                 ical.append ("\nDTEND;TZID=Europe/Berlin:");
187                 ical.append_printf ("%04d%02d%02dT%02d%02d00", lift.time.year + 2000, lift.time.month, lift.time.day, lift.time.hour, lift.time.minute);
188                 ical.append ("\nDESCRIPTION:");
189                 ical.append (lift.description.replace ("\n", "\\n"));
190                 ical.append ("\nEND:VEVENT\nEND:VCALENDAR\n");
191
192                 ics_filename = Path.build_path ("/", Environment.get_tmp_dir (),
193                                                 "beifahrer.ics");
194                 try {
195                         FileUtils.set_contents (ics_filename, ical.str);
196                 } catch (FileError e) {
197                         stderr.printf ("Failed to write %s: %s\n", ics_filename, e.message);
198                         return;
199                 }
200
201                 var error = DBus.RawError ();
202                 var bus = DBus.RawBus.get (DBus.BusType.SESSION, ref error);
203                 var res = HildonMime.open_file (bus, "file://" + ics_filename);
204         }
205
206         void on_destroy () {
207                 if (ics_filename != null)
208                         FileUtils.remove (ics_filename);
209         }
210
211         void on_button_phone_clicked () {
212                 var uri = "tel://";
213                 if (lift.cell != null)
214                         uri += E.normalize_phone_number (lift.cell);
215                 else if (lift.phone != null)
216                         uri += E.normalize_phone_number (lift.phone);
217                 try {
218                         var action = URIAction.get_default_action_by_uri (uri);
219                         if (action != null) {
220                                 action.open (uri);
221                         } else {
222                                 
223                                 Banner.show_information (this, null, _("Couldn't call %s URI").printf (uri));
224                         }
225                 } catch (Error e) {
226                         if (e is URIError) {
227                                 Banner.show_information (this, null, _("Error: %s").printf (e.message));
228                         }
229                 }
230         }
231
232         void on_button_sms_clicked () {
233                 var uri = "sms://";
234                 if (lift.cell != null)
235                         uri += E.normalize_phone_number (lift.cell);
236                 else if (lift.phone != null)
237                         uri += E.normalize_phone_number (lift.phone);
238                 try {
239                         var action = URIAction.get_default_action_by_uri (uri);
240                         if (action != null) {
241                                 action.open (uri);
242                         } else {
243                                 
244                                 Banner.show_information (this, null, _("Couldn't open %s URI").printf (uri));
245                         }
246                 } catch (Error e) {
247                         if (e is URIError) {
248                                 Banner.show_information (this, null, _("Error: %s").printf (e.message));
249                         }
250                 }
251         }
252
253         void on_add_contact_clicked () {
254                 var contact = new OssoABook.Contact ();
255                 var attr_fn = new E.VCardAttribute (null, E.EVC_FN);
256                 contact.add_attribute_with_value ((owned) attr_fn, lift.name);
257                 if (lift.cell != null) {
258                         var attr_cell = new E.VCardAttribute (null, E.EVC_TEL);
259                         var param = new E.VCardAttributeParam (E.EVC_TYPE);
260                         attr_cell.add_param_with_value ((owned) param, "CELL");
261                         contact.add_attribute_with_value ((owned) attr_cell, E.normalize_phone_number (lift.cell));
262                 }
263                 if (lift.phone != null) {
264                         var attr_phone = new E.VCardAttribute (null, E.EVC_TEL);
265                         var param = new E.VCardAttributeParam (E.EVC_TYPE);
266                         attr_phone.add_param_with_value ((owned) param, "VOICE");
267                         contact.add_attribute_with_value ((owned) attr_phone, E.normalize_phone_number (lift.phone));
268                 }
269                 var dialog = new OssoABook.TemporaryContactDialog.with_contact (this, contact);
270                 dialog.show ();
271         }
272
273         void on_goto_website_clicked () {
274                 var url = "http://mitfahrclub.adac.de" + lift.href;
275
276                 try {
277                         var conn = DBus.Bus.get (DBus.BusType.SESSION);
278
279                         dynamic DBus.Object browser = conn.get_object (BROWSER_SERVICE, BROWSER_PATH, BROWSER_IF);
280                         browser.open_new_window (url, false);
281                 } catch (Error e) {
282                         stderr.printf ("Error: %s\n", e.message);
283                         Banner.show_information (this, null, _("Failed to open browser."));
284                 }
285         }
286 }