22
22
namespace GwibberGtk
24
public class StreamViewAvatar : Gtk.Image
26
public StreamViewAvatar()
28
draw.connect (on_draw);
31
private bool on_draw (Cairo.Context cr)
34
get_allocation(out alloc);
37
cr.move_to(0, radius);
38
cr.curve_to(0, 0, 0, 0, radius, 0);
39
cr.line_to(alloc.width - radius, 0);
40
cr.curve_to(alloc.width, 0, alloc.width, 0, alloc.width, radius);
41
cr.line_to(alloc.width, alloc.height - radius);
42
cr.curve_to(alloc.width, alloc.height, alloc.width, alloc.height, alloc.width - radius, alloc.height);
43
cr.line_to(radius, alloc.height);
44
cr.curve_to(0, alloc.height, 0, alloc.height, 0, alloc.height - radius);
24
54
public class StreamViewTile : Gtk.EventBox
26
56
private const int our_padding = 6;
30
60
private Gtk.Alignment lalignment;
31
61
private Gtk.Alignment ralignment;
32
62
private Gtk.EventBox icon_box;
33
private Gtk.Image icon;
63
private StreamViewAvatar icon;
34
64
private Gtk.Image private;
35
65
private Gtk.VBox vbox;
66
private Gtk.VBox comments_box;
36
67
private Gtk.HBox likes_hbox;
37
68
private Gtk.Label likes_count;
38
69
private new Gtk.Label name;
39
70
//private new Gtk.Label source;
40
71
private Gtk.Label time;
41
72
private Gtk.Label message;
73
private StreamViewAvatar thumbnail;
74
private Gtk.EventBox thumb_box;
42
75
private Gtk.Label reply_to;
43
76
private Gtk.Label retweeted_by;
44
77
public Gwibber.Utils utils { get; construct set; }
78
public Gwibber.Service service { get; construct set; }
45
79
public bool show_fullname { get; construct set; }
46
80
private uint _update_time_area_id = 0;
81
private uint _cache_avatar_id = 0;
82
private List<uint> _to_disconnect;
48
84
public uint uid = 0;
55
91
private GwibberGtk.ActionBox action_box;
57
public StreamViewTile (Gwibber.Utils utils, bool show_fullname)
93
private Cancellable cancellable;
94
private string img_uri;
95
private string img_src;
98
public StreamViewTile (Gwibber.Utils utils, Gwibber.Service service, bool show_fullname)
59
Object (above_child:false, visible_window:false, utils:utils, show_fullname:show_fullname);
100
Object (above_child:false, visible_window:false, utils:utils, service:service, show_fullname:show_fullname);
105
_to_disconnect = new GLib.List<uint> ();
64
106
draw.connect (on_draw);
66
108
align = new Gtk.Alignment (0.0f, 0.0f, 1.0f, 1.0f);
211
thumb_box = new Gtk.EventBox ();
212
thumb_box.set_visible_window (false);
213
thumb_box.set_no_show_all(true);
214
var thumb_hbox = new Gtk.HBox (false, 2);
215
vbox.pack_start(thumb_hbox, false, false, 4);
216
thumb_hbox.pack_start(thumb_box, false, false, 4);
217
thumb_box.button_release_event.connect(() =>
220
Gtk.show_uri(Gdk.Screen.get_default(), img_src, 0);
224
thumbnail = new StreamViewAvatar();
225
thumbnail.set_no_show_all(true);
226
thumb_box.add(thumbnail);
229
comments_box = new Gtk.VBox (false, 0);
230
comments_box.set_no_show_all (true);
231
vbox.pack_start (comments_box, false, false, 4);
169
233
reply_to = new Gtk.Label ("");
170
234
reply_to.set_no_show_all(true);
171
235
reply_to.set_markup ("<span font_weight='light' font_size='small'></span>");
324
391
string _img_thumb,
393
string _video_picture,
399
// hide and reset values to prevent reuse as the tiles change
402
action_box.set_no_show_all (true);
403
comments_box.set_no_show_all (true);
404
comments_box.hide ();
405
thumb_box.set_no_show_all (true);
408
message.set_markup ("");
409
name.set_markup ("");
410
icon.set_from_icon_name ("stock_person", Gtk.IconSize.DIALOG);
413
// end hide and reset
415
/* Cancel all pending async operations */
417
Source.remove(img_id);
420
if (_stream == "images")
422
if (_img_thumb != null && _img_thumb.length > 0)
423
img_uri = _img_thumb;
426
else if (_stream == "links")
428
img_uri = _link_picture;
431
else if (_stream == "videos")
433
img_uri = _video_picture;
434
img_src = _video_src;
328
437
if (_stream == "private")
333
message.set_markup ("");
442
foreach (uint _to_disconnect_id in _to_disconnect)
444
GLib.Source.remove (_to_disconnect_id);
445
_to_disconnect.remove (_to_disconnect_id);
448
foreach (var w in comments_box.get_children ())
452
if (_comments != null)
454
//comments_box.set_no_show_all (false);
455
var parser = new Json.Parser();
456
parser.load_from_data(_comments, -1);
457
unowned Json.Node comments_node = null;
458
comments_node = parser.get_root();
459
if (comments_node != null)
461
Json.Object comments_obj = comments_node.get_object ();
462
if (comments_obj != null)
464
if (comments_obj.has_member ("comments"))
466
Json.Array comments = comments_obj.get_array_member ("comments");
467
for(int i = 0; i < comments.get_length(); i++) {
468
var obj = comments.get_element(i).get_object();
471
var cvbox = new Gtk.VBox (false, 2);
472
var chbox = new Gtk.HBox (false, 2);
473
var clalignment = new Gtk.Alignment (0.5f, 0.0f, 0.0f, 0.0f);
474
chbox.pack_start (clalignment, false, false, 0);
476
var cicon = new StreamViewAvatar();
477
clalignment.add (cicon);
479
comments_box.pack_start (chbox, false, false, 2);
480
chbox.pack_start (cvbox, false, false, 2);
481
if (obj.has_member ("text"))
483
var ctext = obj.get_string_member ("text");
484
var ctext_label = new Gtk.Label ("");
485
ctext_label.set_selectable (true);
486
ctext_label.set_single_line_mode (false);
487
ctext_label.set_line_wrap (true);
488
ctext_label.set_line_wrap_mode (Pango.WrapMode.WORD_CHAR);
489
ctext_label.set_alignment (0.0f, 0.0f);
490
ctext_label.set_markup ("<span font_size='small'>" + ctext + "</span>");
491
cvbox.pack_end (ctext_label, false, false, 2);
493
if (obj.has_member ("sender"))
495
var _sender_obj = obj.get_object_member ("sender");
496
if (_sender_obj != null)
498
if (_sender_obj.has_member ("name"))
500
var cname = _sender_obj.get_string_member ("name");
501
var cname_box = new Gtk.HBox (false, 2);
502
var cname_label = new Gtk.Label ("");
503
cname_label.set_markup ("<b><span font_size='small'>" + cname + "</span></b>");
504
cname_box.pack_start (cname_label, false, false, 2);
505
cvbox.pack_end (cname_box, false, false, 2);
507
if (_sender_obj.has_member ("image"))
509
var cimage = _sender_obj.get_string_member ("image");
510
var cached_cicon = utils.avatar_path(cimage);
511
if (cached_cicon != null)
512
cicon.set_from_file(cached_cicon);
515
cicon.set_from_icon_name ("stock_person", Gtk.IconSize.DIALOG);
517
uint cid = Idle.add (() => {
518
load_avatar_async.begin (cimage, cicon);
521
_to_disconnect.append (cid);
526
comments_box.set_no_show_all (false);
527
comments_box.show_all ();
335
536
string display_name = _sender;
467
663
likes_hbox.show_all();
666
message.set_markup (_html);
668
string link_str = null;
470
669
if (_stream == "links")
472
string link_str = "<a href='" + _link_url + "'>" + _link_name + "</a>\n";
671
link_str = "<a href='" + _link_url + "'>" + _link_name + "</a>\n";
473
672
link_str += _link_desc;
475
link_str += _link_caption;
476
673
message.set_markup (link_str);
478
message.set_markup (_html);
481
if (_img_url.length > 0)
483
string img_str = _html;
485
if (_img_name.length > 0)
486
img_str += "<a href='" + _img_url + "'>" + _img_name + "</a>";
488
img_str += "<a href='" + _img_url + "'>" + _img_url + "</a>";
489
message.set_markup (img_str);
676
string video_str = null;
677
if (_stream == "videos")
679
video_str = "<a href='" + _video_url + "'>" + _video_name + "</a>\n";
681
message.set_markup (video_str);
684
if (img_uri.length > 0)
686
/* Let's wait a while before loading in case there is some funny
687
* business going on or the user is scrolling
689
string img_str = null;
690
img_id = Timeout.add (200, () =>
693
if (_stream == "videos" && video_str.length > 0)
695
else if (_stream == "links" && link_str.length > 0)
699
if (_img_name.length > 0)
700
img_str = "<a href='" + _img_url + "'>" + _img_name + "</a>\n";
702
img_str = "<a href='" + _img_url + "'>" + _img_url + "</a>\n";
706
load_thumbnail_async.begin(img_str);
493
711
time_string = utils.generate_time_string ((uint)long.parse(_timestamp));
750
private async void load_avatar_async(string url, Gtk.Image cicon)
753
var file = File.new_for_uri(url);
755
var stream = yield file.read_async(Priority.DEFAULT, cancellable);
756
Gdk.Pixbuf pixbuf = null;
757
pixbuf = new Gdk.Pixbuf.from_stream_at_scale (stream,
762
if (pixbuf is Gdk.Pixbuf)
764
cicon.set_from_pixbuf (pixbuf);
766
var cimage = Path.build_path(Path.DIR_SEPARATOR_S, Environment.get_user_cache_dir(), "gwibber/avatars", url.replace("/",""));
768
if (cimage.has_suffix ("JPG") || cimage.has_suffix ("jpeg") || cimage.has_suffix ("jpg"))
770
pixbuf.save (cimage, t);
773
debug("Error trying to load %s: %s", url, e.message);
774
cicon.set_from_icon_name ("stock_person", Gtk.IconSize.DIALOG);
778
private async void load_thumbnail_async(string img_markup)
780
Gtk.Allocation alloc;
781
message.get_allocation (out alloc);
784
var file = File.new_for_uri(fix_image_uri(img_uri));
786
var stream = yield file.read_async(Priority.DEFAULT, cancellable);
787
Gdk.Pixbuf pixbuf = null;
788
pixbuf = new Gdk.Pixbuf.from_stream_at_scale (stream,
793
if (pixbuf is Gdk.Pixbuf)
795
thumbnail.set_from_pixbuf (pixbuf);
797
thumb_box.set_no_show_all (false);
800
message.set_markup (img_markup);
802
debug("Error trying to load %s: %s", img_uri, e.message);
804
thumb_box.set_no_show_all (true);
809
/* Do any magic we want to here */
810
private string fix_image_uri(string uri)
814
if (uri.contains("imgur.com") && !uri.has_suffix(".png"))
816
/* let's point to the static content in imgur */
817
var last = uri.rstr("/").substring(1);
818
ret = "http://i.imgur.com/%s.png".printf(last);
820
else if (uri.contains("youtube.com"))
822
string id = uri.rstr("/").substring(1);
824
if (uri.contains("watch?v="))
826
if (uri.contains("&"))
827
id = uri.split("v=")[1].split("&")[0];
829
id = uri.split("v=")[1];
831
ret = "http://img.youtube.com/vi/%s/default.jpg".printf(id);
533
836
private bool on_avatar_click (Gdk.EventButton button)