Mercurial repo sync
authorJulien Valroff <julien@kirya.net>
Sun, 7 Nov 2010 19:46:33 +0000 (20:46 +0100)
committerJulien Valroff <julien@kirya.net>
Sun, 7 Nov 2010 19:46:33 +0000 (20:46 +0100)
debian/changelog
src/account_abstract.vala
src/accounts.vala
src/content_view.vala
src/status_choose_bar.vala
src/template.vala
src/twitter_account.vala

index da61ad4..b8765cd 100644 (file)
@@ -1,5 +1,5 @@
-pino (0.3~20100924-1) experimental; urgency=low
+pino (0.3~20101101-1) experimental; urgency=low
 
   * Initial release (Closes: #573040)
 
- -- Julien Valroff <julien@kirya.net>  Mon, 16 Aug 2010 14:58:58 +0200
+ -- Julien Valroff <julien@kirya.net>  Sun, 07 Nov 2010 20:45:22 +0100
index d97e8ea..945d28d 100644 (file)
@@ -13,6 +13,7 @@ public abstract class AAccount : GLib.Object {
        public signal void message_indicate(string msg);
        public signal void stop_indicate();
        public signal void do_reply(AAccount account, Status status);
+       public signal void insert_reply(string stream_hash, string status_id, Status result);
        
        /* For tree widget */
        public signal void stream_was_changed(AAccount account, AStream stream, int stream_index);
index fe9268d..69ece48 100644 (file)
@@ -15,6 +15,7 @@ public class Accounts : ArrayList<AAccount> {
        public signal void message_indicate(string msg);
        public signal void stop_indicate();
        public signal void do_reply(AAccount account, Status status);
+       public signal void insert_reply(string stream_hash, string status_id, Status result);
        
        //private ArrayList<AccountState> accounts_states;
        
@@ -339,6 +340,10 @@ public class Accounts : ArrayList<AAccount> {
                account.do_reply.connect((acc, status) => {
                        do_reply(acc, status);
                });
+               
+               account.insert_reply.connect((stream_hash, status_id, result) => {
+                       insert_reply(stream_hash, status_id, result);
+               });
        }
 
        /** New stream was added, we need to report about this to the tree widget */
index 7224263..d9f3986 100644 (file)
@@ -17,6 +17,8 @@ public class ContentView : GLib.Object {
        
        private string current_stream = "";
        
+       private bool not_more = false;
+       
        public ContentView(Accounts accounts, VisualStyle visual_style) {
                view = new WebView();
                view.set_size_request(250, 350);
@@ -36,9 +38,8 @@ public class ContentView : GLib.Object {
                scroll_map = new HashMap<string, string>(str_hash, str_equal);
                
                view.load_finished.connect((f) => {
-                       if(scroll_map.has_key(current_stream)) {
-                               slider.set_value(scroll_map[current_stream].to_double());
-                       }
+                       update_style();
+                       
                });
                
                //when scroll to the bottom
@@ -50,7 +51,32 @@ public class ContentView : GLib.Object {
                
                tpl = new Template(this.visual_style);
                
+               view.load_string(tpl.render_body(), "text/html", "utf8", "file:///");
+               
                this.accounts.stream_was_updated.connect(generate_list);
+               
+               this.accounts.insert_reply.connect(insert_reply);
+       }
+       
+       private void insert_reply(string stream_hash, string status_id, Status status) {
+               if(stream_hash != current_stream) {
+                       debug("not this stream");
+                       return;
+               }
+               
+               AStream? stream = accounts.stream_from_hash(stream_hash);
+               if(stream == null) {
+                       debug("can't find this stream");
+                       return;
+               }
+               
+               string result = tpl.render_small_status(status, stream);
+               result = result.replace("'", "\\'");
+               debug(result);
+               
+               string script = """insert_reply('%s', '%s');""".printf(status_id, result);
+               script = script.replace("\n", " ");
+               view.execute_script(script);
        }
        
        private void slider_move() {
@@ -58,7 +84,7 @@ public class ContentView : GLib.Object {
                double current = slider.get_value();
                double scroll_size = slider.adjustment.page_size;
                
-               if(current != 0 && current + scroll_size == max) {
+               if(!not_more && current != 0 && current + scroll_size == max) {
                        debug("need more");
                        AStream? stream = accounts.stream_from_hash(current_stream);
                        
@@ -75,7 +101,10 @@ public class ContentView : GLib.Object {
                if(stream.statuses.size == 0 && stream.statuses_fresh.size == 0)
                        return;
                
-               content_map.set(hash, tpl.stream_to_list(stream, hash));
+               string data = tpl.stream_to_list(stream, hash);
+               data = data.replace("\n", " ");
+               data = data.replace("'", "\\'");
+               content_map.set(hash, data);
                
                if(hash == current_stream)
                        set_current_list(hash);
@@ -85,29 +114,47 @@ public class ContentView : GLib.Object {
                if(hash == null)
                        return;
                
+               not_more = true;
+               
                if(current_stream != "")
                        scroll_map[current_stream] = slider.get_value().to_string();
                
                current_stream = hash;
                
                if(content_map.has_key(hash)) {
-                       view.load_string(content_map.get(hash), "text/html", "utf8", "file:///");
+                       //view.load_string(content_map.get(hash), "text/html", "utf8", "file:///");
+                       load_content(content_map.get(hash));
                } else {
-                       view.load_string("empty", "text/html", "utf8", "file:///");
+                       load_content("empty");
                }
                
-               debug(content_map.size.to_string());
+               if(scroll_map.has_key(current_stream)) {
+                       slider.set_value(scroll_map[current_stream].to_double());
+               }
+               
+               not_more = false;
+       }
+       
+       protected void load_content(owned string data) {
+               string script = """set_content('%s');""".printf(data);
+               view.execute_script(script);
        }
        
        private void update_style() {
                view.settings.set_property("default-font-size", visual_style.font_size);
                view.settings.set_property("default-font-family", visual_style.font_family);
                
-               tpl.render_header();
+               string header = tpl.render_header();
                
+               /*
                accounts.update_all_streams();
                
                set_current_list(current_stream);
+               */
+               
+               string script = """change_style("%s");""".printf(header);
+               script = script.replace("\n", " ");
+               view.execute_script(script);
                
                debug("style changed");
        }
index 40ea092..8d664a9 100644 (file)
@@ -33,7 +33,26 @@ public class StatusChooseBar : Toolbar {
                set_icon_size(IconSize.SMALL_TOOLBAR);
                toolbar_style = ToolbarStyle.ICONS;
                
-               this.accounts.element_was_removed.connect(remove_account);
+               accounts.insert_new_account.connect((acc) => {
+                       add_new_account(acc);
+                       update_config();
+               });
+               
+               accounts.element_was_removed.connect((path, acc) => {
+                       if(path.contains(":")) //just stream, not account
+                       return;
+               
+                       foreach(Widget tb in this.get_children()) {
+                               if(tb.get_type() != typeof(ToggleToolButton))
+                                       continue;
+                               
+                               if(((ToggleToolButton) tb).label == acc.get_hash()) {
+                                       this.remove(tb);
+                               }
+                       }
+                       
+                       update_config();
+               });
        }
        
        public void set_count(int chars) {
@@ -79,42 +98,41 @@ public class StatusChooseBar : Toolbar {
                }
        }
        
+       private void add_new_account(AAccount account) {
+               debug(account.s_name);
+               ToggleToolButton tb = new ToggleToolButton();
+               tb.label = account.get_hash();
+               tb.set_tooltip_text("%s (%s)".printf(account.s_name, account.id));
+               
+               if(settings.selected_for_posting.contains(tb.label))
+                       tb.set_active(true);
+               
+               account.notify["userpic"].connect((s) => {
+                       debug("userpic is loaded");
+                       Image img = new Image.from_pixbuf(account.userpic.scale_simple(
+                               24, 24, Gdk.InterpType.HYPER));
+                       img.show();
+                       tb.set_icon_widget(img);
+               });
+               
+               tb.toggled.connect(() => {
+                       update_config();
+               });
+               
+               /*
+               if(account.userpic != null) {
+                       debug("userpic is ok");
+                       Image img = new Image.from_pixbuf(account.userpic);
+                       img.pixel_size = 48;
+                       tb.set_icon_widget(img);
+               }*/
+               this.add(tb);
+               tb.show();
+       }
+       
        private void generate_acc() {
                foreach(AAccount account in this.accounts) {
-                       ToggleToolButton tb = new ToggleToolButton();
-                       tb.label = account.get_hash();
-                       tb.set_tooltip_text("%s (%s)".printf(account.s_name, account.id));
-                       
-                       if(settings.selected_for_posting.contains(tb.label))
-                               tb.set_active(true);
-                       
-                       account.notify["userpic"].connect((s) => {
-                               debug("userpic is loaded");
-                               Image img = new Image.from_pixbuf(account.userpic.scale_simple(
-                                       24, 24, Gdk.InterpType.HYPER));
-                               img.show();
-                               tb.set_icon_widget(img);
-                       });
-                       
-                       tb.toggled.connect(() => {
-                               update_config();
-                       });
-                       
-                       /*
-                       if(account.userpic != null) {
-                               debug("userpic is ok");
-                               Image img = new Image.from_pixbuf(account.userpic);
-                               img.pixel_size = 48;
-                               tb.set_icon_widget(img);
-                       }*/
-                       this.add(tb);
+                       add_new_account(account);
                }
        }
-       
-       private void remove_account(string path, AAccount account) {
-               if(path.contains(":")) //just stream, not account
-                       return;
-               
-               update_config();
-       }
 }
index 2655c4e..f27d42d 100644 (file)
@@ -9,6 +9,38 @@ public class Template : Object {
                <html>
                        <head>
                        <script type="text/javascript">
+                       function insertAfter(newElement,targetElement) {
+                               var parent = targetElement.parentNode;
+                               if(parent.lastchild == targetElement) {
+                                       parent.appendChild(newElement);
+                               } else {
+                                       parent.insertBefore(newElement, targetElement.nextSibling);
+                               }
+                       }
+                       function insert_reply(status_id, data) {
+                               var footer = document.getElementById("footer" + status_id);
+                               footer.removeAttribute("href");
+                               
+                               var reply = document.getElementById("reply" + status_id);
+                               
+                               if(reply == null) {
+                                       reply = document.createElement("div");
+                                       reply.setAttribute("class", "reply-box");
+                                       reply.setAttribute("id", "reply" + status_id);
+                               }
+                               
+                               reply.innerHTML += data;
+                               
+                               var status = document.getElementById("status" + status_id);
+                               //alert(status);
+                               insertAfter(reply, status);
+                       }
+                       function change_style(data) {
+                               document.getElementById("style").innerHTML = data;
+                       }
+                       function set_content(data) {
+                               document.getElementById("body").innerHTML = data;
+                       }
                        function menu(e, data) {
                                if(e.button == 2) {
                                        location.href="contextmenu://" + data;
@@ -22,9 +54,10 @@ public class Template : Object {
                                return true;
                        }
                        </script>
-                       %s
+                       <style type="text/css" id="style">
+                       </style>
                        </head>
-                       <body>
+                       <body id="body">
                        %s
                        </body>
                </html>
@@ -198,21 +231,26 @@ public class Template : Object {
        */
        
        private string header_tpl = """
-               <style type="text/css">
        body {
                color: {{fg_color}};
-               background: {{bg_light_color}}
+               background: {{bg_color}};
                #font-family: Droid Sans;
                #font-size: 9pt;
                margin: 0px;
        }
-       .status, .status-fresh, .status-own {
+       .status, .status-fresh, .status-own, .status-small {
+               background: {{bg_light_color}};
                padding: 6px;
                position: relative;
                min-height: 50px;
                border: 0px solid #edeceb;
                border-bottom-width: 1px;
        }
+       .status-small {
+               border-left-width: 1px;
+               -webkit-border-radius: 3px 0px 0px 3px;
+               min-height: 30px;
+       }
        .status-content {
                z-index: 4;
                position: relative;
@@ -226,6 +264,9 @@ public class Template : Object {
                font-weight: bold;
                text-decoration: none;
        }
+       .reply-box {
+               margin-left: 24px;
+       }
        .status-fresh {
                #background: #c3dff7;
                background: -webkit-gradient(linear, 0 -75, 0 bottom, from({{bg_light_color}}), to(#c6ebb1));
@@ -246,6 +287,9 @@ public class Template : Object {
                position:relative;
                margin-left: 50px;
        }
+       .status-small .right {
+                       margin-left: 24px;
+       }
        .left {
                float: left;
                width: 48px;
@@ -255,6 +299,11 @@ public class Template : Object {
                -webkit-background-size: 48px 48px;
                -webkit-box-shadow: 1px 1px 1px  #ccc;
        }
+       .status-small .left {
+               width: 24px;
+               height: 24px;
+               -webkit-background-size: 24px 24px;
+       }
        .header {
                margin-bottom: 3px;
        }
@@ -323,7 +372,7 @@ public class Template : Object {
                -webkit-animation-name: menu-hover;
                -webkit-animation-duration: 1s;
        }
-               </style>""";
+       """;
        
        /*
        private string status_tpl = """
@@ -347,7 +396,7 @@ public class Template : Object {
        */
        
        private string status_tpl = """
-       <div class="status{{status_state}}" onmouseup="menu(event, '{{account_hash}}##{{stream_hash}}##{{status_id}}');" ondblclick="reply(event, '{{account_hash}}##{{stream_hash}}##{{status_id}}');">
+       <div class="status{{status_state}}" id="status{{status_id}}" onmouseup="menu(event, '{{account_hash}}##{{stream_hash}}##{{status_id}}');" ondblclick="reply(event, '{{account_hash}}##{{stream_hash}}##{{status_id}}');">
                <div class="left" style="background-image:url('{{user_pic}}');"></div>
                <div class="right">
                        <div class="status-content">
@@ -363,8 +412,20 @@ public class Template : Object {
        </div>
        """;
        
+       private string status_small_tpl = """
+       <div class="status-small">
+               <div class="left" style="background-image:url({{user_pic}});"></div>
+               <div class="right">
+                       <div class="status-content">
+                               <a class="re_nick" href="">{{user_name}}</a>: {{content}}
+                       </div>
+               </div>
+               <div class="clear"></div>
+       </div>
+       """;
+       
        private string retweet_tpl = """<span class="rt">Rt:</span>""";
-       private string footer_tpl = """<div class="sep"></div><a class="footer" href="">%s</a>""";
+       private string footer_tpl = """<div class="sep"></div><a class="footer" id="footer{{status_id}}" href="context://{{account_hash}}##{{stream_hash}}##{{status_id}}">%s</a>""";
        
        private string header;
        
@@ -403,23 +464,27 @@ public class Template : Object {
                        result += render_status(status, stream);
                }
                
-               string main_result = main_tpl.printf(header, result);
+               //string main_result = main_tpl.printf(header, result);
                //debug(main_result);
                
                //back to the normal locale
                GLib.Intl.setlocale(GLib.LocaleCategory.TIME, currentLocale);
                
-               return main_result;
+               return result;
+       }
+       
+       public string render_body() {
+               return main_tpl.printf("");
        }
        
-       public void render_header() {
+       public string render_header() {
                HashMap<string, string> map = new HashMap<string, string>();
                map["fg_color"] = visual_style.fg_color;
                map["bg_color"] = visual_style.bg_color;
                map["bg_light_color"] = visual_style.bg_light_color;
                map["lk_color"] = visual_style.lk_color;
                header = render(header_tpl, map);
-               //debug(header);
+               return header;
        }
        
        public string render_fresh_status(Status status, AStream stream) {
@@ -477,6 +542,20 @@ public class Template : Object {
                return render(status_tpl, map);
        }
        
+       public string render_small_status(Status status, AStream stream) {
+               HashMap<string, string> map = new HashMap<string, string>();
+               if(img_cache.exist(status.user.pic)) //load from cache, if exist
+                       map["user_pic"] = img_cache.download(status.user.pic);
+               else
+                       map["user_pic"] = status.user.pic;
+               
+               
+               map["user_name"] = status.user.name;
+               map["content"] = format_content(status.content, stream);
+               
+               return render(status_small_tpl, map);
+       }
+       
        private string render(string text, HashMap<string, string> map) {
                string result = text;
                
@@ -484,6 +563,7 @@ public class Template : Object {
                        var pat = new Regex("{{" + key + "}}");
                        result = pat.replace(result, -1, 0, map[key]);
                }
+               //debug(result);
                return result;
        }
        
@@ -510,9 +590,9 @@ public class Template : Object {
                        if(bingo) {
                                foreach(string s in match_info.fetch_all()) {
                                        if(s.length > 30) {
-                                               data = data.replace(s, "<a href='%s' title='%s'>%s...</a>".printf(s, s, s.substring(0, 30)));
+                                               data = data.replace(s, """<a href="%s" title="%s">%s...</a>""".printf(s, s, s.substring(0, 30)));
                                        } else {
-                                               data = data.replace(s, "<a href='%s'>%s</a>".printf(s, s));
+                                               data = data.replace(s, """<a href="%s">%s</a>""".printf(s, s));
                                        }
                                        
                                        match_info.fetch_pos(0, null, out pos);
index dd56403..bb11a96 100644 (file)
@@ -61,6 +61,8 @@ public class Account : AAccount {
                }
        }
        
+       protected RecursiveReply rec_reply;
+       
        construct {
        }
        
@@ -159,6 +161,31 @@ public class Account : AAccount {
                                menu_do_reply(status);
                        break;
                
+               
+               case "context":
+                       Status? status = null;
+                       foreach(AStream stream in streams) {
+                               if(get_stream_hash(stream) == stream_hash) {
+                                       status = get_status(stream.stream_type, val);
+                                       break;
+                               }
+                       }
+                       
+                       if(status == null)
+                               return null;
+                       
+                       debug(status.id);
+                       
+                       //get status and send signal to cintent_view
+                       rec_reply = new RecursiveReply(proxy, status, s_name,
+                               stream_hash);
+                       rec_reply.new_reply.connect((rstatus, shash, sid) => {
+                               insert_reply(shash, sid, rstatus); //signal
+                       });
+                       rec_reply.run();
+                       
+                       break;
+               
                case "contextmenu":
                        debug("menu");
                        AStream? stream = null;