Mercurial repo sync
[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                 case "reply":
153                         Status? status = null;
154                         foreach(AStream stream in streams) {
155                                 if(get_stream_hash(stream) == stream_hash) {
156                                         status = get_status(stream.stream_type, val);
157                                 }
158                         }
159                         
160                         if(status != null)
161                                 menu_do_reply(status);
162                         break;
163                 
164                 
165                 case "context":
166                         Status? status = null;
167                         foreach(AStream stream in streams) {
168                                 if(get_stream_hash(stream) == stream_hash) {
169                                         status = get_status(stream.stream_type, val);
170                                         break;
171                                 }
172                         }
173                         
174                         if(status == null)
175                                 return null;
176                         
177                         debug(status.id);
178                         
179                         //get status and send signal to cintent_view
180                         rec_reply = new RecursiveReply(proxy, status, s_name,
181                                 stream_hash);
182                         rec_reply.new_reply.connect((rstatus, shash, sid) => {
183                                 insert_reply(shash, sid, rstatus); //signal
184                         });
185                         rec_reply.run();
186                         
187                         break;
188                 
189                 case "contextmenu":
190                         debug("menu");
191                         AStream? stream = null;
192                         Status? status = null;
193                         foreach(AStream astream in streams) {
194                                 if(get_stream_hash(astream) == stream_hash) {
195                                         stream = astream;
196                                         
197                                         foreach(Status astatus in stream.statuses_fresh) {
198                                                 if(astatus.id == val) {
199                                                         status = astatus;
200                                                         break;
201                                                 }
202                                         }
203                                         if(status == null) {
204                                                 foreach(Status astatus in stream.statuses) {
205                                                         if(astatus.id == val) {
206                                                                 status = astatus;
207                                                                 break;
208                                                         }
209                                                 }
210                                         }
211                                         break;
212                                 }
213                         }
214                         
215                         if(stream != null && status != null)
216                                 context_menu(stream, status);
217                         else
218                                 debug("can't find this status");
219                         
220                         return null;
221                 }
222                 
223                 return null;
224         }
225         
226         protected void load_userpic_thread() {
227                 try {
228                         unowned Thread thread = Thread.create(load_userpic, true);
229                 } catch(GLib.Error e) {
230                         debug(e.message); //TODO
231                 }
232         }
233         
234         private void* load_userpic() {
235                 if(s_avatar_url == "")
236                         Thread.usleep(5000);
237                 
238                 string? img_path = img_cache.download(s_avatar_url);
239                 if(img_path != null) {
240                         debug("%s, %s", img_path, s_avatar_url);
241                         Idle.add(() => {
242                                 try {
243                                         userpic = new Gdk.Pixbuf.from_file(img_path);
244                                 } catch(GLib.Error e) {
245                                         debug(e.message); //TODO
246                                 }
247                                 return false;
248                         });
249                 }
250                 
251                 debug("loading userpic");
252                 return null;
253         }
254         
255         public override void send_status(string status_text, string reply_id) {
256                 debug("%s (%s): status sent".printf(this.s_name, this.id));
257                 
258                 Rest.ProxyCall call = proxy.new_call();
259                 call.add_param("status", status_text);
260                 
261                 if(reply_id != "")
262                         call.add_param("in_reply_to_status_id", reply_id);
263                 
264                 call.set_function("statuses/update.xml");
265                 call.set_method("POST");
266                 
267                 Rest.ProxyCallAsyncCallback callback = status_sent_respose;
268                 call.run_async(callback, this);
269         }
270         
271         protected void status_sent_respose(Rest.ProxyCall call, Error? error, Object? obj) {
272                 debug("ok");
273                 
274                 status_sent(this, true);
275                 
276                 foreach(AStream stream in streams) {
277                         if(stream.stream_type == StreamEnum.HOME) {
278                                 ((StreamAbstract) stream).sync();
279                                 break;
280                         }
281                 }
282         }
283         
284         protected override void menu_do_favorite(Status status) {
285                 Rest.ProxyCall call = proxy.new_call();
286                 call.set_method("POST");
287                 
288                 if(status.favorited) {
289                         message_indicate(_("Removing from favorites...")); //signal
290                         call.set_function("favorites/destroy/%s.xml".printf(status.id));
291                 }
292                 else {
293                         message_indicate(_("Adding to favorites...")); //signal
294                         call.set_function("favorites/create/%s.xml".printf(status.id));
295                 }
296                 
297                 Rest.ProxyCallAsyncCallback callback = ((c, e, o) => {
298                         if(c.get_status_code() == 200) {
299                                 Status fstatus = Twitter.Parser.get_status_from_string(c.get_payload(),
300                                         s_name);
301                                 
302                                 if(fstatus != null) {
303                                         foreach(Status real_status in get_statuses(fstatus.id)) {
304                                                 if(real_status != null) {
305                                                         real_status.favorited = !real_status.favorited;
306                                                         debug("invert");
307                                                 }
308                                         }
309                                 }
310                         }
311                         
312                         stop_indicate(); //signal
313                 });
314                 
315                 call.run_async(callback, this);
316         }
317         
318         protected override void menu_do_retweet(Status status) {
319                 Rest.ProxyCall call = proxy.new_call();
320                 call.set_method("POST");
321                 
322                 message_indicate(_("Making retweet...")); //signal
323                 
324                 call.set_function("statuses/retweet/%s.xml".printf(status.id));
325                 
326                 Rest.ProxyCallAsyncCallback callback = ((c, e, o) => {
327                         if(c.get_status_code() != 200) {
328                                 //TODO
329                         }
330                         
331                         stop_indicate(); //signal
332                 });
333                 
334                 call.run_async(callback, this);
335         }
336         
337         protected override void menu_do_remove(Status status) {
338                 Rest.ProxyCall call = proxy.new_call();
339                 call.set_method("POST");
340                 
341                 message_indicate(_("Removing status...")); //signal
342                 
343                 call.set_function("statuses/destroy/%s.xml".printf(status.id));
344                 
345                 Rest.ProxyCallAsyncCallback callback = ((c, e, o) => {
346                         if(c.get_status_code() != 200) {
347                                 //TODO
348                                 return;
349                         }
350                         
351                         Status fstatus = Twitter.Parser.get_status_from_string(c.get_payload(),
352                                         s_name);
353                         
354                         if(fstatus != null) {
355                                 remove_status_complete(fstatus.id);
356                         }
357                         
358                         stop_indicate(); //signal
359                 });
360                 
361                 call.run_async(callback, this);
362         }
363         
364         protected override void menu_do_reply(Status status) {
365                 if(!status.own)
366                         do_reply(this, status); //signal
367         }
368 }
369
370 }