From 02f1ab0e4a227653ff9eadb12334b5aa13344806 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Wed, 9 Jan 2019 16:47:58 -0600 Subject: [PATCH] Added support to comment threads. Shows comment replies in a separate viewer. Show total replies for a comment in a column in the list --- src/interactors/postDisplayer.py | 20 ++++++++- src/presenters/postDisplayer.py | 73 ++++++++++++++++++++++++++++---- src/views/dialogs/postDisplay.py | 34 +++++++++++++-- 3 files changed, 115 insertions(+), 12 deletions(-) diff --git a/src/interactors/postDisplayer.py b/src/interactors/postDisplayer.py index 6dcaa5e..44bd579 100644 --- a/src/interactors/postDisplayer.py +++ b/src/interactors/postDisplayer.py @@ -46,7 +46,11 @@ class displayPostInteractor(base.baseInteractor): widgetUtils.connect_event(self.view.like, widgetUtils.BUTTON_PRESSED, self.on_like) widgetUtils.connect_event(self.view.comment, widgetUtils.BUTTON_PRESSED, self.on_add_comment) widgetUtils.connect_event(self.view.tools, widgetUtils.BUTTON_PRESSED, self.on_show_tools_menu) - widgetUtils.connect_event(self.view.repost, widgetUtils.BUTTON_PRESSED, self.on_repost) + if hasattr(self.view, "repost"): + widgetUtils.connect_event(self.view.repost, widgetUtils.BUTTON_PRESSED, self.on_repost) + self.view.comments.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.on_focus) + if hasattr(self.view, "reply"): + widgetUtils.connect_event(self.view.reply, widgetUtils.BUTTON_PRESSED, self.on_reply) # self.view.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.on_show_menu, self.view.comments.list) # self.view.Bind(wx.EVT_LIST_KEY_DOWN, self.on_show_menu_by_key, self.view.comments.list) pub.subscribe(self.set, self.modulename+"_set") @@ -63,12 +67,26 @@ class displayPostInteractor(base.baseInteractor): pub.unsubscribe(self.enable_attachments, self.modulename+"_enable_attachments") pub.unsubscribe(self.enable_photo_controls, self.modulename+"_enable_photo_controls") + def on_focus(self, *args, **kwargs): + item = self.view.comments.get_selected() + if item == -1: + self.view.reply.Enable(False) + else: + self.view.reply.Enable(True) + def on_like(self, *args, **kwargs): self.presenter.post_like() def on_repost(self, *args, **kwargs): self.presenter.post_repost() + def on_reply(self, *args, **kwargs): + if hasattr(self.view, "repost"): + comment = self.view.comments.get_selected() + self.presenter.reply(comment) + else: + self.presenter.reply() + def on_add_comment(self, *args, **kwargs): self.presenter.add_comment() diff --git a/src/presenters/postDisplayer.py b/src/presenters/postDisplayer.py index 178983f..e8b0a0c 100644 --- a/src/presenters/postDisplayer.py +++ b/src/presenters/postDisplayer.py @@ -69,7 +69,7 @@ class displayPostPresenter(base.basePresenter): """ Get comments and insert them in a list.""" user = self.post[self.user_identifier] id = self.post[self.post_identifier] - self.comments = self.session.vk.client.wall.getComments(owner_id=user, post_id=id, need_likes=1, count=100, extended=1, preview_length=0) + self.comments = self.session.vk.client.wall.getComments(owner_id=user, post_id=id, need_likes=1, count=100, extended=1, preview_length=0, thread_items_count=10) comments_ = [] for i in self.comments["items"]: # If comment has a "deleted" key it should not be displayed, obviously. @@ -88,7 +88,8 @@ class displayPostPresenter(base.basePresenter): original_date = arrow.get(i["date"]) created_at = original_date.humanize(locale=languageHandler.curLang[:2]) likes = str(i["likes"]["count"]) - comments_.append((from_, text, created_at, likes)) + replies = str(i["thread"]["count"]) + comments_.append((from_, text, created_at, likes, replies)) self.send_message("add_items", control="comments", items=comments_) def get_post_information(self): @@ -226,7 +227,7 @@ class displayPostPresenter(base.basePresenter): def post_repost(self): object_id = "wall{0}_{1}".format(self.post[self.user_identifier], self.post[self.post_identifier]) - p = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.post(title=_("Repost"), message=_("Add your comment here"), text="", mode="comment")) + p = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Repost"), message=_("Add your comment here"), text="", mode="comment")) if hasattr(p, "text") or hasattr(p, "privacy"): msg = p.text self.session.vk.client.wall.repost(object=object_id, message=msg) @@ -238,7 +239,7 @@ class displayPostPresenter(base.basePresenter): self.send_message("set_label", control="shares", label=_("Shared {0} times").format(self.post["reposts"]["count"],)) def add_comment(self): - comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.post(title=_("Add a comment"), message="", text="", mode="comment")) + comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Add a comment"), message="", text="", mode="comment")) if hasattr(comment, "text") or hasattr(comment, "privacy"): msg = comment.text try: @@ -252,12 +253,27 @@ class displayPostPresenter(base.basePresenter): except Exception as msg: log.error(msg) + def reply(self, comment): + c = self.comments["items"][comment] + comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {username}").format(username=self.session.get_user_name(c["from_id"]),), message="", text="", mode="comment")) + if hasattr(comment, "text") or hasattr(comment, "privacy"): + msg = comment.text + try: + user = c["owner_id"] + reply_to_comment = c["id"] + post_id = c["post_id"] + r = self.session.vk.client.wall.createComment(owner_id=user, reply_to_user=user, post_id=post_id, message=msg, reply_to_comment=reply_to_comment, v=5.51) + output.speak(_("You've posted a comment")) + except IndexError as msg: + log.error(msg) + def clear_comments_list(self): self.send_message("clear_list", list="comments") def show_comment(self, comment_index): c = self.comments["items"][comment_index] - a = displayCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayPost()) + c["post_id"] = self.post[self.post_identifier] + a = displayCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment()) def translate(self, text, language): msg = translator.translator.translate(text, language) @@ -337,19 +353,18 @@ class displayCommentPresenter(displayPostPresenter): def load_all_components(self): self.get_post_information() self.get_likes() - self.send_message("disable_control", control="shares") self.send_message("disable_control", control="comment") + self.get_comments() if self.post["likes"]["can_like"] == 0 and self.post["likes"]["user_likes"] == 0: self.send_message("disable_control", "like") elif self.post["likes"]["user_likes"] == 1: self.send_message("set_label", control="like", label=_("&Dislike")) - self.send_message("disable_control", control="repost") def get_post_information(self): from_ = self.session.get_user_name(self.post[self.user_identifier]) if ("from_id" in self.post and "owner_id" in self.post): # Translators: {0} will be replaced with the user who is posting, and {1} with the wall owner. - title = _("Post from {0} in the {1}'s post").format(self.session.get_user_name(self.post["from_id"]), self.session.get_user_name(self.post["owner_id"])) + title = _("Comment from {0} in the {1}'s post").format(self.session.get_user_name(self.post["from_id"]), self.session.get_user_name(self.post["owner_id"])) self.send_message("set_title", value=title) message = "" message = get_message(self.post) @@ -357,6 +372,48 @@ class displayCommentPresenter(displayPostPresenter): self.get_attachments(self.post, message) self.check_image_load() + def reply(self): + comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {username}").format(username=self.session.get_user_name(self.post["from_id"]),), message="", text="", mode="comment")) + if hasattr(comment, "text") or hasattr(comment, "privacy"): + msg = comment.text + try: + user = self.post["owner_id"] + reply_to_comment = self.post["id"] + post_id = self.post["post_id"] + r = self.session.vk.client.wall.createComment(owner_id=self.post["owner_id"], post_id=post_id, message=msg, reply_to_comment=reply_to_comment) + output.speak(_("You've posted a comment")) + except IndexError as msg: + log.error(msg) + + def get_comments(self): + """ Get comments and insert them in a list.""" + comments_ = [] + for i in self.post["thread"]["items"]: + # If comment has a "deleted" key it should not be displayed, obviously. + if "deleted" in i: + continue + from_ = self.session.get_user_name(i["from_id"]) + if "reply_to_user" in i: + extra_info = self.session.get_user_name(i["reply_to_user"]) + from_ = _("{0} > {1}").format(from_, extra_info) + # As we set the comment reply properly in the from_ field, let's remove the first username from here if it exists. + fixed_text = re.sub("^\[id\d+\|\D+\], ", "", i["text"]) + if len(fixed_text) > 140: + text = fixed_text[:141] + else: + text = fixed_text + original_date = arrow.get(i["date"]) + created_at = original_date.humanize(locale=languageHandler.curLang[:2]) + likes = str(i["likes"]["count"]) + replies = "" + comments_.append((from_, text, created_at, likes, replies)) + self.send_message("add_items", control="comments", items=comments_) + + def show_comment(self, comment_index): + c = self.post["thread"]["items"][comment_index] + c["post_id"] = self.post["post_id"] + a = displayCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment()) + class displayAudioPresenter(base.basePresenter): def __init__(self, session, postObject, view, interactor): super(displayAudioPresenter, self).__init__(view=view, interactor=interactor, modulename="display_audio") diff --git a/src/views/dialogs/postDisplay.py b/src/views/dialogs/postDisplay.py index 5589f5e..9268a71 100644 --- a/src/views/dialogs/postDisplay.py +++ b/src/views/dialogs/postDisplay.py @@ -23,10 +23,13 @@ class displayBasicPost(widgetUtils.BaseDialog): def create_comments_list(self): lbl = wx.StaticText(self.panel, -1, _("Comments")) - self.comments = widgetUtils.list(self.panel, _("User"), _("Comment"), _("Date"), _("Likes"), style=wx.LC_REPORT) + self.comments = widgetUtils.list(self.panel, _("User"), _("Comment"), _("Date"), _("Likes"), _("replies"), style=wx.LC_REPORT) + self.reply = wx.Button(self.panel, -1, _("Reply to comment")) + self.reply.Enable(False) box = wx.BoxSizer(wx.HORIZONTAL) box.Add(lbl, 0, wx.ALL, 5) box.Add(self.comments.list, 0, wx.ALL, 5) + box.Add(self.reply, 0, wx.ALL, 5) return box def create_attachments(self): @@ -58,7 +61,6 @@ class displayBasicPost(widgetUtils.BaseDialog): self.previous_photo.Enable(True) self.next_photo.Enable(True) - def create_likes_box(self): self.likes = wx.Button(self.panel, -1, _("Loading data...")) return self.likes @@ -73,6 +75,7 @@ class displayBasicPost(widgetUtils.BaseDialog): if comment: self.comment = wx.Button(self.panel, -1, _("Add comment")) box = wx.BoxSizer(wx.HORIZONTAL) box.Add(self.like, 0, wx.ALL, 5) + box.Add(self.repost, 0, wx.ALL, 5) if comment: box.Add(self.comment, 0, wx.ALL, 5) return box @@ -137,15 +140,40 @@ class displayComment(displayBasicPost): super(displayComment, self).__init__(*args, **kwargs) post_view_box = self.create_post_view() self.sizer.Add(post_view_box, 0, wx.ALL, 5) + attachments_box = self.create_attachments() + self.sizer.Add(attachments_box, 0, wx.ALL, 5) + self.attachments.list.Enable(False) + self.create_photo_viewer() + self.image.Enable(False) self.create_tools_button() self.sizer.Add(self.tools, 0, wx.ALL, 5) likes_box = self.create_likes_box() self.sizer.Add(likes_box, 0, wx.ALL, 5) - actions_box = self.create_action_buttons(comment=False) + actions_box = self.create_action_buttons() self.sizer.Add(actions_box, 0, wx.ALL, 5) + comments_box = self.create_comments_list() + self.sizer.Add(comments_box, 0, wx.ALL, 5) self.sizer.Add(self.create_dialog_buttons()) self.done() + def create_comments_list(self): + lbl = wx.StaticText(self.panel, -1, _("Replies")) + self.comments = widgetUtils.list(self.panel, _("User"), _("Comment"), _("Date"), _("Likes"), _("Replies"), style=wx.LC_REPORT) + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(lbl, 0, wx.ALL, 5) + box.Add(self.comments.list, 0, wx.ALL, 5) + return box + + def create_action_buttons(self, comment=True): + self.like = wx.Button(self.panel, -1, _("&Like")) + self.reply = wx.Button(self.panel, -1, _("Reply to thread")) + if comment: self.comment = wx.Button(self.panel, -1, _("Add comment")) + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(self.like, 0, wx.ALL, 5) + box.Add(self.reply, 0, wx.ALL, 5) + if comment: box.Add(self.comment, 0, wx.ALL, 5) + return box + class displayAudio(widgetUtils.BaseDialog): def __init__(self, *args, **kwargs): super(displayAudio, self).__init__(parent=None, *args, **kwargs)