Merge branch 'upstream' into experimental
[debian/pino.git] / src / twitter_account.vala
1 using Gee;
2 using PinoEnums;
3 using RestCustom;
4
5 namespace Twitter {
6
7 public class Account : AAccount {
8         
9         protected virtual string consumer_key {get; set; default = "Rcy44V1o5z8j68UHgmWHA";}
10         protected virtual string consumer_secret {get; set; default = "CsqwYwk3qWFHCbB4fZvpqS0VTHSTVlOIRy1SMj1GjQ";}
11         protected Rest.Proxy proxy;
12         
13         protected virtual string root_url {get; set; default = "http://twitter.com/";}
14         protected virtual string search_url {get; set; default = "http://search.twitter.com/";}
15         
16         //protected virtual string service_icon {get; set; default = accounts_types[get_type()].name}
17         //protected virtual string service_icon {get; set; default = "Twitter";}
18         
19         public string s_token {get; set; default = "";}
20         public string s_token_secret {get; set; default = "";}
21
22         public override MenuItems[] popup_items {
23                 owned get {
24                         return {
25                                 MenuItems.SETTINGS,
26                                 MenuItems.REMOVE
27                         };
28                 }
29         }
30         
31         public override StatusMenuItems[] status_popup_items {
32                 owned get {
33                         return {
34                                 StatusMenuItems.REPLY,
35                                 StatusMenuItems.RETWEET,
36                                 StatusMenuItems.FAVORITE,
37                                 StatusMenuItems.REMOVE
38                         };
39                 }
40         }
41         
42         protected override HashMap<StreamEnum, GLib.Type> avaliable_streams {
43                 owned get {
44                         HashMap<StreamEnum, GLib.Type> map = new HashMap<StreamEnum, GLib.Type>();
45
46                         map.set(StreamEnum.HOME, typeof(Twitter.StreamHome));
47                         map.set(StreamEnum.MENTIONS, typeof(Twitter.StreamMentions));
48                         map.set(StreamEnum.PUBLIC, typeof(Twitter.StreamPublic));
49                         map.set(StreamEnum.FAVORITES, typeof(Twitter.StreamFavorites));
50                         map.set(StreamEnum.SEARCH, typeof(Twitter.StreamSearch));
51                         return map;
52                 }
53         }
54         
55         protected override StreamEnum[] default_streams {
56                 owned get {
57                         return {
58                                 StreamEnum.HOME,
59                                 StreamEnum.MENTIONS
60                         };
61                 }
62         }
63         
64         protected RecursiveReply rec_reply;
65         
66         construct {
67         }
68         
69         public override string id {get; set; default = "twitter";}
70         
71         protected override void init_stream(AStream stream) {
72                 debug("init stream");
73                 
74                 if(s_token != "") {
75                         if(stream.get_type().name() == "TwitterStreamSearch") { //setup searches
76                                 if(((StreamSearch) stream).s_keyword == "") {
77                                         SearchDialog s_dialog = new SearchDialog();
78                                         if(s_dialog.run() == Gtk.ResponseType.OK) {
79                                                 ((StreamSearch) stream).s_keyword = s_dialog.input.get_text();
80                                                 s_dialog.close();
81                                         } else { //remove stream
82                                                 int index = streams.index_of(stream);
83                                                 streams_actions_tracker(index, MenuItems.REMOVE);
84                                                 s_dialog.close();
85                                                 return;
86                                         }
87                                 }
88                                 
89                                 Rest.Proxy search_proxy = new Rest.Proxy(search_url, false);
90                                 ((Twitter.StreamAbstract) stream).set_proxy(search_proxy, s_name);
91                         } else {
92                                 ((Twitter.StreamAbstract) stream).set_proxy(proxy, s_name);
93                         }
94                 }
95         }
96         
97         public override void post_install() {
98                 //create proxy
99                 if(s_token != "") {
100                         proxy = new OAuthProxy.with_token(consumer_key, consumer_secret,
101                                 s_token, s_token_secret, root_url, false);
102                 }
103                 
104                 //load userpic
105                 load_userpic_thread();
106                 
107                 //setp proxies to all streams
108                 foreach(AStream stream in streams) {
109                         init_stream(stream);
110                 }
111         }
112         
113         public override bool create(Gtk.Window w) {
114                 debug("trying to create account");
115                 debug(consumer_key);
116                 CreateDialog create_dlg = new CreateDialog(w, root_url, consumer_key,
117                         consumer_secret, accounts_types[get_type()].icon_name,
118                         accounts_types[get_type()].name);
119                 
120                 if(create_dlg.run() == Gtk.ResponseType.OK) {
121                         base.create(w);
122                         
123                         s_token = create_dlg.s_token;
124                         s_token_secret = create_dlg.s_token_secret;
125                         s_name = create_dlg.s_name;
126                         s_avatar_url = create_dlg.s_avatar_url;
127                         
128                         load_userpic_thread();
129                         
130                         create_dlg.close();
131                         
132                         proxy = new OAuthProxy.with_token(consumer_key, consumer_secret,
133                                 s_token, s_token_secret, root_url, false);
134                         
135                         return true;
136                 }
137                 
138                 create_dlg.close();
139                 return false;
140         }
141         
142         public override AStream? new_content_action(string action_type,
143                 string stream_hash, string val) {
144                 
145                 switch(action_type) {
146                 case "search":
147                         HashMap<string, string> map = new HashMap<string, string>();
148                         map["s-keyword"] = "#" + val;
149                         add_stream(StreamEnum.SEARCH, true, map);
150                         return null;
151                 
152                 /*
153                 case "reply":
154                         Status? status = null;
155                         foreach(AStream stream in streams) {
156                                 if(get_stream_hash(stream) == stream_hash) {
157                                         status = get_status(stream.stream_type, val);
158                                 }
159                         }
160                         
161                         if(status != null)
162                                 menu_do_reply(status);
163                         break;
164                 */
165                 /*
166                 case "context":
167                         Status? status = null;
168                         foreach(AStream stream in streams) {
169                                 if(get_stream_hash(stream) == stream_hash) {
170                                         status = get_status(stream.stream_type, val);
171                                         break;
172                                 }
173                         }
174                         
175                         if(status == null)
176                                 return null;
177                         
178                         debug(status.id);
179                         
180                         //get status and send signal to cintent_view
181                         rec_reply = new RecursiveReply(proxy, status, s_name,
182                                 stream_hash);
183                         rec_reply.new_reply.connect((rstatus, shash, sid) => {
184                                 insert_reply(shash, sid, rstatus); //signal
185                         });
186                         rec_reply.run();
187                         
188                         break;
189                 */
190                 /*
191                 case "contextmenu":
192                         debug("menu");
193                         AStream? stream = null;
194                         Status? status = null;
195                         foreach(AStream astream in streams) {
196                                 if(get_stream_hash(astream) == stream_hash) {
197                                         stream = astream;
198                                         
199                                         foreach(Status astatus in stream.statuses_fresh) {
200                                                 if(astatus.id == val) {
201                                                         status = astatus;
202                                                         break;
203                                                 }
204                                         }
205                                         if(status == null) {
206                                                 foreach(Status astatus in stream.statuses) {
207                                                         if(astatus.id == val) {
208                                                                 status = astatus;
209                                                                 break;
210                                                         }
211                                                 }
212                                         }
213                                         break;
214                                 }
215                         }
216                         
217                         if(stream != null && status != null)
218                                 context_menu(stream, status);
219                         else
220                                 debug("can't find this status");
221                         
222                         return null;
223                 */
224                 }
225                 
226                 return null;
227         }
228         
229         protected void load_userpic_thread() {
230                 try {
231                         unowned Thread thread = Thread.create(load_userpic, true);
232                 } catch(GLib.Error e) {
233                         debug(e.message); //TODO
234                 }
235         }
236         
237         private void* load_userpic() {
238                 if(s_avatar_url == "")
239                         Thread.usleep(5000);
240                 
241                 string? img_path = img_cache.download(s_avatar_url);
242                 if(img_path != null) {
243                         debug("%s, %s", img_path, s_avatar_url);
244                         Idle.add(() => {
245                                 try {
246                                         userpic = new Gdk.Pixbuf.from_file(img_path);
247                                 } catch(GLib.Error e) {
248                                         debug(e.message); //TODO
249                                 }
250                                 return false;
251                         });
252                 }
253                 
254                 debug("loading userpic");
255                 return null;
256         }
257         
258         public override void send_status(string status_text, string reply_id) {
259                 debug("%s (%s): status sent".printf(this.s_name, this.id));
260                 
261                 Rest.ProxyCall call = proxy.new_call();
262                 call.add_param("status", status_text);
263                 
264                 if(reply_id != "")
265                         call.add_param("in_reply_to_status_id", reply_id);
266                 
267                 call.set_function("statuses/update.xml");
268                 call.set_method("POST");
269                 
270                 Rest.ProxyCallAsyncCallback callback = status_sent_respose;
271                 call.run_async(callback, this);
272         }
273         
274         protected void status_sent_respose(Rest.ProxyCall call, Error? error, Object? obj) {
275                 debug("ok");
276                 
277                 status_sent(this, true);
278                 
279                 foreach(AStream stream in streams) {
280                         if(stream.stream_type == StreamEnum.HOME) {
281                                 ((StreamAbstract) stream).sync();
282                                 break;
283                         }
284                 }
285         }
286         
287         protected override void menu_do_favorite(Status status) {
288                 /*
289                 Rest.ProxyCall call = proxy.new_call();
290                 call.set_method("POST");
291                 
292                 if(status.favorited) {
293                         message_indicate(_("Removing from favorites...")); //signal
294                         call.set_function("favorites/destroy/%s.xml".printf(status.id));
295                 }
296                 else {
297                         message_indicate(_("Adding to favorites...")); //signal
298                         call.set_function("favorites/create/%s.xml".printf(status.id));
299                 }
300                 
301                 Rest.ProxyCallAsyncCallback callback = ((c, e, o) => {
302                         if(c.get_status_code() == 200) {
303                                 Status fstatus = Twitter.Parser.get_status_from_string(c.get_payload(),
304                                         s_name);
305                                 
306                                 if(fstatus != null) {
307                                         foreach(Status real_status in get_statuses(fstatus.id)) {
308                                                 if(real_status != null) {
309                                                         real_status.favorited = !real_status.favorited;
310                                                         debug("invert");
311                                                 }
312                                         }
313                                 }
314                         }
315                         
316                         stop_indicate(); //signal
317                 });
318                 
319                 call.run_async(callback, this);
320                 */
321         }
322         
323         protected override void menu_do_retweet(Status status) {
324                 Rest.ProxyCall call = proxy.new_call();
325                 call.set_method("POST");
326                 
327                 message_indicate(_("Making retweet...")); //signal
328                 
329                 call.set_function("statuses/retweet/%s.xml".printf(status.id));
330                 
331                 Rest.ProxyCallAsyncCallback callback = ((c, e, o) => {
332                         if(c.get_status_code() != 200) {
333                                 //TODO
334                         }
335                         
336                         stop_indicate(); //signal
337                 });
338                 
339                 call.run_async(callback, this);
340         }
341         
342         protected override void menu_do_remove(Status status) {
343                 /*
344                 Rest.ProxyCall call = proxy.new_call();
345                 call.set_method("POST");
346                 
347                 message_indicate(_("Removing status...")); //signal
348                 
349                 call.set_function("statuses/destroy/%s.xml".printf(status.id));
350                 
351                 Rest.ProxyCallAsyncCallback callback = ((c, e, o) => {
352                         if(c.get_status_code() != 200) {
353                                 //TODO
354                                 return;
355                         }
356                         
357                         Status fstatus = Twitter.Parser.get_status_from_string(c.get_payload(),
358                                         s_name);
359                         
360                         if(fstatus != null) {
361                                 remove_status_complete(fstatus.id);
362                         }
363                         
364                         stop_indicate(); //signal
365                 });
366                 
367                 call.run_async(callback, this);
368                 */
369         }
370         
371         protected override void menu_do_reply(Status status) {
372                 if(!status.own)
373                         do_reply(this, status); //signal
374         }
375 }
376
377 }