From 7168b874aa2eba5c21b85e1b56264a65b5a637cb Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 8 Jan 2019 17:56:51 -0600 Subject: [PATCH] Added basic comment viewer. It is possible to do likes and remove likes to comments. Pressing enter in a comment will open the experimental viewer --- src/controller/buffers.py | 14 +- src/controller/mainController.py | 6 +- src/controller/posts.py | 514 ------------------ src/interactors/postDisplayer.py | 22 +- src/presenters/postDisplayer.py | 89 ++- src/views/__init__.py | 1 + src/views/dialogs/postCreation.py | 12 +- .../dialogs/postDisplay.py} | 20 +- 8 files changed, 116 insertions(+), 562 deletions(-) delete mode 100644 src/controller/posts.py rename src/{wxUI/dialogs/postDialogs.py => views/dialogs/postDisplay.py} (93%) diff --git a/src/controller/buffers.py b/src/controller/buffers.py index 0b6aa6c..84f3648 100644 --- a/src/controller/buffers.py +++ b/src/controller/buffers.py @@ -14,7 +14,6 @@ import widgetUtils from presenters import player import output from . import selector -from . import posts from pubsub import pub from vk_api.exceptions import VkApiError from vk_api import upload @@ -24,7 +23,6 @@ from sessionmanager import session, renderers, utils from mysc.thread_utils import call_threaded from wxUI import commonMessages, menus from sessionmanager.renderers import add_attachment -from wxUI.dialogs import postDialogs log = logging.getLogger("controller.buffers") @@ -342,11 +340,11 @@ class baseBuffer(object): if post == None: return if "type" in post and post["type"] == "audio": - a = presenters.displayAudioPresenter(session=self.session, postObject=post["audio"]["items"], interactor=interactors.displayAudioInteractor(), view=postDialogs.audio()) + a = presenters.displayAudioPresenter(session=self.session, postObject=post["audio"]["items"], interactor=interactors.displayAudioInteractor(), view=views.displayAudio()) elif "type" in post and post["type"] == "friend": - pub.sendMessage("open-post", post_object=post, controller_="friendship") + pub.sendMessage("open-post", post_object=post, controller_="displayFriendship") else: - pub.sendMessage("open-post", post_object=post, controller_="displayPostPresenter") + pub.sendMessage("open-post", post_object=post, controller_="displayPost") def pause_audio(self, *args, **kwargs): """ pauses audio playback.""" @@ -513,7 +511,7 @@ class audioBuffer(feedBuffer): if selected == -1: return audios = [self.session.db[self.name]["items"][selected]] - a = presenters.displayAudioPresenter(session=self.session, postObject=audios, interactor=interactors.displayAudioInteractor(), view=postDialogs.audio()) + a = presenters.displayAudioPresenter(session=self.session, postObject=audios, interactor=interactors.displayAudioInteractor(), view=views.displayAudio()) def play_all(self, *args, **kwargs): selected = self.tab.list.get_selected() @@ -968,9 +966,7 @@ class chatBuffer(baseBuffer): index = self.tab.attachments.get_selected() attachment = self.attachments[index] if attachment["type"] == "audio": - a = posts.audio(session=self.session, postObject=[attachment["audio"]]) - a.dialog.get_response() - a.dialog.Destroy() + a = presenters.displayAudioPresenter(session=self.session, postObject=[attachment["audio"]], interactor=interactors.displayAudioInteractor(), view=views.displayAudio()) elif attachment["type"] == "audio_message": link = attachment["audio_message"]["link_mp3"] output.speak(_("Playing...")) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 30dfa71..5da7c65 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -20,12 +20,10 @@ from mysc import localization from sessionmanager import session, utils, renderers from wxUI import (mainWindow, commonMessages) from wxUI.dialogs import search as searchDialogs -from wxUI.dialogs import timeline, creation, postDialogs from update import updater from issueReporter import issueReporter from . import buffers from presenters import player -from . import posts from presenters import longpollthread from . import selector @@ -253,9 +251,7 @@ class Controller(object): player.player.play_all(audios, shuffle=self.window.player_shuffle.IsChecked()) def view_post(self, post_object, controller_): - p = getattr(presenters, controller_)(session=self.session, postObject=post_object, interactor=interactors.displayPostInteractor(), view=postDialogs.post()) - p.dialog.get_response() - p.dialog.Destroy() + p = getattr(presenters, controller_+"Presenter")(session=self.session, postObject=post_object, interactor=getattr(interactors, controller_+"Interactor")(), view=getattr(views, controller_)()) def exit(self, *args, **kwargs): log.debug("Receibed an exit signal. closing...") diff --git a/src/controller/posts.py b/src/controller/posts.py deleted file mode 100644 index 7dc0f30..0000000 --- a/src/controller/posts.py +++ /dev/null @@ -1,514 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals -from future import standard_library -standard_library.install_aliases() -import re -import os -import six -import threading -import arrow -import requests -import languageHandler -import widgetUtils -import views -import presenters -import interactors -import output -import wx -import webbrowser -import logging -from sessionmanager import session, renderers, utils # We'll use some functions from there -from pubsub import pub -from wxUI.dialogs import postDialogs, urlList -from extra import SpellChecker, translator -from mysc.thread_utils import call_threaded -from wxUI import menus - -log = logging.getLogger("controller.post") - -def get_user(id, profiles): - """ Returns an user name and last name based in the id receibed.""" - for i in profiles: - if i["id"] == id: - return "{0} {1}".format(i["first_name"], i["last_name"]) - # Translators: This string is used when socializer can't find the right user information. - return _("Unknown username") - -def get_message(status): - message = "" - if "text" in status: - message = renderers.clean_text(status["text"]) - return message - -class postController(object): - """ Base class for post representation.""" - - def __init__(self, session, postObject): - super(postController, self).__init__() - self.session = session - self.post = postObject - # Posts from newsfeed contains this source_id instead from_id in walls. Also it uses post_id and walls use just id. - if "source_id" in self.post: - self.user_identifier = "source_id" - self.post_identifier = "post_id" - else: - # In wall's posts, if someone has posted in user's wall, owner_id should be used instead from_id - # This will help for retrieving comments, do likes, etc. - if "owner_id" not in self.post: - self.user_identifier = "from_id" - else: - self.user_identifier = "owner_id" - self.post_identifier = "id" - self.dialog = postDialogs.post() -# self.dialog.comments.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.show_comment) - widgetUtils.connect_event(self.dialog.like, widgetUtils.BUTTON_PRESSED, self.post_like) - widgetUtils.connect_event(self.dialog.comment, widgetUtils.BUTTON_PRESSED, self.add_comment) - widgetUtils.connect_event(self.dialog.tools, widgetUtils.BUTTON_PRESSED, self.show_tools_menu) - widgetUtils.connect_event(self.dialog.repost, widgetUtils.BUTTON_PRESSED, self.post_repost) -# self.dialog.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu, self.dialog.comments.list) -# self.dialog.Bind(wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key, self.dialog.comments.list) - self.worker = threading.Thread(target=self.load_all_components) - self.worker.finished = threading.Event() - self.worker.start() - self.attachments = [] - self.load_images = False - # We'll put images here, so it will be easier to work with them. - self.images = [] - self.imageIndex = 0 - - def get_comments(self): - """ 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) - comments_ = [] - for i in self.comments["items"]: - # If comment has a "deleted" key it should not be displayed, obviously. - if "deleted" in i: - continue - from_ = get_user(i["from_id"], self.comments["profiles"]) - if "reply_to_user" in i: - extra_info = get_user(i["reply_to_user"], self.comments["profiles"]) - 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"]) - comments_.append((from_, text, created_at, likes)) - try: - self.dialog.insert_comments(comments_) - except wx.PyDeadObjectError: - pass - - def get_post_information(self): - from_ = self.session.get_user_name(self.post[self.user_identifier]) - if "copy_history" in self.post: - # Translators: {0} will be replaced with an user. - title = _("repost from {0}").format(from_,) - else: - if ("from_id" in self.post and "owner_id" in self.post) and (self.post["from_id"] != self.post["owner_id"]): - # 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 wall").format(self.session.get_user_name(self.post["from_id"]), self.session.get_user_name(self.post["owner_id"])) - else: - title = _("Post from {0}").format(from_,) - self.dialog.set_title(title) - message = "" - message = get_message(self.post) - if "copy_history" in self.post: - nm = "\n" - for i in self.post["copy_history"]: - nm += "{0}: {1}\n\n".format(self.session.get_user_name(i["from_id"]), get_message(i)) - self.get_attachments(i) - message += nm - self.dialog.set_post(message) - self.get_attachments(self.post) - self.check_image_load() - - def get_attachments(self, post): - attachments = [] - if "attachments" in post: - for i in post["attachments"]: - # We don't need the photos_list attachment, so skip it. - if i["type"] == "photos_list": - continue - if i["type"] == "photo": - if self.load_images == False: self.load_images = True - self.images.append(i) - attachments.append(renderers.add_attachment(i)) - self.attachments.append(i) - # Links in text are not treated like normal attachments, so we'll have to catch and add those to the list without title - # We can't get a title because title is provided by the VK API and it will not work for links as simple text. - urls = utils.find_urls_in_text(self.dialog.get("post_view")) - if len(urls) > 0: - links = [] - for i in urls: - links.append({"link": {"title": _("Untitled link"), "url": i}, "type": "link"}) - for i in links: - attachments.append(renderers.add_attachment(i)) - self.attachments.append(i) - if len(self.attachments) > 0: - self.dialog.attachments.list.Enable(True) - self.dialog.attachments.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.open_attachment) - self.dialog.insert_attachments(attachments) - - def check_image_load(self): - if self.load_images and len(self.images) > 0 and self.session.settings["general"]["load_images"]: - self.dialog.image.Enable(True) - nav = False # Disable navigation controls in photos - if len(self.images) > 1: - nav = True - widgetUtils.connect_event(self.dialog.previous_photo, widgetUtils.BUTTON_PRESSED, self.set_previous_image) - widgetUtils.connect_event(self.dialog.next_photo, widgetUtils.BUTTON_PRESSED, self.set_next_image) - self.dialog.enable_photo_controls(navigation=nav) - self.set_image(0) - - def set_next_image(self, *args, **kwargs): - if self.imageIndex < -1 or self.imageIndex == len(self.images)-1: - self.imageIndex = -1 - if len(self.images) <= self.imageIndex+1: - self.imageIndex = 0 - else: - self.imageIndex = self.imageIndex + 1 - self.set_image(self.imageIndex) - - def set_previous_image(self, *args, **kwargs): - if self.imageIndex <= 0: - self.imageIndex = len(self.images) - self.imageIndex = self.imageIndex - 1 - self.set_image(self.imageIndex) - - def set_image(self, index): - if len(self.images) < index-1: - log.exception("Error in loading image {0} in a list with {1} images".format(index, len(self.images))) - return - # Get's photo URL. - url = self.get_photo_url(self.images[index]["photo"], "x") - if url != "": - img = requests.get(url) - img_data = six.BytesIO(img.content) - image = wx.Image(stream=img_data) - try: - self.dialog.image.SetBitmap(wx.Bitmap(image)) - except NameError: - return - self.dialog.SetClientSize(self.dialog.sizer.CalcMin()) - # Translators: {0} is the number of the current photo and {1} is the total number of photos. - output.speak(_("Loaded photo {0} of {1}").format(index+1, len(self.images))) - return - - def get_photo_url(self, photo, size="x"): - url = "" - for i in photo["sizes"]: - if i["type"] == size: - url = i["url"] - break - return url - - def load_all_components(self): - self.get_post_information() - self.get_likes() - self.get_reposts() - self.get_comments() - if self.post["comments"]["can_post"] == 0: - self.dialog.disable("comment") - if self.post["likes"]["can_like"] == 0 and self.post["likes"]["user_likes"] == 0: - self.dialog.disable("like") - elif self.post["likes"]["user_likes"] == 1: - self.dialog.set("like", _("&Dislike")) - if self.post["likes"]["can_publish"] == 0: - self.dialog.disable("repost") - - def post_like(self, *args, **kwargs): - if ("owner_id" in self.post) == False: - user = int(self.post[self.user_identifier]) - else: - user = int(self.post["owner_id"]) - id = int(self.post[self.post_identifier]) - if "type" in self.post: - type_ = self.post["type"] - else: - type_ = "post" - if self.dialog.get("like") == _("&Dislike"): - l = self.session.vk.client.likes.delete(owner_id=user, item_id=id, type=type_) - output.speak(_("You don't like this")) - self.post["likes"]["count"] = l["likes"] - self.post["likes"]["user_likes"] = 2 - self.get_likes() - self.dialog.set("like", _("&Like")) - else: - l = self.session.vk.client.likes.add(owner_id=user, item_id=id, type=type_) - output.speak(_("You liked this")) - self.dialog.set("like", _("&Dislike")) - self.post["likes"]["count"] = l["likes"] - self.post["likes"]["user_likes"] = 1 - self.get_likes() - - def post_repost(self, *args, **kwargs): - object_id = "wall{0}_{1}".format(self.post[self.user_identifier], self.post[self.post_identifier]) - p = messages.post(session=self.session, title=_("Repost"), caption=_("Add your comment here"), text="") - if p.message.get_response() == widgetUtils.OK: - msg = p.message.get_text().encode("utf-8") - self.session.vk.client.wall.repost(object=object_id, message=msg) - - def get_likes(self): - try: - self.dialog.set_likes(self.post["likes"]["count"]) - except wx.PyDeadObjectError: - pass - - def get_reposts(self): - try: - self.dialog.set_shares(self.post["reposts"]["count"]) - except wx.PyDeadObjectError: - pass - - def add_comment(self, *args, **kwargs): - comment = presenters.postPresenter(session=self.session, interactor=interactors.postInteractor(), view=views.post(title=_("Add a comment"), message="", text="", mode="comment")) - if hasattr(comment, "text") or hasattr(comment, "privacy"): - msg = comment.text - try: - user = self.post[self.user_identifier] - id = self.post[self.post_identifier] - self.session.vk.client.wall.addComment(owner_id=user, post_id=id, text=msg) - output.speak(_("You've posted a comment")) - if self.comments["count"] < 100: - self.clear_comments_list() - self.get_comments() - except Exception as msg: - log.error(msg) - - def clear_comments_list(self): - self.dialog.comments.clear() - - def show_comment(self, *args, **kwargs): - c = comment(self.session, self.comments["data"][self.dialog.comments.get_selected()]) - c.dialog.get_response() - - def show_menu(self, *args, **kwargs): - if self.dialog.comments.get_count() == 0: return - menu = menus.commentMenu() - widgetUtils.connect_event(self.dialog, widgetUtils.MENU, self.show_comment, menuitem=menu.open) - widgetUtils.connect_event(self.dialog, widgetUtils.MENU, self.comment_like, menuitem=menu.like) - widgetUtils.connect_event(self.dialog, widgetUtils.MENU, self.comment_unlike, menuitem=menu.unlike) - self.dialog.PopupMenu(menu, self.dialog.comments.list.GetPosition()) - - def show_menu_by_key(self, ev): - if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU: - self.show_menu() - - def show_tools_menu(self, *args, **kwargs): - menu = menus.toolsMenu() - widgetUtils.connect_event(self.dialog, widgetUtils.MENU, self.open_url, menuitem=menu.url) - widgetUtils.connect_event(self.dialog, widgetUtils.MENU, self.translate, menuitem=menu.translate) - widgetUtils.connect_event(self.dialog, widgetUtils.MENU, self.spellcheck, menuitem=menu.CheckSpelling) - self.dialog.PopupMenu(menu, self.dialog.tools.GetPosition()) - - def comment_like(self, *args, **kwargs): - comment_id = self.comments["data"][self.dialog.comments.get_selected()]["id"] - self.session.like(comment_id) - output.speak(_("You do like this comment")) - - def comment_unlike(self, *args, **kwargs): - comment_id = self.comments["data"][self.dialog.comments.get_selected()]["id"] - self.session.unlike(comment_id) - output.speak(_("You don't like this comment")) - - def translate(self, *args, **kwargs): - dlg = translator.gui.translateDialog() - if dlg.get_response() == widgetUtils.OK: - text_to_translate = self.dialog.post_view.GetValue().encode("utf-8") - dest = [x[0] for x in translator.translator.available_languages()][dlg.get("dest_lang")] - msg = translator.translator.translate(text_to_translate, target=dest) - self.dialog.post_view.ChangeValue(msg) - output.speak(_("Translated")) - else: - return - - def spellcheck(self, *args, **kwargs): - text = self.dialog.post_view.GetValue() - checker = SpellChecker.spellchecker.spellChecker(text, "") - if hasattr(checker, "fixed_text"): - self.dialog.post_view.ChangeValue(checker.fixed_text) - - def open_attachment(self, *args, **kwargs): - index = self.dialog.attachments.get_selected() - attachment = self.attachments[index] - if attachment["type"] == "audio": - a = audio(session=self.session, postObject=[attachment["audio"]]) - a.dialog.get_response() - a.dialog.Destroy() - if attachment["type"] == "link": - output.speak(_("Opening URL..."), True) - webbrowser.open_new_tab(attachment["link"]["url"]) - elif attachment["type"] == "doc": - output.speak(_("Opening document in web browser...")) - webbrowser.open(attachment["doc"]["url"]) - elif attachment["type"] == "video": - # it seems VK doesn't like to attach video links as normal URLS, so we'll have to - # get the full video object and use its "player" key which will open a webbrowser in their site with a player for the video. - # see https://vk.com/dev/attachments_w and and https://vk.com/dev/video.get - # However, the flash player isn't good for visually impaired people (when you press play you won't be able to close the window with alt+f4), so it could be good to use the HTML5 player. - # For firefox, see https://addons.mozilla.org/ru/firefox/addon/force-html5-video-player-at-vk/ - # May be I could use a dialogue here for inviting people to use this addon in firefox. It seems it isn't possible to use this html5 player from the player URL. - object_id = "{0}_{1}".format(attachment["video"]["owner_id"], attachment["video"]["id"]) - video_object = self.session.vk.client.video.get(owner_id=attachment["video"]["owner_id"], videos=object_id) - video_object = video_object["items"][0] - output.speak(_("Opening video in web browser..."), True) - webbrowser.open_new_tab(video_object["player"]) - elif attachment["type"] == "photo": - output.speak(_("Opening photo in web browser..."), True) - # Possible photo sizes for looking in the attachment information. Try to use the biggest photo available. - possible_sizes = [1280, 604, 130, 75] - url = "" - for i in possible_sizes: - if "photo_{0}".format(i,) in attachment["photo"]: - url = attachment["photo"]["photo_{0}".format(i,)] - break - if url != "": - webbrowser.open_new_tab(url) - else: - log.debug("Unhandled attachment: %r" % (attachment,)) - - def __del__(self): - if hasattr(self, "worker"): - self.worker.finished.set() - -class comment(object): - def __init__(self, session, comment_object): - super(comment, self).__init__() - self.session = session - self.comment = comment_object - self.dialog = postDialogs.comment() - from_ = self.comment["from"]["name"] - message = self.comment["message"] - original_date = arrow.get(self.comment["created_time"], "YYYY-MM-DTHH:m:sZ", locale="en") - created_at = original_date.humanize(locale=languageHandler.curLang[:2]) - self.dialog.set_post(message) - self.dialog.set_title(_("Comment from {0}").format(from_,)) - widgetUtils.connect_event(self.dialog.like, widgetUtils.BUTTON_PRESSED, self.post_like) - call_threaded(self.get_likes) - - def get_likes(self): - self.likes = self.session.fb.client.get_connections(id=self.comment["id"], connection_name="likes", summary=True) - self.dialog.set_likes(self.likes["summary"]["total_count"]) - - def post_like(self, *args, **kwargs): - lk = self.session.like(self.comment["id"]) - self.get_likes() - -class audio(postController): - def __init__(self, session, postObject): - self.added_audios = {} - self.session = session - self.post = postObject - self.dialog = postDialogs.audio() - widgetUtils.connect_event(self.dialog.list, widgetUtils.LISTBOX_CHANGED, self.handle_changes) - self.load_audios() - self.fill_information(0) - widgetUtils.connect_event(self.dialog.download, widgetUtils.BUTTON_PRESSED, self.download) - widgetUtils.connect_event(self.dialog.play, widgetUtils.BUTTON_PRESSED, self.play) - widgetUtils.connect_event(self.dialog.add, widgetUtils.BUTTON_PRESSED, self.add_to_library) - widgetUtils.connect_event(self.dialog.remove, widgetUtils.BUTTON_PRESSED, self.remove_from_library) - - def add_to_library(self, *args, **kwargs): - post = self.post[self.dialog.get_audio()] - args = {} - args["audio_id"] = post["id"] - if "album_id" in post: - args["album_id"] = post["album_id"] - args["owner_id"] = post["owner_id"] - audio = self.session.vk.client.audio.add(**args) - if audio != None and int(audio) > 21: - self.added_audios[post["id"]] = audio - self.dialog.change_state("add", False) - self.dialog.change_state("remove", True) - - def remove_from_library(self, *args, **kwargs): - post = self.post[self.dialog.get_audio()] - args = {} - if post["id"] in self.added_audios: - args["audio_id"] = self.added_audios[post["id"]] - args["owner_id"] = self.session.user_id - else: - args["audio_id"] = post["id"] - args["owner_id"] = post["owner_id"] - result = self.session.vk.client.audio.delete(**args) - if int(result) == 1: - self.dialog.change_state("add", True) - self.dialog.change_state("remove", False) - if post["id"] in self.added_audios: - self.added_audios.pop(post["id"]) - - def fill_information(self, index): - post = self.post[index] - if "artist" in post: - self.dialog.set("artist", post["artist"]) - if "title" in post: - self.dialog.set("title", post["title"]) - if "duration" in post: - self.dialog.set("duration", utils.seconds_to_string(post["duration"])) - self.dialog.set_title("{0} - {1}".format(post["title"], post["artist"])) - call_threaded(self.get_lyrics) - if post["owner_id"] == self.session.user_id or (post["id"] in self.added_audios) == True: - self.dialog.change_state("remove", True) - self.dialog.change_state("add", False) - else: - self.dialog.change_state("add", True) - self.dialog.change_state("remove", False) - - def get_lyrics(self): - post = self.post[self.dialog.get_audio()] - if "lyrics_id" in post: - l = self.session.vk.client.audio.getLyrics(lyrics_id=int(post["lyrics_id"])) - self.dialog.set("lyric", l["text"]) - else: - self.dialog.change_state("lyric", False) - - def download(self, *args, **kwargs): - post = self.post[self.dialog.get_audio()] - f = "{0} - {1}.mp3".format(post["title"], post["artist"]) - path = self.dialog.get_destination_path(f) - if path != None: - pub.sendMessage("download-file", url=post["url"], filename=path) - - def play(self, *args, **kwargs): - post = self.post[self.dialog.get_audio()] - pub.sendMessage("play-audio", audio_object=post) - - def load_audios(self): - for i in self.post: - s = "{0} - {1}. {2}".format(i["title"], i["artist"], utils.seconds_to_string(i["duration"])) - self.dialog.insert_audio(s) - self.dialog.list.SetSelection(0) - if len(self.post) == 1: - self.dialog.list.Enable(False) - self.dialog.title.SetFocus() - - def handle_changes(self, *args, **kwargs): - p = self.dialog.get_audio() - self.fill_information(p) - -class friendship(object): - - def __init__(self, session, post): - self.session = session - self.post = post - self.dialog = postDialogs.friendship() - list_of_friends = self.get_friend_names() - from_ = self.session.get_user_name(self.post["source_id"]) - title = _("{0} added the following friends").format(from_,) - self.dialog.set_title(title) - self.set_friends_list(list_of_friends) - - def get_friend_names(self): - self.friends = self.post["friends"]["items"] - return [self.session.get_user_name(i["user_id"]) for i in self.friends] - - def set_friends_list(self, friendslist): - for i in friendslist: - self.dialog.friends.insert_item(False, *[i]) diff --git a/src/interactors/postDisplayer.py b/src/interactors/postDisplayer.py index a573622..6dcaa5e 100644 --- a/src/interactors/postDisplayer.py +++ b/src/interactors/postDisplayer.py @@ -4,7 +4,6 @@ import six import widgetUtils import wx from pubsub import pub -from wxUI.dialogs import postDialogs, urlList from wxUI import menus from .import base @@ -57,6 +56,7 @@ class displayPostInteractor(base.baseInteractor): pub.subscribe(self.enable_photo_controls, self.modulename+"_enable_photo_controls") def uninstall(self): + super(displayPostInteractor, self).uninstall() pub.unsubscribe(self.set, self.modulename+"_set") pub.unsubscribe(self.load_image, self.modulename+"_load_image") pub.unsubscribe(self.add_items, self.modulename+"_add_items") @@ -127,6 +127,7 @@ class displayAudioInteractor(base.baseInteractor): pub.subscribe(self.add_items, self.modulename+"_add_items") def uninstall(self): + super(displayAudioInteractor, self).uninstall() pub.unsubscribe(self.set, self.modulename+"_set") pub.unsubscribe(self.add_items, self.modulename+"_add_items") @@ -150,4 +151,21 @@ class displayAudioInteractor(base.baseInteractor): def on_remove_from_library(self, *args, **kwargs): post = self.view.get_audio() - self.presenter.remove_from_library(post) \ No newline at end of file + self.presenter.remove_from_library(post) + +class displayFriendshipInteractor(base.baseInteractor): + + def add_items(self, control, items): + if not hasattr(self.view, control): + raise AttributeError("The control is not present in the view.") + for i in items: + getattr(self.view, control).insert_item(False, *[i]) + + + def install(self, *args, **kwargs): + super(displayFriendshipInteractor, self).install(*args, **kwargs) + pub.subscribe(self.add_items, self.modulename+"_add_items") + + def uninstall(self): + super(displayFriendshipInteractor, self).install() + pub.unsubscribe(self.add_items, self.modulename+"_add_items") \ No newline at end of file diff --git a/src/presenters/postDisplayer.py b/src/presenters/postDisplayer.py index 750a774..178983f 100644 --- a/src/presenters/postDisplayer.py +++ b/src/presenters/postDisplayer.py @@ -12,7 +12,6 @@ import interactors import output import webbrowser import logging -from wxUI.dialogs import postDialogs from sessionmanager import session, renderers, utils # We'll use some functions from there from pubsub import pub from extra import SpellChecker, translator @@ -20,6 +19,8 @@ from mysc.thread_utils import call_threaded from .import base from .postCreation import createPostPresenter +log = logging.getLogger(__file__) + def get_user(id, profiles): """ Returns an user name and last name based in the id receibed.""" for i in profiles: @@ -39,6 +40,7 @@ class displayPostPresenter(base.basePresenter): def __init__(self, session, postObject, view, interactor): super(displayPostPresenter, self).__init__(view=view, interactor=interactor, modulename="display_post") + self.type = "post" self.session = session self.post = postObject # Posts from newsfeed contains this source_id instead from_id in walls. Also it uses post_id and walls use just id. @@ -206,7 +208,7 @@ class displayPostPresenter(base.basePresenter): if "type" in self.post: type_ = self.post["type"] else: - type_ = "post" + type_ = self.type if self.post["likes"]["user_likes"] == 1: l = self.session.vk.client.likes.delete(owner_id=user, item_id=id, type=type_) output.speak(_("You don't like this")) @@ -254,18 +256,8 @@ class displayPostPresenter(base.basePresenter): self.send_message("clear_list", list="comments") def show_comment(self, comment_index): - c = comment(self.session, self.comments["items"][comment_index]) - c.dialog.get_response() - - def comment_like(self, comment): - comment_id = self.comments["data"][comment]["id"] - self.session.like(comment_id) - output.speak(_("You do like this comment")) - - def comment_dislike(self, comment): - comment_id = self.comments["data"][comment]["id"] - self.session.unlike(comment_id) - output.speak(_("You don't like this comment")) + c = self.comments["items"][comment_index] + a = displayCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayPost()) def translate(self, text, language): msg = translator.translator.translate(text, language) @@ -283,8 +275,8 @@ class displayPostPresenter(base.basePresenter): def open_attachment(self, index): attachment = self.attachments[index] if attachment["type"] == "audio": - a = displayAudioPresenter(session=self.session, postObject=[attachment["audio"]], interactor=interactors.displayAudioInteractor(), view=postDialogs.audio()) - if attachment["type"] == "link": + a = displayAudioPresenter(session=self.session, postObject=[attachment["audio"]], interactor=interactors.displayAudioInteractor(), view=views.displayAudio()) + elif attachment["type"] == "link": output.speak(_("Opening URL..."), True) webbrowser.open_new_tab(attachment["link"]["url"]) elif attachment["type"] == "doc": @@ -320,6 +312,51 @@ class displayPostPresenter(base.basePresenter): if hasattr(self, "worker"): self.worker.finished.set() +class displayCommentPresenter(displayPostPresenter): + + def __init__(self, session, postObject, view, interactor): + self.type = "comment" + self.modulename = "display_comment" + self.interactor = interactor + self.view = view + self.interactor.install(view=view, presenter=self, modulename=self.modulename) + self.session = session + self.post = postObject + self.user_identifier = "from_id" + self.post_identifier = "id" + self.worker = threading.Thread(target=self.load_all_components) + self.worker.finished = threading.Event() + self.worker.start() + self.attachments = [] + self.load_images = False + # We'll put images here, so it will be easier to work with them. + self.images = [] + self.imageIndex = 0 + self.run() + + 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") + 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"])) + self.send_message("set_title", value=title) + message = "" + message = get_message(self.post) + self.send_message("set", control="post_view", value=message) + self.get_attachments(self.post, message) + self.check_image_load() + class displayAudioPresenter(base.basePresenter): def __init__(self, session, postObject, view, interactor): super(displayAudioPresenter, self).__init__(view=view, interactor=interactor, modulename="display_audio") @@ -409,3 +446,23 @@ class displayAudioPresenter(base.basePresenter): def handle_changes(self, audio_index): self.fill_information(audio_index) + +class displayFriendshipPresenter(base.basePresenter): + + def __init__(self, session, postObject, view, interactor): + self.session = session + self.post = postObject + super(displayFriendshipPresenter, self).__init__(view=view, interactor=interactor, modulename="display_friendship") + list_of_friends = self.get_friend_names() + from_ = self.session.get_user_name(self.post["source_id"]) + title = _("{0} added the following friends").format(from_,) + self.send_message("set_title", value=title) + self.set_friends_list(list_of_friends) + self.run() + + def get_friend_names(self): + self.friends = self.post["friends"]["items"] + return [self.session.get_user_name(i["user_id"]) for i in self.friends] + + def set_friends_list(self, friendslist): + self.send_message("add_items", control="friends", items=friendslist) \ No newline at end of file diff --git a/src/views/__init__.py b/src/views/__init__.py index 93df602..5ee8491 100644 --- a/src/views/__init__.py +++ b/src/views/__init__.py @@ -6,5 +6,6 @@ from .dialogs.attach import * from .dialogs.audioRecorder import * from .dialogs.postCreation import * +from .dialogs.postDisplay import * from .dialogs.configuration import * from .dialogs.profiles import * \ No newline at end of file diff --git a/src/views/dialogs/postCreation.py b/src/views/dialogs/postCreation.py index e9f1026..48e6597 100644 --- a/src/views/dialogs/postCreation.py +++ b/src/views/dialogs/postCreation.py @@ -3,9 +3,9 @@ from __future__ import unicode_literals import wx import widgetUtils -class textMessage(widgetUtils.BaseDialog): +class createTextMessage(widgetUtils.BaseDialog): def __init__(self, *args, **kwargs): - super(textMessage, self).__init__(parent=None, *args, **kwargs) + super(createTextMessage, self).__init__(parent=None, *args, **kwargs) def createTextArea(self, message="", text=""): self.panel = wx.Panel(self) @@ -52,7 +52,7 @@ class textMessage(widgetUtils.BaseDialog): def get_position(self): return self.text.GetInsertionPoint() -class post(textMessage): +class createPostDialog(createTextMessage): def createControls(self, title, message, text, mode): self.mainBox = wx.BoxSizer(wx.VERTICAL) self.createTextArea(message, text) @@ -86,11 +86,11 @@ class post(textMessage): self.SetTitle(title) def __init__(self, title, message, text, mode="post"): - super(post, self).__init__() + super(createPostDialog, self).__init__() self.createControls(title, message, text, mode) self.SetClientSize(self.mainBox.CalcMin()) -class comment(textMessage): +class createCommentDialog(createTextMessage): def createControls(self, title, message, text): self.mainBox = wx.BoxSizer(wx.VERTICAL) self.createTextArea(message, text) @@ -118,6 +118,6 @@ class comment(textMessage): self.SetTitle(title) def __init__(self, title, message, text): - super(comment, self).__init__() + super(createCommentDialog, self).__init__() self.createControls(message, title, text) self.SetClientSize(self.mainBox.CalcMin()) diff --git a/src/wxUI/dialogs/postDialogs.py b/src/views/dialogs/postDisplay.py similarity index 93% rename from src/wxUI/dialogs/postDialogs.py rename to src/views/dialogs/postDisplay.py index 45199a2..5589f5e 100644 --- a/src/wxUI/dialogs/postDialogs.py +++ b/src/views/dialogs/postDisplay.py @@ -3,9 +3,9 @@ from __future__ import unicode_literals import wx import widgetUtils -class basicPost(widgetUtils.BaseDialog): +class displayBasicPost(widgetUtils.BaseDialog): def __init__(self, *args, **kwargs): - super(basicPost, self).__init__(parent=None, *args, **kwargs) + super(displayBasicPost, self).__init__(parent=None, *args, **kwargs) self.panel = wx.Panel(self, -1) self.sizer = wx.BoxSizer(wx.VERTICAL) @@ -109,9 +109,9 @@ class basicPost(widgetUtils.BaseDialog): else: return False -class post(basicPost): +class displayPost(displayBasicPost): def __init__(self, *args, **kwargs): - super(post, self).__init__(*args, **kwargs) + super(displayPost, 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() @@ -132,9 +132,9 @@ class post(basicPost): self.sizer.Add(self.create_dialog_buttons()) self.done() -class comment(basicPost): +class displayComment(displayBasicPost): def __init__(self, *args, **kwargs): - super(comment, self).__init__(*args, **kwargs) + super(displayComment, self).__init__(*args, **kwargs) post_view_box = self.create_post_view() self.sizer.Add(post_view_box, 0, wx.ALL, 5) self.create_tools_button() @@ -146,9 +146,9 @@ class comment(basicPost): self.sizer.Add(self.create_dialog_buttons()) self.done() -class audio(widgetUtils.BaseDialog): +class displayAudio(widgetUtils.BaseDialog): def __init__(self, *args, **kwargs): - super(audio, self).__init__(parent=None, *args, **kwargs) + super(displayAudio, self).__init__(parent=None, *args, **kwargs) panel = wx.Panel(self) sizer = wx.BoxSizer(wx.VERTICAL) lbl_list = wx.StaticText(panel, wx.NewId(), _("Audio &files")) @@ -210,9 +210,9 @@ class audio(widgetUtils.BaseDialog): def get_audio(self): return self.list.GetSelection() -class friendship(widgetUtils.BaseDialog): +class displayFriendship(widgetUtils.BaseDialog): def __init__(self): - super(friendship, self).__init__(parent=None) + super(displayFriendship, self).__init__(parent=None) panel = wx.Panel(self) sizer = wx.BoxSizer(wx.VERTICAL) self.friends = widgetUtils.list(panel, [_("Friend")], style=wx.LC_REPORT)