Merge commit 'upstream/0.2.85' 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         public override void get_conversation(Status status) {
230                 debug(status.id);
231                 
232                 //get status and send signal to cintent_view
233                 rec_reply = new RecursiveReply(proxy, status, s_name);
234                 /*
235                 rec_reply.new_reply.connect((rstatus, sid) => {
236                         //insert_reply(shash, sid, rstatus); //signal
237                         debug(rstatus.id);
238                 });*/
239                 rec_reply.run();
240         }
241         
242         public override void go_hashtag(string tag) {
243                 HashMap<string, string> map = new HashMap<string, string>();
244                 map["s-keyword"] = "#" + tag;
245                 add_stream(StreamEnum.SEARCH, true, map);
246         }
247         
248         protected void load_userpic_thread() {
249                 try {
250                         unowned Thread thread = Thread.create(load_userpic, true);
251                 } catch(GLib.Error e) {
252                         debug(e.message); //TODO
253                 }
254         }
255         
256         private void* load_userpic() {
257                 if(s_avatar_url == "")
258                         Thread.usleep(5000);
259                 
260                 string? img_path = img_cache.download(s_avatar_url);
261                 if(img_path != null) {
262                         debug("%s, %s", img_path, s_avatar_url);
263                         Idle.add(() => {
264                                 try {
265                                         userpic = new Gdk.Pixbuf.from_file(img_path);
266                                 } catch(GLib.Error e) {
267                                         debug(e.message); //TODO
268                                 }
269                                 return false;
270                         });
271                 }
272                 
273                 debug("loading userpic");
274                 return null;
275         }
276         
277         public override void send_status(string status_text, string reply_id) {
278                 debug("%s (%s): status sent".printf(this.s_name, this.id));
279                 
280                 Rest.ProxyCall call = proxy.new_call();
281                 call.add_param("status", status_text);
282                 
283                 if(reply_id != "")
284                         call.add_param("in_reply_to_status_id", reply_id);
285                 
286                 call.set_function("statuses/update.xml");
287                 call.set_method("POST");
288                 
289                 Rest.ProxyCallAsyncCallback callback = status_sent_respose;
290                 call.run_async(callback, this);
291         }
292         
293         protected void status_sent_respose(Rest.ProxyCall call, Error? error, Object? obj) {
294                 debug("ok");
295                 
296                 status_sent(this, true);
297                 
298                 foreach(AStream stream in streams) {
299                         if(stream.stream_type == StreamEnum.HOME) {
300                                 ((StreamAbstract) stream).sync();
301                                 break;
302                         }
303                 }
304         }
305         
306         protected override void menu_do_favorite(Status status) {
307                 Rest.ProxyCall call = proxy.new_call();
308                 call.set_method("POST");
309                 
310                 if(status.favorited) {
311                         message_indicate(_("Removing from favorites...")); //signal
312                         call.set_function("favorites/destroy/%s.xml".printf(status.id));
313                 }
314                 else {
315                         message_indicate(_("Adding to favorites...")); //signal
316                         call.set_function("favorites/create/%s.xml".printf(status.id));
317                 }
318                 
319                 Rest.ProxyCallAsyncCallback callback = ((c, e, o) => {
320                         if(c.get_status_code() == 200) {
321                                 Status fstatus = Twitter.Parser.get_status_from_string(c.get_payload(),
322                                         s_name);
323                                 
324                                 if(fstatus != null) {
325                                         foreach(Status real_status in get_statuses(fstatus.id)) {
326                                                 if(real_status != null) {
327                                                         real_status.favorited = !real_status.favorited;
328                                                         debug("invert");
329                                                 }
330                                         }
331                                 }
332                         }
333                         
334                         stop_indicate(); //signal
335                 });
336                 
337                 call.run_async(callback, this);
338         }
339         
340         protected override void menu_do_retweet(Status status) {
341                 Rest.ProxyCall call = proxy.new_call();
342                 call.set_method("POST");
343                 
344                 message_indicate(_("Making retweet...")); //signal
345                 
346                 call.set_function("statuses/retweet/%s.xml".printf(status.id));
347                 
348                 Rest.ProxyCallAsyncCallback callback = ((c, e, o) => {
349                         if(c.get_status_code() != 200) {
350                                 //TODO
351                         }
352                         
353                         stop_indicate(); //signal
354                 });
355                 
356                 call.run_async(callback, this);
357         }
358         
359         protected override void menu_do_remove(Status status) {
360                 Rest.ProxyCall call = proxy.new_call();
361                 call.set_method("POST");
362                 
363                 message_indicate(_("Removing status...")); //signal
364                 
365                 call.set_function("statuses/destroy/%s.xml".printf(status.id));
366                 
367                 Rest.ProxyCallAsyncCallback callback = ((c, e, o) => {
368                         if(c.get_status_code() != 200) {
369                                 //TODO
370                                 return;
371                         }
372                         
373                         Status fstatus = Twitter.Parser.get_status_from_string(c.get_payload(),
374                                         s_name);
375                         
376                         if(fstatus != null) {
377                                 remove_status_complete(fstatus.id);
378                         }
379                         
380                         stop_indicate(); //signal
381                 });
382                 
383                 call.run_async(callback, this);
384         }
385         
386         protected override void menu_do_reply(Status status) {
387                 if(!status.own)
388                         do_reply(this, status); //signal
389         }
390 }
391
392 }