From 5f224a077cfb5f95b8df3acb86e467b45989b137 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Tue, 16 Apr 2019 12:24:42 -0500 Subject: [PATCH] Reordered presenters for post display and cretion --- src/presenters/__init__.py | 4 +- src/presenters/__pycache__/__init__.py | 19 + src/presenters/createPosts/__init__.py | 2 + .../basePost.py} | 4 +- src/presenters/displayPosts/__init__.py | 8 + src/presenters/displayPosts/audio.py | 98 ++++ .../basePost.py} | 420 +----------------- src/presenters/displayPosts/comment.py | 105 +++++ src/presenters/displayPosts/peopleList.py | 50 +++ src/presenters/displayPosts/poll.py | 55 +++ src/presenters/displayPosts/topic.py | 137 ++++++ src/presenters/displayPosts/topicComment.py | 28 ++ 12 files changed, 514 insertions(+), 416 deletions(-) create mode 100644 src/presenters/__pycache__/__init__.py create mode 100644 src/presenters/createPosts/__init__.py rename src/presenters/{postCreation.py => createPosts/basePost.py} (97%) create mode 100644 src/presenters/displayPosts/__init__.py create mode 100644 src/presenters/displayPosts/audio.py rename src/presenters/{postDisplayer.py => displayPosts/basePost.py} (52%) create mode 100644 src/presenters/displayPosts/comment.py create mode 100644 src/presenters/displayPosts/peopleList.py create mode 100644 src/presenters/displayPosts/poll.py create mode 100644 src/presenters/displayPosts/topic.py create mode 100644 src/presenters/displayPosts/topicComment.py diff --git a/src/presenters/__init__.py b/src/presenters/__init__.py index 7e7e8ea..f11bea9 100644 --- a/src/presenters/__init__.py +++ b/src/presenters/__init__.py @@ -13,7 +13,7 @@ """ from .attach import * from .audioRecorder import * -from .postCreation import * -from .postDisplayer import * +from .createPosts import * +from .displayPosts import * from .configuration import * from .profiles import * \ No newline at end of file diff --git a/src/presenters/__pycache__/__init__.py b/src/presenters/__pycache__/__init__.py new file mode 100644 index 0000000..7e7e8ea --- /dev/null +++ b/src/presenters/__pycache__/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +""" A "presenter" in the socializer's terminology is a module that handles business logic in the application's workflow. + All presenter classes should derive from base.basePresenter and will be completely abstracted from views (the GUI elements). It means presenters and views don't know anything about the each other. + Both Presenters and views can communicate through the interactors. Interactors are responsible to receive user input and send requests to the presenters, aswell as receiving presenter requests and render those in the view. + So, in a tipical user interaction made in socializer, the following could happen when someone decides to do something: + 1. A new presenter is created, with two mandatory arguments: The corresponding view and interactor. + 2. The presenter will call to the install() method in the interactor, to connect all GUI events to their corresponding methods. All of these functions will be present in the interactor only. + 3. After install(), the presenter will run the View, which will display the graphical user interface that users can see and interact with. The view is the only layer directly accessible from the user world and does not handle any kind of logic. + 4. If the user presses a button or generates an event connected to a function in the interactor side, the function will be executed in the interactor. The interactor is aware of the View, and holds a reference to the presenter. The interactor should call other GUI elements if necessary and handle some logic (related to GUI, like yes/no dialogs). The interactor can call the presenter to retrieve some information, though the interactor cannot perform any business logic (like altering the cache database, retrieving usernames and so on). + 5. If the interactor calls something in the presenter, it will be executed. The presenter knows everything about VK and the session object, so it will fetch data, save it in the cache, call other methods from VK and what not. If the presenter wants to change something in the GUI elements (for example, hiding a control or displaying something else), it will send a pubsub event that the interactor will receive and act on accordingly. + + By using this design pattern it allows more decoupled code, easier testing (as we don't need to instantiate the views) and easy to switch (or add) a new graphical user interface by replacing interactors and views. +""" +from .attach import * +from .audioRecorder import * +from .postCreation import * +from .postDisplayer import * +from .configuration import * +from .profiles import * \ No newline at end of file diff --git a/src/presenters/createPosts/__init__.py b/src/presenters/createPosts/__init__.py new file mode 100644 index 0000000..ecd8504 --- /dev/null +++ b/src/presenters/createPosts/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from .basePost import * \ No newline at end of file diff --git a/src/presenters/postCreation.py b/src/presenters/createPosts/basePost.py similarity index 97% rename from src/presenters/postCreation.py rename to src/presenters/createPosts/basePost.py index 0d45435..c3af745 100644 --- a/src/presenters/postCreation.py +++ b/src/presenters/createPosts/basePost.py @@ -7,8 +7,8 @@ import output from logging import getLogger from pubsub import pub from extra import SpellChecker, translator -from .import attach -from .import base +from presenters import attach +from presenters import base log = getLogger("controller.message") diff --git a/src/presenters/displayPosts/__init__.py b/src/presenters/displayPosts/__init__.py new file mode 100644 index 0000000..dcdbe5f --- /dev/null +++ b/src/presenters/displayPosts/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from .basePost import * +from .audio import * +from .comment import * +from .peopleList import * +from .poll import * +from .topic import * +from .topicComment import * \ No newline at end of file diff --git a/src/presenters/displayPosts/audio.py b/src/presenters/displayPosts/audio.py new file mode 100644 index 0000000..52cbd78 --- /dev/null +++ b/src/presenters/displayPosts/audio.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +import logging +from sessionmanager import utils +from pubsub import pub +from mysc.thread_utils import call_threaded +from presenters import base + +log = logging.getLogger(__file__) + +class displayAudioPresenter(base.basePresenter): + def __init__(self, session, postObject, view, interactor): + super(displayAudioPresenter, self).__init__(view=view, interactor=interactor, modulename="display_audio") + self.added_audios = {} + self.session = session + self.post = postObject + self.load_audios() + self.fill_information(0) + self.run() + + def add_to_library(self, audio_index): + post = self.post[audio_index] + 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.send_message("disable_control", control="add") + self.send_message("enable_control", control="remove") + + def remove_from_library(self, audio_index): + post = self.post[audio_index] + 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.send_message("enable_control", control="add") + self.send_message("disable_control", control="remove") + 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.send_message("set", control="artist", value=post["artist"]) + if "title" in post: + self.send_message("set", control="title", value=post["title"]) + if "duration" in post: + self.send_message("set", control="duration", value=utils.seconds_to_string(post["duration"])) + self.send_message("set_title", value="{0} - {1}".format(post["title"], post["artist"])) + call_threaded(self.get_lyrics, index) + if post["owner_id"] == self.session.user_id or (post["id"] in self.added_audios) == True: + self.send_message("enable_control", control="remove") + self.send_message("disable_control", control="add") + else: + self.send_message("enable_control", control="add") + self.send_message("disable_control", control="remove") + + def get_lyrics(self, audio_index): + post = self.post[audio_index] + if "lyrics_id" in post: + l = self.session.vk.client.audio.getLyrics(lyrics_id=int(post["lyrics_id"])) + self.send_message("set", control="lyric", value=l["text"]) + else: + self.send_message("disable_control", control="lyric") + + def get_suggested_filename(self, audio_index): + post = self.post[audio_index] + return "{0} - {1}.mp3".format(post["title"], post["artist"]) + + def download(self, audio_index, path): + post = self.post[audio_index] + if path != None: + pub.sendMessage("download-file", url=post["url"], filename=path) + + def play(self, audio_index): + post = self.post[audio_index] + pub.sendMessage("play", object=post) + + def load_audios(self): + audios = [] + for i in self.post: + s = "{0} - {1}. {2}".format(i["title"], i["artist"], utils.seconds_to_string(i["duration"])) + audios.append(s) + self.send_message("add_items", control="list", items=audios) + if len(self.post) == 1: + self.send_message("disable_control", control="list") + self.send_message("focus_control", control="title") + + def handle_changes(self, audio_index): + self.fill_information(audio_index) \ No newline at end of file diff --git a/src/presenters/postDisplayer.py b/src/presenters/displayPosts/basePost.py similarity index 52% rename from src/presenters/postDisplayer.py rename to src/presenters/displayPosts/basePost.py index 463081e..2fcae58 100644 --- a/src/presenters/postDisplayer.py +++ b/src/presenters/displayPosts/basePost.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -import os -import six import threading import arrow import requests @@ -15,8 +13,9 @@ from sessionmanager import session, renderers, utils # We'll use some functions from pubsub import pub from extra import SpellChecker, translator from mysc.thread_utils import call_threaded -from .import base -from .postCreation import createPostPresenter +from presenters import base +from presenters.createPosts.basePost import createPostPresenter +from . import audio, poll log = logging.getLogger(__file__) @@ -354,9 +353,10 @@ class displayPostPresenter(base.basePresenter): call_threaded(self.do_last, comment, owner_id=c["owner_id"], reply_to_comment=c["id"], post_id=c["post_id"], reply_to_user=c["owner_id"]) def show_comment(self, comment_index): + from . import comment c = self.comments["items"][comment_index] c["post_id"] = self.post[self.post_identifier] - a = displayCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment()) + a = comment.displayCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment()) def translate(self, text, language): msg = translator.translator.translate(text, language) @@ -374,7 +374,7 @@ 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=views.displayAudio()) + a = audio.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"]) @@ -405,7 +405,7 @@ class displayPostPresenter(base.basePresenter): if url != "": webbrowser.open_new_tab(url) elif attachment["type"] == "poll": - a = displayPollPresenter(session=self.session, poll=attachment, interactor=interactors.displayPollInteractor(), view=views.displayPoll()) + a = poll.displayPollPresenter(session=self.session, poll=attachment, interactor=interactors.displayPollInteractor(), view=views.displayPoll()) else: log.debug("Unhandled attachment: %r" % (attachment,)) @@ -430,408 +430,4 @@ class displayPostPresenter(base.basePresenter): result = self.session.vk.client.likes.getList(**data) if result["count"] > 0: post = {"source_id": self.post[self.user_identifier], "friends": {"items": result["items"]}} - pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("people who shared this"))) - -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="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")) - - def get_post_information(self): - from_ = self.session.get_user(self.post[self.user_identifier]) - if ("from_id" in self.post and "owner_id" in self.post): - user2 = self.session.get_user(self.post["owner_id"], "user2") - user2.update(from_) - title = _("Comment from {user1_nom} in the {user2_nom}'s post").format(**user2) - 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() - - def reply(self, *args, **kwargs): - comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {user1_nom}").format(**self.session.get_user(self.post["from_id"])), message="", text="", mode="comment")) - if hasattr(comment, "text") or hasattr(comment, "privacy"): - call_threaded(self.do_last, comment, owner_id=self.post["owner_id"], reply_to_comment=self.post["id"], post_id=self.post["post_id"], reply_to_user=self.post["owner_id"]) - - def get_comments(self): - """ Get comments and insert them in a list.""" - comments_ = [] - if "thread" not in self.post: - return - 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(i["from_id"]) - if "reply_to_user" in i: - extra_info = self.session.get_user(i["reply_to_user"], "user2") - extra_info.update(from_) - from_ = _("{user1_nom} > {user2_nom}").format(**extra_info) - else: - from_ = from_["user1_nom"] - # As we set the comment reply properly in the from_ field, let's remove the first username from here if it exists. - fixed_text = utils.clean_text(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()) - self.clear_comments_list() - -class displayTopicCommentPresenter(displayCommentPresenter): - - def get_post_information(self): - from_ = self.session.get_user(self.post[self.user_identifier]) - title = from_["user1_nom"] - 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() - self.send_message("disable_control", control="reply") - self.send_message("disable_control", control="comments") - -class displayTopicPresenter(displayPostPresenter): - - def __init__(self, session, postObject, group_id, view, interactor): - self.type = "topic" - self.modulename = "display_topic" - self.interactor = interactor - self.view = view - self.interactor.install(view=view, presenter=self, modulename=self.modulename) - self.session = session - self.post = postObject - self.group_id = group_id - self.load_images = False - # We'll put images here, so it will be easier to work with them. - self.images = [] - self.imageIndex = 0 - result = self.get_post_information() - # Stop loading everything else if post was deleted. - if result == False: - self.interactor.uninstall() - return - self.worker = threading.Thread(target=self.load_all_components) - self.worker.finished = threading.Event() - self.worker.start() - self.attachments = [] - self.run() - - def load_all_components(self): - self.get_comments() - - def get_post_information(self): - title = self.post["title"] - self.send_message("set_title", value=title) - return True - - def get_comments(self): - """ Get comments and insert them in a list.""" - self.comments = self.session.vk.client.board.getComments(group_id=self.group_id, topic_id=self.post["id"], need_likes=1, count=100, extended=1) - comments_ = [] - data = dict(profiles=self.comments["profiles"], groups=[]) - self.session.process_usernames(data) - for i in self.comments["items"]: - # If comment has a "deleted" key it should not be displayed, obviously. - if "deleted" in i: - continue - from_ = self.session.get_user(i["from_id"])["user1_nom"] - # match user mentions inside text comment. - original_date = arrow.get(i["date"]) - created_at = original_date.humanize(locale=languageHandler.curLang[:2]) - likes = str(i["likes"]["count"]) - text = utils.clean_text(text=i["text"]) - comments_.append((from_, text, created_at, likes)) - self.send_message("add_items", control="comments", items=comments_) - - def post_like(self): - c = self.interactor.view.comments.get_selected() - id = self.comments["items"][c]["id"] - if self.comments["items"][c]["likes"]["user_likes"] == 1: - l = self.session.vk.client.likes.delete(owner_id=-1*self.group_id, item_id=id, type="topic_comment") - output.speak(_("You don't like this")) - self.comments["items"][c]["likes"]["count"] = l["likes"] - self.comments["items"][c]["likes"]["user_likes"] = 2 - self.send_message("set_label", control="like", label=_("&Like")) - else: - l = self.session.vk.client.likes.add(owner_id=-1*self.group_id, item_id=id, type="topic_comment") - output.speak(_("You liked this")) - self.send_message("set_label", control="like", label=_("&Dislike")) - self.comments["items"][c]["likes"]["count"] = l["likes"] - self.comments["items"][c]["likes"]["user_likes"] = 1 - self.clear_comments_list() - - def change_comment(self, comment): - comment = self.comments["items"][comment] - self.send_message("clean_list", list="attachments") - self.get_attachments(comment, "") - if comment["likes"]["user_likes"] == 1: - self.send_message("set_label", control="like", label=_("&Dislike")) - else: - self.send_message("set_label", control="like", label=_("&Like")) - - def add_comment(self): - 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"): - group_id = self.group_id - topic_id = self.post["id"] - call_threaded(self.do_last, comment, group_id=group_id, topic_id=topic_id) - - def do_last(self, comment, **kwargs): - msg = comment.text - attachments = "" - if hasattr(comment, "attachments"): - attachments = self.upload_attachments(comment.attachments) - urls = utils.find_urls_in_text(msg) - if len(urls) != 0: - if len(attachments) == 0: attachments = urls[0] - else: attachments += urls[0] - msg = msg.replace(urls[0], "") - if msg != "": - kwargs.update(message=msg) - if attachments != "": - kwargs.update(attachments=attachments) - if "message" not in kwargs and "attachments" not in kwargs: - return # No comment made here. - result = self.session.vk.client.board.createComment(**kwargs) - self.clear_comments_list() - - def reply(self, comment): - c = self.comments["items"][comment] - comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {user1_nom}").format(**self.session.get_user(c["from_id"])), message="", text="", mode="comment")) - if hasattr(comment, "text") or hasattr(comment, "privacy"): - user = self.session.get_user(c["from_id"]) - name = user["user1_nom"].split(" ")[0] - comment.text = "[post{post_id}|{name}], {text}".format(post_id=c["id"], text=comment.text, name=name) - group_id = self.group_id - topic_id = self.post["id"] - call_threaded(self.do_last, comment, group_id=group_id, topic_id=topic_id, reply_to_comment=c["id"]) - - def show_comment(self, comment_index): - c = self.comments["items"][comment_index] - c["post_id"] = self.post["id"] - a = displayTopicCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment()) - -class displayPollPresenter(base.basePresenter): - - def __init__(self, session, poll, view, interactor, show_results=False): - super(displayPollPresenter, self).__init__(view=view, interactor=interactor, modulename="display_poll") - self.poll = poll["poll"] - self.session = session - self.get_poll() - self.load_poll(show_results) - self.run() - - def get_poll(self): - # Retrieve the poll again so we will have a fresh and updated object. - data = dict(owner_id=self.poll["owner_id"], is_board=int(self.poll["is_board"]), poll_id=self.poll["id"]) - self.poll = self.session.vk.client.polls.getById(**data) - - def load_poll(self, load_results=False): - user = self.session.get_user(self.poll["author_id"]) - title = _("Poll from {user1_nom}").format(**user) - self.send_message("set_title", value=title) - self.send_message("set", control="question", value=self.poll["question"]) - if len(self.poll["answer_ids"]) > 0 or ("is_closed" in self.poll and self.poll["is_closed"] == True) or load_results == True or ("can_vote" in self.poll and self.poll["can_vote"] == False): - options = [] - for i in self.poll["answers"]: - options.append((i["text"], i["votes"], i["rate"])) - self.send_message("add_options", options=options, multiple=self.poll["multiple"]) - self.send_message("done") - self.send_message("disable_control", control="ok") - else: - options = [] - for i in self.poll["answers"]: - options.append(i["text"]) - self.send_message("add_options", options=options, multiple=self.poll["multiple"]) - self.send_message("done") - - def vote(self, answers): - ids = "" - for i in range(0, len(self.poll["answers"])): - if answers[i] == True: - ids = ids+"{answer_id},".format(answer_id=self.poll["answers"][i]["id"]) - if self.poll["multiple"] == False: - break - if ids == "": - log.exception("An error occurred when retrieving answer IDS for the following poll: %r. Provided answer list: %r" % (self.poll, answers)) - return - data = dict(owner_id=self.poll["owner_id"], poll_id=self.poll["id"], answer_ids=ids, is_board=int(self.poll["is_board"])) - result = self.session.vk.client.polls.addVote(**data) - if result == 1: - output.speak(_("Your vote has been added to this poll.")) - - - -class displayAudioPresenter(base.basePresenter): - def __init__(self, session, postObject, view, interactor): - super(displayAudioPresenter, self).__init__(view=view, interactor=interactor, modulename="display_audio") - self.added_audios = {} - self.session = session - self.post = postObject - self.load_audios() - self.fill_information(0) - self.run() - - def add_to_library(self, audio_index): - post = self.post[audio_index] - 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.send_message("disable_control", control="add") - self.send_message("enable_control", control="remove") - - def remove_from_library(self, audio_index): - post = self.post[audio_index] - 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.send_message("enable_control", control="add") - self.send_message("disable_control", control="remove") - 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.send_message("set", control="artist", value=post["artist"]) - if "title" in post: - self.send_message("set", control="title", value=post["title"]) - if "duration" in post: - self.send_message("set", control="duration", value=utils.seconds_to_string(post["duration"])) - self.send_message("set_title", value="{0} - {1}".format(post["title"], post["artist"])) - call_threaded(self.get_lyrics, index) - if post["owner_id"] == self.session.user_id or (post["id"] in self.added_audios) == True: - self.send_message("enable_control", control="remove") - self.send_message("disable_control", control="add") - else: - self.send_message("enable_control", control="add") - self.send_message("disable_control", control="remove") - - def get_lyrics(self, audio_index): - post = self.post[audio_index] - if "lyrics_id" in post: - l = self.session.vk.client.audio.getLyrics(lyrics_id=int(post["lyrics_id"])) - self.send_message("set", control="lyric", value=l["text"]) - else: - self.send_message("disable_control", control="lyric") - - def get_suggested_filename(self, audio_index): - post = self.post[audio_index] - return "{0} - {1}.mp3".format(post["title"], post["artist"]) - - def download(self, audio_index, path): - post = self.post[audio_index] - if path != None: - pub.sendMessage("download-file", url=post["url"], filename=path) - - def play(self, audio_index): - post = self.post[audio_index] - pub.sendMessage("play", object=post) - - def load_audios(self): - audios = [] - for i in self.post: - s = "{0} - {1}. {2}".format(i["title"], i["artist"], utils.seconds_to_string(i["duration"])) - audios.append(s) - self.send_message("add_items", control="list", items=audios) - if len(self.post) == 1: - self.send_message("disable_control", control="list") - self.send_message("focus_control", control="title") - - def handle_changes(self, audio_index): - self.fill_information(audio_index) - -class displayFriendshipPresenter(base.basePresenter): - - def __init__(self, session, postObject, view, interactor, caption=""): - 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(self.post["source_id"]) - title = caption.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"] - friends = list() - for i in self.friends: - if "user_id" in i: - friends.append(self.session.get_user(i["user_id"])["user1_nom"]) - else: - friends.append(self.session.get_user(i["id"])["user1_nom"]) - return friends - - def set_friends_list(self, friendslist): - self.send_message("add_items", control="friends", items=friendslist) - - def view_profile(self, item): - user = self.friends[item] - if "user_id" in user: - id = user["user_id"] - else: - id = user["id"] - pub.sendMessage("user-profile", person=id) - - def open_in_browser(self, item): - user = self.friends[item] - if "user_id" in user: - id = user["user_id"] - else: - id = user["id"] - url = "https://vk.com/id{user_id}".format(user_id=id) - webbrowser.open_new_tab(url) \ No newline at end of file + pub.sendMessage("open-post", post_object=post, controller_="displayFriendship", vars=dict(caption=_("people who shared this"))) \ No newline at end of file diff --git a/src/presenters/displayPosts/comment.py b/src/presenters/displayPosts/comment.py new file mode 100644 index 0000000..9750c71 --- /dev/null +++ b/src/presenters/displayPosts/comment.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +import threading +import arrow +import languageHandler +import views +import interactors +import logging +from sessionmanager import renderers, utils # We'll use some functions from there +from mysc.thread_utils import call_threaded +from presenters import base +from presenters.createPosts.basePost import createPostPresenter +from . import basePost + +log = logging.getLogger(__file__) + +def get_message(status): + message = "" + if "text" in status: + message = utils.clean_text(status["text"]) + return message + +class displayCommentPresenter(basePost.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="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")) + + def get_post_information(self): + from_ = self.session.get_user(self.post[self.user_identifier]) + if ("from_id" in self.post and "owner_id" in self.post): + user2 = self.session.get_user(self.post["owner_id"], "user2") + user2.update(from_) + title = _("Comment from {user1_nom} in the {user2_nom}'s post").format(**user2) + 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() + + def reply(self, *args, **kwargs): + comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {user1_nom}").format(**self.session.get_user(self.post["from_id"])), message="", text="", mode="comment")) + if hasattr(comment, "text") or hasattr(comment, "privacy"): + call_threaded(self.do_last, comment, owner_id=self.post["owner_id"], reply_to_comment=self.post["id"], post_id=self.post["post_id"], reply_to_user=self.post["owner_id"]) + + def get_comments(self): + """ Get comments and insert them in a list.""" + comments_ = [] + if "thread" not in self.post: + return + 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(i["from_id"]) + if "reply_to_user" in i: + extra_info = self.session.get_user(i["reply_to_user"], "user2") + extra_info.update(from_) + from_ = _("{user1_nom} > {user2_nom}").format(**extra_info) + else: + from_ = from_["user1_nom"] + # As we set the comment reply properly in the from_ field, let's remove the first username from here if it exists. + fixed_text = utils.clean_text(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()) + self.clear_comments_list() \ No newline at end of file diff --git a/src/presenters/displayPosts/peopleList.py b/src/presenters/displayPosts/peopleList.py new file mode 100644 index 0000000..cacf216 --- /dev/null +++ b/src/presenters/displayPosts/peopleList.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +import webbrowser +import logging +from pubsub import pub +from presenters import base + +log = logging.getLogger(__file__) + +class displayFriendshipPresenter(base.basePresenter): + + def __init__(self, session, postObject, view, interactor, caption=""): + 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(self.post["source_id"]) + title = caption.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"] + friends = list() + for i in self.friends: + if "user_id" in i: + friends.append(self.session.get_user(i["user_id"])["user1_nom"]) + else: + friends.append(self.session.get_user(i["id"])["user1_nom"]) + return friends + + def set_friends_list(self, friendslist): + self.send_message("add_items", control="friends", items=friendslist) + + def view_profile(self, item): + user = self.friends[item] + if "user_id" in user: + id = user["user_id"] + else: + id = user["id"] + pub.sendMessage("user-profile", person=id) + + def open_in_browser(self, item): + user = self.friends[item] + if "user_id" in user: + id = user["user_id"] + else: + id = user["id"] + url = "https://vk.com/id{user_id}".format(user_id=id) + webbrowser.open_new_tab(url) \ No newline at end of file diff --git a/src/presenters/displayPosts/poll.py b/src/presenters/displayPosts/poll.py new file mode 100644 index 0000000..4aceae3 --- /dev/null +++ b/src/presenters/displayPosts/poll.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +import output +import logging +from presenters import base + +log = logging.getLogger(__file__) + +class displayPollPresenter(base.basePresenter): + + def __init__(self, session, poll, view, interactor, show_results=False): + super(displayPollPresenter, self).__init__(view=view, interactor=interactor, modulename="display_poll") + self.poll = poll["poll"] + self.session = session + self.get_poll() + self.load_poll(show_results) + self.run() + + def get_poll(self): + # Retrieve the poll again so we will have a fresh and updated object. + data = dict(owner_id=self.poll["owner_id"], is_board=int(self.poll["is_board"]), poll_id=self.poll["id"]) + self.poll = self.session.vk.client.polls.getById(**data) + + def load_poll(self, load_results=False): + user = self.session.get_user(self.poll["author_id"]) + title = _("Poll from {user1_nom}").format(**user) + self.send_message("set_title", value=title) + self.send_message("set", control="question", value=self.poll["question"]) + if len(self.poll["answer_ids"]) > 0 or ("is_closed" in self.poll and self.poll["is_closed"] == True) or load_results == True or ("can_vote" in self.poll and self.poll["can_vote"] == False): + options = [] + for i in self.poll["answers"]: + options.append((i["text"], i["votes"], i["rate"])) + self.send_message("add_options", options=options, multiple=self.poll["multiple"]) + self.send_message("done") + self.send_message("disable_control", control="ok") + else: + options = [] + for i in self.poll["answers"]: + options.append(i["text"]) + self.send_message("add_options", options=options, multiple=self.poll["multiple"]) + self.send_message("done") + + def vote(self, answers): + ids = "" + for i in range(0, len(self.poll["answers"])): + if answers[i] == True: + ids = ids+"{answer_id},".format(answer_id=self.poll["answers"][i]["id"]) + if self.poll["multiple"] == False: + break + if ids == "": + log.exception("An error occurred when retrieving answer IDS for the following poll: %r. Provided answer list: %r" % (self.poll, answers)) + return + data = dict(owner_id=self.poll["owner_id"], poll_id=self.poll["id"], answer_ids=ids, is_board=int(self.poll["is_board"])) + result = self.session.vk.client.polls.addVote(**data) + if result == 1: + output.speak(_("Your vote has been added to this poll.")) \ No newline at end of file diff --git a/src/presenters/displayPosts/topic.py b/src/presenters/displayPosts/topic.py new file mode 100644 index 0000000..1ee8b92 --- /dev/null +++ b/src/presenters/displayPosts/topic.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +import threading +import arrow +import languageHandler +import views +import interactors +import output +import logging +from sessionmanager import utils # We'll use some functions from there +from mysc.thread_utils import call_threaded +from presenters import base +from presenters.createPosts.basePost import createPostPresenter +from . import basePost +from .topicComment import * + +log = logging.getLogger(__file__) + +class displayTopicPresenter(basePost.displayPostPresenter): + + def __init__(self, session, postObject, group_id, view, interactor): + self.type = "topic" + self.modulename = "display_topic" + self.interactor = interactor + self.view = view + self.interactor.install(view=view, presenter=self, modulename=self.modulename) + self.session = session + self.post = postObject + self.group_id = group_id + self.load_images = False + # We'll put images here, so it will be easier to work with them. + self.images = [] + self.imageIndex = 0 + result = self.get_post_information() + # Stop loading everything else if post was deleted. + if result == False: + self.interactor.uninstall() + return + self.worker = threading.Thread(target=self.load_all_components) + self.worker.finished = threading.Event() + self.worker.start() + self.attachments = [] + self.run() + + def load_all_components(self): + self.get_comments() + + def get_post_information(self): + title = self.post["title"] + self.send_message("set_title", value=title) + return True + + def get_comments(self): + """ Get comments and insert them in a list.""" + self.comments = self.session.vk.client.board.getComments(group_id=self.group_id, topic_id=self.post["id"], need_likes=1, count=100, extended=1) + comments_ = [] + data = dict(profiles=self.comments["profiles"], groups=[]) + self.session.process_usernames(data) + for i in self.comments["items"]: + # If comment has a "deleted" key it should not be displayed, obviously. + if "deleted" in i: + continue + from_ = self.session.get_user(i["from_id"])["user1_nom"] + # match user mentions inside text comment. + original_date = arrow.get(i["date"]) + created_at = original_date.humanize(locale=languageHandler.curLang[:2]) + likes = str(i["likes"]["count"]) + text = utils.clean_text(text=i["text"]) + comments_.append((from_, text, created_at, likes)) + self.send_message("add_items", control="comments", items=comments_) + + def post_like(self): + c = self.interactor.view.comments.get_selected() + id = self.comments["items"][c]["id"] + if self.comments["items"][c]["likes"]["user_likes"] == 1: + l = self.session.vk.client.likes.delete(owner_id=-1*self.group_id, item_id=id, type="topic_comment") + output.speak(_("You don't like this")) + self.comments["items"][c]["likes"]["count"] = l["likes"] + self.comments["items"][c]["likes"]["user_likes"] = 2 + self.send_message("set_label", control="like", label=_("&Like")) + else: + l = self.session.vk.client.likes.add(owner_id=-1*self.group_id, item_id=id, type="topic_comment") + output.speak(_("You liked this")) + self.send_message("set_label", control="like", label=_("&Dislike")) + self.comments["items"][c]["likes"]["count"] = l["likes"] + self.comments["items"][c]["likes"]["user_likes"] = 1 + self.clear_comments_list() + + def change_comment(self, comment): + comment = self.comments["items"][comment] + self.send_message("clean_list", list="attachments") + self.get_attachments(comment, "") + if comment["likes"]["user_likes"] == 1: + self.send_message("set_label", control="like", label=_("&Dislike")) + else: + self.send_message("set_label", control="like", label=_("&Like")) + + def add_comment(self): + 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"): + group_id = self.group_id + topic_id = self.post["id"] + call_threaded(self.do_last, comment, group_id=group_id, topic_id=topic_id) + + def do_last(self, comment, **kwargs): + msg = comment.text + attachments = "" + if hasattr(comment, "attachments"): + attachments = self.upload_attachments(comment.attachments) + urls = utils.find_urls_in_text(msg) + if len(urls) != 0: + if len(attachments) == 0: attachments = urls[0] + else: attachments += urls[0] + msg = msg.replace(urls[0], "") + if msg != "": + kwargs.update(message=msg) + if attachments != "": + kwargs.update(attachments=attachments) + if "message" not in kwargs and "attachments" not in kwargs: + return # No comment made here. + result = self.session.vk.client.board.createComment(**kwargs) + self.clear_comments_list() + + def reply(self, comment): + c = self.comments["items"][comment] + comment = createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=_("Reply to {user1_nom}").format(**self.session.get_user(c["from_id"])), message="", text="", mode="comment")) + if hasattr(comment, "text") or hasattr(comment, "privacy"): + user = self.session.get_user(c["from_id"]) + name = user["user1_nom"].split(" ")[0] + comment.text = "[post{post_id}|{name}], {text}".format(post_id=c["id"], text=comment.text, name=name) + group_id = self.group_id + topic_id = self.post["id"] + call_threaded(self.do_last, comment, group_id=group_id, topic_id=topic_id, reply_to_comment=c["id"]) + + def show_comment(self, comment_index): + c = self.comments["items"][comment_index] + c["post_id"] = self.post["id"] + a = displayTopicCommentPresenter(session=self.session, postObject=c, interactor=interactors.displayPostInteractor(), view=views.displayComment()) \ No newline at end of file diff --git a/src/presenters/displayPosts/topicComment.py b/src/presenters/displayPosts/topicComment.py new file mode 100644 index 0000000..74b9cb6 --- /dev/null +++ b/src/presenters/displayPosts/topicComment.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +import logging +from sessionmanager import renderers, utils # We'll use some functions from there +from presenters import base +from presenters.createPosts.basePost import createPostPresenter +from . import comment + +log = logging.getLogger(__file__) + +def get_message(status): + message = "" + if "text" in status: + message = utils.clean_text(status["text"]) + return message + +class displayTopicCommentPresenter(comment.displayCommentPresenter): + + def get_post_information(self): + from_ = self.session.get_user(self.post[self.user_identifier]) + title = from_["user1_nom"] + 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() + self.send_message("disable_control", control="reply") + self.send_message("disable_control", control="comments") \ No newline at end of file