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
This commit is contained in:
		| @@ -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...")) | ||||
|   | ||||
| @@ -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...") | ||||
|   | ||||
| @@ -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]) | ||||
| @@ -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") | ||||
|  | ||||
| @@ -151,3 +152,20 @@ class displayAudioInteractor(base.baseInteractor): | ||||
| 	def on_remove_from_library(self, *args, **kwargs): | ||||
| 		post = self.view.get_audio() | ||||
| 		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") | ||||
| @@ -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) | ||||
| @@ -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 * | ||||
| @@ -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()) | ||||
|   | ||||
| @@ -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) | ||||
		Reference in New Issue
	
	Block a user