54 Commits

Author SHA1 Message Date
740ae124f9 Version 2016.07.9 2016-07-12 05:10:57 -05:00
17977d2a88 Fixed a few bugs 2016-07-12 05:00:07 -05:00
ed29923d2e Improved play all function for slow connections 2016-07-10 22:59:59 -05:00
6228e7229b Removed print statements 2016-07-10 22:51:06 -05:00
677f92af68 Added a few translatable strings 2016-07-08 16:40:34 -05:00
ce43d8b30e Updated changelog 2016-07-08 16:37:43 -05:00
09470e85ce Remove a few bugs when users press enter in friend lists 2016-07-08 16:34:28 -05:00
bab896aba1 Get instrumental case for name in chat buffers. Remove set Offline option in VK at exit 2016-07-07 14:50:09 -05:00
519381684d Updated russian translations 2016-07-07 13:24:01 -05:00
a66b35190f Fixed a bug in the get_page function 2016-07-07 13:23:49 -05:00
5b655d7889 Russian: use genitive case of names in certain strings 2016-07-07 10:20:03 -05:00
e22839168d Updated russian locales 2016-07-07 09:46:18 -05:00
7036f5c5ca If an audio album is not loaded, play and play all buttons are not enabled 2016-06-30 09:30:17 -05:00
a943da1812 Now using API V5.52 2016-06-30 08:21:46 -05:00
2426ed782e Changed user_id for owner_id in audio timelines creation 2016-06-30 08:21:25 -05:00
8caf879b5c Included pandoc as a dependency 2016-06-30 04:47:54 -05:00
972702a1c6 Added spanish documentation 2016-06-29 17:26:44 -05:00
438e2fb494 Created documentation's translation catalog 2016-06-29 17:26:16 -05:00
d66db99241 Translation generators are divided in two categories, interface and documentation 2016-06-29 17:25:34 -05:00
a8bebc2808 Removed an error in the paths module 2016-06-29 17:21:00 -05:00
23ecd43fc0 Generates translatable documentation in spanish 2016-06-29 17:19:47 -05:00
fe7a085c39 Updated spanish translation 2016-06-29 13:20:57 -05:00
194b4f9bdc Updated translation catalog 2016-06-29 13:17:11 -05:00
5099ac9621 Added documentation in the help menu 2016-06-29 13:16:35 -05:00
70a3f2fff3 Updated docstrings 2016-06-29 13:15:40 -05:00
ed49bcca00 Updated documentation 2016-06-29 13:15:12 -05:00
4918c74d49 Albums are not loaded at startup. User needs to load albums per request 2016-06-29 12:33:09 -05:00
e528aa1eec Added some comments for translators 2016-06-29 10:56:41 -05:00
f5608576c9 Modified translation script. Now uses xGettext 2016-06-29 10:00:13 -05:00
d00e8cf64f Now is possible to move an audio to an album with the menu key or right click in the item 2016-06-29 04:08:37 -05:00
42c8d9bbb7 Implemented audio album removal. An album selector has been created 2016-06-28 22:32:32 -05:00
dc88d68a6c Added a new item to the audio menu 2016-06-19 12:54:38 -05:00
b278c8cde9 Added album load an creation at startup 2016-06-19 12:25:06 -05:00
47bab9d2c4 Added a context menu for most kind of buffers 2016-06-08 05:45:03 -05:00
6ef97389a0 Rmodified set_ize in lists 2016-06-08 05:13:07 -05:00
7bac05e63b Modified some parameters in the visual look for lists 2016-06-08 05:12:25 -05:00
e8e8dd91bc Modified some GUI parameters for lists 2016-06-07 05:32:27 -05:00
ba31b40d9b Updated readme 2016-06-06 04:31:37 -05:00
8d9082235b Marks read messages every two minutes 2016-06-06 04:27:07 -05:00
2b9aa467bd Added an error message when there is an exception in authorisation 2016-06-06 03:53:55 -05:00
4df4e620c1 Updated readme 2016-06-06 03:11:27 -05:00
d269888edc The build script can generate the manual 2016-06-06 03:03:24 -05:00
f46033cac5 Added a translatable manual 2016-06-06 02:41:42 -05:00
b9af6ced83 updated dependencies 2016-06-05 23:54:59 -05:00
f30a099bf4 Update some info when focusing an item in the list of posts 2016-06-05 14:15:40 -05:00
24140f9e42 Started to work in visual appearance 2016-06-05 08:11:25 -05:00
68e659d751 Removed an unneeded print 2016-06-03 11:41:19 -05:00
2cf9ee3c46 Fixed getting unread messages 2016-06-03 11:24:14 -05:00
06c3fb58a7 Create chat for unread messages. Set online and offline 2016-06-03 10:24:35 -05:00
5ac17087f4 Fixed some issues in the built version 2016-06-02 17:42:44 -05:00
8e8922b78e Added friends buffer to the list of supported timelines 2016-06-02 13:12:42 -05:00
1981093293 Deleted audios are ignored by the program 2016-06-02 13:11:42 -05:00
6634ed8e4c Removed platform information from last seen in friends 2016-05-31 13:00:51 -05:00
336a331c52 Added update information 2016-05-25 15:03:38 -05:00
49 changed files with 3851 additions and 2554 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ src/bootstrap.exe
src/Microsoft.VC90.CRT src/Microsoft.VC90.CRT
src/Microsoft.VC90.MFC src/Microsoft.VC90.MFC
src/documentation/ src/documentation/
src/com_cache/

View File

@@ -8,8 +8,8 @@ Socializer's functionality is far to be perfect, in fact there are lots of metho
Before downloading, take in to account the following: This source code is completely experimental. The current functionality in this application is not very useful. If you decide to use nightly build versions, take into account that this doesn't work as an application for everyday use yet. Before downloading, take in to account the following: This source code is completely experimental. The current functionality in this application is not very useful. If you decide to use nightly build versions, take into account that this doesn't work as an application for everyday use yet.
Version: 2016.05.25 Version: 2016.07.9
Build date: May 25 2016 Build date: Jul 9 2016
[Download socializer weekly build](https://github.com/manuelcortez/socializer/blob/master/nightly/socializer-nightly-build.zip?raw=true) [Download socializer weekly build](https://github.com/manuelcortez/socializer/blob/master/nightly/socializer-nightly-build.zip?raw=true)
I have started this effort as an open source project on Feb 13, 2016. Pull requests and bug reports are welcome. Socializer is not a definitive name for this project, it could be changed in future. I have started this effort as an open source project on Feb 13, 2016. Pull requests and bug reports are welcome. Socializer is not a definitive name for this project, it could be changed in future.
@@ -21,74 +21,19 @@ I have started this effort as an open source project on Feb 13, 2016. Pull requ
* [Python windows extensions (pywin32)](http://www.sourceforge.net/projects/pywin32/) for python 2.7, build 220 * [Python windows extensions (pywin32)](http://www.sourceforge.net/projects/pywin32/) for python 2.7, build 220
* [PyEnchant,](http://pythonhosted.org/pyenchant/) version 1.6.6. * [PyEnchant,](http://pythonhosted.org/pyenchant/) version 1.6.6.
* [VK API bindings for Python](https://github.com/dimka665/vk) (already included in the SRC directory) * [VK API bindings for Python](https://github.com/dimka665/vk) (already included in the SRC directory)
* If you want to build your own versions, [Pandoc](http://pandoc.org/installing.html) make sure you have pandoc.exe in your path variable. If not, edit scripts/build.sh.
* pypubsub * pypubsub
* configobj * configobj
* requests-oauthlib * requests-oauthlib
* future * future
* arrow==0.6 * arrow==0.6
* microsofttranslator * microsofttranslator
* [Pandoc](http://pandoc.org/installing.html) for generating the changelog.
## Running ## Documentation
Just open the main.py file with the python interpreter. This file is located in the src directory. If you haven't configured your VK account, you will see a dialogue, just press yes and a new dialogue will prompt for an user email or phone number and the password for your account. Take into account that the provided information will be saved in a config file as plain text. This application will need your information for renegotiating the access token when it expires. I am trying to write an updated manual for socializer. It can be found in the documentation folder once the program zip file is uncompressed, or in the manual.md file (in markdown). The idea of this manual is to be updated as socializer receives new features or improvements.
Note: Every time you grant access to socializer, probably You will receive an email from VK by telling you that someone has accessed to your account. It means that a new token has been negotiated between VK and socializer by using an authomatic process, you should ignore those advices, unless you receive an email when you are not logged in VK with socializer or other application. You can see your authorised applications in the configuration section in the VK website. New tokens are renegotiated every 24 hours. A copy of the English version of the manual can be read here: [Manual in the socializer's wiki](https://github.com/manuelcortez/socializer/wiki/manual)
## Main interface
If you have used [TWBlue](https://github.com/manuelcortez/twblue) before, the socializer's interface is quite similar. Once you have authorised your account, you will see a window with the following elements:
* A tree view at the left of the window, where you will see the list of buffers (at the moment, there are only five of these: news feed, my wall, my audios, populars and recommended). These buffers are divided in two categories, posts and music. You could expand each category for seeing the child buffers. There are some additional buffers, timelines and chats, wich will be filled with timelines for your friends or with chats, when you start or receive a chat session.
* A button for making a post to your wall.
* In audio buffers, Two buttons: Play and play all.
* A list where you will see the posts for the currently selected buffer.
* A status bar where the program will put some useful information about what it's doing at the moment.
* And a menu bar, which could be used for making a search for audio files in VK, or check for updates.
When socializer starts, it will try to load your news items, wall and audios. At the moment there are only a few supported actions for these items:
* Audio files: You can play the currently selected song, view the song's details (including lyrics, if available), add or remove from your library, and download it to a desired place in your hard drive. You can find audio files in your news feed or in your own audios buffers.
* News feed's post: In your news feed buffer, you can press return in any post and socializer will open a new dialogue which can be different, depending in the kind of post you are when the return key was pressed.
* At the moment you can't open your wall posts.
### Making a post
When you press the post button, a new dialogue will show up. This dialogue allows you to post something in your wall. In this dialogue you have to write a message. You can translate your message and fix your spelling mistakes. Also you can post an URL address, socializer will try to add it as an attachment, so you will not have to worry about this. When you're ready, just press the send button and it'll be done.
### Working with posts in news feed
You can press the return key in any post in your news feed for opening a new dialogue with some information. The information and dialogue will be different if you are viewing a friendship's notification (when someone has added some friends), an audio file, or a regular post.
If you open a regular post in your newsfeed, you will be able to see the comments in a list, indicate if you do like or dislike the post, or add a new comment.
For friend notifications, you can only view the new added friends in a list and there are some kind of posts that aren't handled. It should be improved.
### Working with songs
If you want to play or view audio's details, you'll have to navigate to the tree view, and, using the down arrow, look for "my audios", "populars" or "Recommendations". You will see two more buttons, play and play all. The play button will play the currently selected audio, and the play all button will play audios in the current buffer, starting with the current selected item. You can go to the song's list, look for a desired song and press the play button, or Ctrl+return, which is a keyboard shorcut. Take in to account that there are some keyboard shorcuts that only work in the list of items.
You can play audio from any buffer, just press ctrl+return for making the audio playback possible.
If someone has added multiple audios at once to his library, you will see something like this in your newsfeed: "(friend) has added 4 audios: audio 1, audio2, audio3 and audio4". You can press return in the post for opening the audio's details dialogue, where you will be able to see a list with these audios. By default the first detected song is selected, which means that you could read its details by pressing tab, download or add it to your library. If you change the audio in the list, the information will be updated and you will see details and actions will take effect in the new selected audio.
When an audio file is playing, you can press f5 and f6 for decreasing and increasing volume, respectively, or control+shift+return for play/pause.
If you want to see some details for the selected audio file, you can do it by pressing the return key. You will be able to read some useful information (title, artist, duration and the lyric, if available). Also you will be able to download the song to your hard drive, you have to press the download button in the details' dialogue.
When the download starts, you can close the details dialogue and check the status bar in the main window for seeing the current progress.
## menu Bar
You can go to the menu bar by pressing ALT. Right now, there are only two menus, buffer and help:
### Buffer menu
* New buffer: This submenu allows you to create a new buffer, at the moment, you can create only a kind of buffer, an audio search. The audio search will be located in the music category and will have the last 299 results of your query. It isn't possible to delete the buffers until you restart the client.
* Update current buffer: perform an update operation in the selected buffer, which will retrieve the new items.
* Remove buffer: Tries to remove the current buffer. It only works with audio searches, because the default buffers shouldn't be removed.
The help menu is self explanatory.
## Contributing ## Contributing

View File

@@ -1,6 +1,27 @@
% Changelog % Changelog
## Changes for the current build () ## Changes for the current build (08/07/2016)
* Removed platform from "last seen" column in the friends list as it could cause some problems and it was being not so exact.
* Now deleted audios are not parsed and displayed as "audio removed from library". They are silently ignored.
* It's possible to open a friends timeline for others.
* Fixed some strange bugs in the built version.
* Deactivated accounts will not cause problems in friends lists. They will be displayed as deactivated, wich means that it'll be impossible to interact with those accounts.
* When opened, the client will set online for the user account, it'll inform VK that this user is currently online. This parameter will be updated every 15 minutes, as stated in the API documentation.
* When opened, socializer will try to create chat buffers for all unread messages.
* Update some information on certain posts when an item is selected. For example, update the date of a post.
* Read messages will be marked as read in the social network, so it'll cause that your friends could see that you have read the message and socializer will not load chat buffers with read messages at startup.
* Included a brief manual in the help menu. Currently available only in English.
* Included a context menu in list items. Currently there are functions not available. Menu for chat buffers is not implemented yet.
* Implemented audio album load (in the music buffer), creation (in the application menu) and deletion (in the application menu, too).
* audios can be moved to albums by pressing the menu key or doing a right click in the item, and selecting "move to album". Audios will be added to the album in the next update (there is a programmed update every 3 minutes), or you can update the buffer manually (from the buffer menu in the menu bar). This option will be available in audio buffers (searches, popular and recommended audio buffers, and audio timelines).
* Albums will be empty at startup. In order to get the album's audios, you'll have to navigate to the album and press the button "load". It'll load the needed information for displaying and playing the added songs
* If the config is invalid (for example you changed email or phone in the VK site and didn't changed that in Socializer, or just entered invalid credentials), the program will display an error with instructions for fixing the problem.
* Now is possible to press enter in the password or email/phone field and it'll do the action of the OK button.
* If you have set russian as the main language in the VK site, you'll see names in genitive and instrumental cases in certain phrases.
* Updated russian and spanish translations.
## Changes on build 2016.05.25
* Added grouped controls in the audio searches dialogue. It will be more accessible so screen readers could detect and read the label for radio buttons. * Added grouped controls in the audio searches dialogue. It will be more accessible so screen readers could detect and read the label for radio buttons.
* Added documents to the list of supported attachments in the post viewer. The action for this kind of attachments is to open the default web browser, pointing to the URL address of that file. * Added documents to the list of supported attachments in the post viewer. The action for this kind of attachments is to open the default web browser, pointing to the URL address of that file.

0
doc/__init__.py Normal file
View File

12
doc/application.py Normal file
View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
name = "Socializer"
version = "0.13"
author = u"Manuel Cortéz"
authorEmail = "manuel@manuelcortez.net"
copyright = u"Copyright (C) 2016, Manuel cortéz."
description = unicode(name+" Is an accessible VK client for Windows.")
url = "https://github.com/manuelcortez/socializer"
update_url = "https://raw.githubusercontent.com/manuelcortez/socializer/master/update-files/socializer.json"
# The short name will be used for detecting translation files. See languageHandler for more details.
short_name = "socializer"
translators = [u"Valeria K (Russian)", u"Manuel Cortez (Spanish)"]

View File

@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
""" This script converts the hold documentation (saved in markdown files) in a python file with a list of strings to translate it using gettext."""
def prepare_documentation_in_file(fileSource, fileDest):
""" This takes documentation written in a markdown file and put all the contents in a python file, to create a internationalized documentation.
@fileSource str: A markdown(.md) file.
@fileDest str: A file where this will put the new strings"""
f1 = open(fileSource, "r")
f2 = open(fileDest, "w")
lns = f1.readlines()
f2.write("# -*- coding: utf-8 -*-\n")
f2.write("documentation = [\n")
for i in lns:
if "\n" == i:
newvar = "\"\","
elif "\n" == i[-1]:
newvar = "_(u\"\"\"%s\"\"\"),\n" % (i[:-1])
else:
newvar = "_(u\"\"\"%s\"\"\"),\n" % (i)
# print i[-1:]
f2.write(newvar)
f1.close()
f2.write("]")
f2.close()
prepare_documentation_in_file("manual.md", "strings.py")

42
doc/generator.py Normal file
View File

@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
import markdown
import os
from codecs import open as _open
import languageHandler
languageHandler.setLanguage("en")
import documentation_importer
# the list of supported language codes of TW Blue
languages = ["en", "es"]
def generate_document(language):
import strings
reload(languageHandler)
languageHandler.setLanguage(language)
reload(strings)
markdown_file = markdown.markdown("\n".join(strings.documentation[1:]), extensions=["markdown.extensions.toc"])
first_html_block = """<!doctype html>
<html lang="%s">
<head>
<title>%s</title>
<meta charset="utf-8">
</head>
<body>
<header><h1>%s</h1></header>
""" % (language, strings.documentation[0], strings.documentation[0])
first_html_block = first_html_block+ markdown_file
first_html_block = first_html_block + "\n</body>\n</html>"
if not os.path.exists(language):
os.mkdir(language)
mdfile = _open("%s/manual.html" % language, "w", encoding="utf-8")
mdfile.write(first_html_block)
mdfile.close()
def create_documentation():
print("Creating documentation in the supported languages...\n")
for i in languages:
print("Creating documentation for: %s" % (i,))
generate_document(i)
print("Done")
create_documentation()

176
doc/languageHandler.py Normal file
View File

@@ -0,0 +1,176 @@
import __builtin__
import os
import sys
import ctypes
import locale
import gettext
#import paths
import platform
# A fix for the mac locales
if platform.system() != 'Windows':
if locale.getlocale()[0] is None:
locale.setlocale(locale.LC_ALL, 'en_US')
#a few Windows locale constants
LOCALE_SLANGUAGE=0x2
LOCALE_SLANGDISPLAYNAME=0x6f
curLang="en"
def localeNameToWindowsLCID(localeName):
"""Retreave the Windows locale identifier (LCID) for the given locale name
@param localeName: a string of 2letterLanguage_2letterCountry or or just 2letterLanguage
@type localeName: string
@returns: a Windows LCID
@rtype: integer
"""
#Windows Vista is able to convert locale names to LCIDs
func_LocaleNameToLCID=getattr(ctypes.windll.kernel32,'LocaleNameToLCID',None)
if func_LocaleNameToLCID is not None:
localeName=localeName.replace('_','-')
LCID=func_LocaleNameToLCID(unicode(localeName),0)
else: #Windows doesn't have this functionality, manually search Python's windows_locale dictionary for the LCID
localeName=locale.normalize(localeName)
if '.' in localeName:
localeName=localeName.split('.')[0]
LCList=[x[0] for x in locale.windows_locale.iteritems() if x[1]==localeName]
if len(LCList)>0:
LCID=LCList[0]
else:
LCID=0
return LCID
def getLanguageDescription(language):
"""Finds out the description (localized full name) of a given local name"""
desc=None
if platform.system() == "Windows":
LCID=localeNameToWindowsLCID(language)
if LCID!=0:
buf=ctypes.create_unicode_buffer(1024)
if '_' not in language:
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGDISPLAYNAME,buf,1024)
else:
res=0
if res==0:
res=ctypes.windll.kernel32.GetLocaleInfoW(LCID,LOCALE_SLANGUAGE,buf,1024)
desc=buf.value
elif platform.system() == "Linux" or not desc:
desc={
"am":pgettext("languageName","Amharic"),
"an":pgettext("languageName","Aragonese"),
"es":pgettext("languageName","Spanish"),
"pt":pgettext("languageName","Portuguese"),
"ru":pgettext("languageName","Russian"),
"it":pgettext("languageName","italian"),
"tr":pgettext("languageName","Turkey"),
"gl":pgettext("languageName","Galician"),
"ca":pgettext("languageName","Catala"),
"eu":pgettext("languageName","Vasque"),
"pl":pgettext("languageName","polish"),
"ar":pgettext("languageName","Arabic"),
"ne":pgettext("languageName","Nepali"),
"sr":pgettext("languageName","Serbian (Latin)"),
}.get(language,None)
return desc
def getAvailableLanguages():
"""generates a list of locale names, plus their full localized language and country names.
@rtype: list of tuples
"""
#Make a list of all the locales found in NVDA's locale dir
l=[x for x in os.listdir("locales") if not x.startswith('.')]
l=[x for x in l if os.path.isfile('locales/%s/LC_MESSAGES/socializer-doc.mo' % x)]
#Make sure that en (english) is in the list as it may not have any locale files, but is default
if 'en' not in l:
l.append('en')
l.sort()
#For each locale, ask Windows for its human readable display name
d=[]
for i in l:
desc=getLanguageDescription(i)
label="%s, %s"%(desc,i) if desc else i
d.append(label)
#include a 'user default, windows' language, which just represents the default language for this user account
l.append("system")
# Translators: the label for the Windows default NVDA interface language.
d.append(_("User default"))
#return a zipped up version of both the lists (a list with tuples of locale,label)
return zip(l,d)
def makePgettext(translations):
"""Obtaina pgettext function for use with a gettext translations instance.
pgettext is used to support message contexts,
but Python 2.7's gettext module doesn't support this,
so NVDA must provide its own implementation.
"""
if isinstance(translations, gettext.GNUTranslations):
def pgettext(context, message):
message = unicode(message)
try:
# Look up the message with its context.
return translations._catalog[u"%s\x04%s" % (context, message)]
except KeyError:
return message
else:
def pgettext(context, message):
return unicode(message)
return pgettext
def setLanguage(lang):
system = platform.system()
global curLang
try:
if lang=="system":
if system == "Windows":
windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage()
localeName=locale.windows_locale[windowsLCID]
else:
localeName=locale.getlocale()[0]
trans=gettext.translation('socializer-doc', localedir="locales", languages=[localeName])
curLang=localeName
else:
trans=gettext.translation("socializer-doc", localedir="locales", languages=[lang])
curLang=lang
localeChanged=False
#Try setting Python's locale to lang
try:
locale.setlocale(locale.LC_ALL, lang)
localeChanged=True
except:
pass
if not localeChanged and '_' in lang:
#Python couldn'tsupport the language_country locale, just try language.
try:
locale.setlocale(locale.LC_ALL, lang.split('_')[0])
except:
pass
#Set the windows locale for this thread (NVDA core) to this locale.
if system == "Windows":
LCID=localeNameToWindowsLCID(lang)
ctypes.windll.kernel32.SetThreadLocale(LCID)
except IOError:
trans=gettext.translation("socializer-doc",fallback=True)
curLang="en"
trans.install(unicode=True)
# Install our pgettext function.
__builtin__.__dict__["pgettext"] = makePgettext(trans)
def getLanguage():
return curLang
def normalizeLanguage(lang):
"""
Normalizes a language-dialect string in to a standard form we can deal with.
Converts any dash to underline, and makes sure that language is lowercase and dialect is upercase.
"""
lang=lang.replace('-','_')
ld=lang.split('_')
ld[0]=ld[0].lower()
#Filter out meta languages such as x-western
if ld[0]=='x':
return None
if len(ld)>=2:
ld[1]=ld[1].upper()
return "_".join(ld)

Binary file not shown.

View File

@@ -0,0 +1,535 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Socializer\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-06-29 13:33-0500\n"
"PO-Revision-Date: 2016-06-29 16:25-0600\n"
"Last-Translator: \n"
"Language-Team: Manuel Cortez <manuel@manuelcortez.net>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.6.11\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. Translators: the label for the Windows default NVDA interface language.
msgid "User default"
msgstr ""
msgid "socializer's manual "
msgstr "Manual de Socializer"
msgid "## Introduction"
msgstr "## Introducción"
msgid ""
"Socializer is an application to use [VK.com](https://vk.com) in an easy and "
"accessible way with minimal CPU resource usage. Socializer will allow you to "
"interact with the VK social network by giving you access to the most "
"relevant features such as:"
msgstr ""
"Socializer es una aplicación para usar [vk.com](http://vk.com) de forma "
"fácil y accesible, con un consumo de CPU mínimo. Socializer te permitirá "
"interactuar con la red social VK, brindándote acceso a las características "
"más relevantes, tales como:"
msgid "* Basic post creation in your wall (including photos)."
msgstr ""
"* Creación básica de publicaciones en tu muro (incluyendo subida de fotos)"
msgid "* Audio addition, removal, download and search."
msgstr "* Añadir, descargar y buscar archivos de audio."
msgid "* audio albums management (create, delete and add audios)."
msgstr ""
"* Administración de albums de audio (crear, eliminar y añadir audios dentro "
"de albums)."
msgid "* Post comments."
msgstr "* Publicar comentarios."
msgid "* like, unlike and repost other's posts."
msgstr ""
"* Indicar que te gusta, que ya no te gusta o compartir publicaciones de "
"otros usuarios."
msgid ""
"* Open other's timelines so you could track someone's friends, posts or "
"audio files."
msgstr ""
"* Abrir líneas temporales de otros usuarios para poder ver sus "
"publicaciones, audios o amigos."
msgid "* Basic chat features."
msgstr "* Características básicas de chat."
msgid ""
"Note: When new features are added to socializer they will be added to this "
"section."
msgstr ""
"Nota: Cuando sean añadidas, las nuevas características se incluirán aquí."
msgid "## Running"
msgstr "## Abriendo socializer"
msgid ""
"If you are using a built version, unzip the file in a new directory with no "
"special characters, and open the socializer.exe file. If you haven't "
"configured your VK account, you will see a dialogue, just press yes and a "
"new dialogue will prompt for an user email or phone number and the password "
"for your account. Take into account that the provided information will be "
"saved in a config file as plain text. This application will need your "
"information for renegotiating the access token when it expires."
msgstr ""
"Si estás usando una versión compilada (distribuible), descomprime el archivo "
"ZIP en un nuevo directorio que no contenga caracteres especiales, y abre el "
"archivo socializer.exe. Si no has configurado tu cuenta de VK, verás un "
"diálogo donde se te preguntará si deseas configurar una. Si presionas en sí, "
"podrás introducir tus datos. Toma en cuenta que la información proporcionada "
"ha de guardarse en un archivo de configuración, como texto plano. La "
"aplicación necesitará tu información para renovar el código de acceso cuando "
"expire."
msgid ""
"Note: Every time you grant access to socializer, probably You will receive "
"an email from VK by telling you that someone has accessed to your account. "
"It means that a new token has been negotiated between VK and socializer by "
"using an authomatic process, you should ignore those advices, unless you "
"receive an email when you are not logged in VK with socializer or other "
"application. You can see your authorised applications in the configuration "
"section in the VK website. New tokens are renegotiated every 24 hours."
msgstr ""
"Nota: Cada que se brinde acceso a socializer, probablemente recibirás un "
"correo electrónico de VK diciéndote que puede que alguien haya entrado a tu "
"cuenta. Significa que un nuevo código de acceso ha sido generado entre VK y "
"Socializer mediante un proceso automático. Deberías ignorar estos avisos, a "
"no ser que hayas recibido un correo cuando no estés usando Socializer o "
"alguna otra aplicación. Puedes ver tus aplicaciones autorizadas en la página "
"de tu perfil en el sitio web de VK. Un nuevo código de acceso debe ser "
"generado cada 24 horas."
msgid "## Main interface"
msgstr "## Interfaz"
msgid ""
"If you have used [TWBlue](https://github.com/manuelcortez/twblue) before, "
"the socializer's interface is quite similar. Once you have authorised your "
"account, you will see a window with the following elements:"
msgstr ""
"Si alguna vez has usado [TWBlue](https//github.com/manuelcortez/twblue) "
"anteriormente, te darás cuenta que la interfaz gráfica de socializer es muy "
"parecida. Una vez que hayas autorizado tu cuenta, Podrás ver una ventana con "
"los siguientes elementos:"
msgid ""
"* A tree view at the left of the window, where you will see the list of "
"buffers. These buffers are divided in three categories, posts, music and "
"people. You could expand each category for seeing the child buffers. There "
"are some additional buffers, timelines and chats, wich will be filled with "
"timelines for your friends or with chats, when you start or receive a chat "
"session."
msgstr ""
"* Una vista de árbol en la parte izquierda de laventana, donde podrás ver la "
"lista de buffers. Los buffers están divididos en tres categorías, "
"publicaciones, música y gente. Puedes expandir cada categoría para ver los "
"elementos hijos. Hay además buffers adicionales, líneas temporales y chats, "
"que serán usados para guardar líneas temporales para tus amigos, o chats "
"cuando recibas o envíes un mensaje."
msgid "* A button for making a post to your wall."
msgstr "* Un botón para publicar en tu muro."
msgid "* In audio buffers, Two buttons: Play and play all."
msgstr ""
"* En buffers de audio, un par de botones: Reproducir y reproducir todo."
msgid ""
"* In audio album buffers, a button for loading music. By default, albums are "
"empty, you have to press the load button for getting the album's items."
msgstr ""
"* En buffers para albums de audio, un botón llamado cargar álbum. De manera "
"predeterminada, los álbumes se encuentran vacíos, debes pulsar el botón "
"cargar álbum para descargar la información necesaria que permitirá mostrar "
"la música dentro del buffer del álbum."
msgid ""
"* A list where you will see the posts for the currently selected buffer."
msgstr "* Una lista donde podrás ver los elementos del buffer seleccionado."
msgid ""
"* In people buffers, like the friends buffer, a button for sending a message "
"to your friends. Pressing that button will cause a chat buffer to be created."
msgstr ""
"* En buffers de amigos, un botón que permite enviar un mensaje a la persona "
"seleccionada. Si es activado, el botón creará un buffer de chat "
"automáticamente."
msgid ""
"* A status bar where the program will put some useful information about what "
"it's doing at the moment."
msgstr ""
"* Una barra de estado, donde el programa escribirá información importante "
"sobre lo que se encuentra haciendo en cada momento."
msgid "* And a menu bar."
msgstr "* Y una barra de menú."
msgid ""
"When socializer starts, it will try to load your news items, wall, audios "
"(your audios, recommended and populars) and friends. At the moment there are "
"only a few supported actions for these items:"
msgstr ""
"Cuando socializer inicia, intentará cargar los elementos en el buffer "
"principal, publicaciones en tu muro, canciones en tus buffers de audio (mis "
"audios, populares y recomendaciones), así como tus amigos. Por el momento "
"solo se pueden hacer pocas acciones para cada uno de estos tipos de elemento."
msgid ""
"* Audio files: You can play the currently selected song, view the song's "
"details (including lyrics, if available), add or remove from your library, "
"and download it to a desired place in your hard drive. You can find audio "
"files in your news feed or in your own audios buffers. You can find audios "
"as post's attachments. You can create an audios timeline for displaying "
"other's audios."
msgstr ""
"* Archivos de audio: Puedes reproducir el audio seleccionado, ver los "
"detalles de la canción (incluyendo letras, si las tiene), añadirlo y "
"eliminarlo de tu biblioteca, y descargar la canción a tu disco duro. Puedes "
"encontrar archivos de audio en tus propios buffers de audio, en el buffer "
"principal y pueden estar incluidos como adjuntos en publicaciones. Puedes "
"abrir una línea temporal de audios para ver los audios de otros usuarios de "
"VK."
msgid ""
"* News feed's post: In your news feed buffer, you can press return in any "
"post and socializer will open a new dialogue which can be different, "
"depending in the kind of post you are when the return key was pressed. For "
"example it will open the post if you are focusing a \"normal\" post, a list "
"of people if you are in a post wich indicates that someone has added "
"friends, an audio displayer if you are in a post wich indicates that someone "
"has added an audio, etc."
msgstr ""
"* Publicaciones en el buffer principal: En el buffer principal, puedes "
"pulsar la tecla intro y socializer abrirá un diálogo que puede ser "
"diferente, dependiendo del tipo de publicación que estaba enfocada cuando se "
"presionó la tecla. Por ejemplo, abrirá la publicación si estabas en una "
"publicación \"normal\", una lista de personas si estabas en una publicación "
"que indicaba que alguien había añadido amigos, el visualizador de detalles "
"de audios si estabas en una publicación que indicaba que alguien había "
"añadido audios, etc."
msgid ""
"* Wall posts: It will show the post in a dialogue so you could interact with "
"its attachments, view and post comments, or like/unlike/share the post."
msgstr ""
"* publicaciones en el muro: Mostrará la publicación en un nuevo diálogo, que "
"te permitirá interactuar con el post, ver los adjuntos, ver y publicar "
"comentarios, así como indicar si te gusta, ya no te gusta y compartir la "
"publicación."
msgid ""
"* You can send a message to someone by pressing the send message button in "
"the buffer where you are, if available. Deactivated accounts cannot receive "
"messages."
msgstr ""
"* Puedes enviar un mensaje a alguien pulsando el botón Enviar mensaje, si "
"está disponible. Los usuarios con cuentas desactivadas no pueden recibir "
"mensajes."
msgid "### Making a post"
msgstr "### Haciendo una publicación"
msgid ""
"When you press the post button, a new dialogue will show up. This dialogue "
"allows you to post something in your wall. In this dialogue you have to "
"write a message. You can translate your message and fix your spelling "
"mistakes. Also you can post an URL address, socializer will try to add it as "
"an attachment, so you will not have to worry about this. When you're ready, "
"just press the send button and it'll be done."
msgstr ""
"Cuando pulses el botón para publicar, se mostrará un diálogo. Este diálogo "
"te permitirá publicar algo en tu muro. En este diálogo tienes que escribir "
"un mensaje. Puedes traducir el mensaje y corregir tus errores ortográficos. "
"También puedes publicar una dirección URL, y socializer intentará enviarla "
"como un adjunto a tu publicación, por lo que no tienes que preocuparte. "
"Cuando estés listo, solo presiona el botón enviar, y estará listo."
msgid ""
"If you want to add some photos, you can press the attach button, then press "
"the kind of attachment you want to add. After this, select the file you want "
"to add and you will see it in the list, once processed. When you are done "
"with attachments, press the OK button, and continue with your post. When you "
"are ready, press the send button. Your post could take some time to be "
"published, depending in the amount of files you have added, but it should be "
"displayed in your wall and newsfeed as soon as it is posted."
msgstr ""
"Si quieres añadir algunas fotos, presiona el botón adjuntar, seguidamente "
"encuentra el botón del elemento que quieres añadir. Después, selecciona el "
"archivo a adjuntar y lo podrás ver en la lista de archivos a cargar una vez "
"sea procesado por el programa. Cuando hayas terminado con los adjuntos, "
"presiona el botón aceptar, y continúa con tu publicación. Cuando esté todo "
"listo, pulsa el botón enviar. Tu publicación podría tomar un tiempo en ser "
"enviada, dependiendo de la cantidad y el tamaño de los adjuntos que "
"añadiste, pero debería aparecer publicada en tu muro y en el buffer "
"principal tan rápidamente como sea publicada."
msgid "### Working with posts in news feed"
msgstr "### Trabajando con publicaciones en el buffer principal."
msgid ""
"You can press the return key in any post in your news feed for opening a new "
"dialogue with some information. The information and dialogue will be "
"different if you are viewing a friendship's notification (when someone has "
"added some friends), an audio file, or a regular post."
msgstr ""
"Puedes pulsar la tecla intro en cualquier publicación de tu buffer principal "
"para abrir un nuevo diálogo con información. La información puede variar si "
"estás viendo una notificación de nuevos amigos (cuando alguien añade "
"amigos), un archivo de audio, o una publicación regular."
msgid ""
"If you open a regular post in your newsfeed, you will be able to see the "
"comments in a list, indicate if you do like or dislike the post, repost or "
"add a new comment. If the post has some attachments, you'll find a list "
"populated with them, you can press return in an attachment to execute its "
"default action, wich will be different depending on the kind of attachment "
"that you are viewing."
msgstr ""
"Si abres una publicación regular en tu buffer principal, serás capaz de leer "
"los comentarios en una lista, indicar si te gusta o ya no te gusta la "
"publicación, compartirla o añadir un nuevo comentario. Si la publicación "
"contiene adjuntos, encontrarás una lista con ellos. Puedes pulsar intro "
"sobre uno de ellos para abrir la acción predeterminada. La acción "
"predeterminada para cada archivo dependerá del tipo de archivo en el que te "
"enfoques."
msgid ""
"For friend notifications, you can only view the new added friends in a list "
"and there are some kind of posts that aren't handled. It should be improved."
msgstr ""
"Para las notificaciones de nuevos amigos, solo puedes ver las personas que "
"han sido añadidas. También hay algunas publicaciones que no se muestran por "
"defecto."
msgid ""
"Additionally, you can press the menu Key or the right click for displaying "
"a menu with some quick actions available for the post you are focusing. "
"These actions are different for every post type."
msgstr ""
"Además, puedes pulsar la tecla de aplicaciones o el botón derecho del ratón "
"para mostrar un menú de acciones rápidas que están disponibles para el "
"elemento seleccionado. Las acciones son diferentes para cada tipo de "
"publicación."
msgid "### Working with songs"
msgstr "### Trabajando con audios"
msgid "Note: the following applies to audio timelines too."
msgstr "Nota: Lo siguiente también es aplicable a líneas temporales de audio."
msgid ""
"If you want to play or view audio's details, you'll have to navigate to the "
"tree view, and, using the down arrow, look for \"my audios\", \"populars\" "
"or \"Recommendations\". You will see two more buttons, play and play all. "
"The play button will play the currently selected audio, and the play all "
"button will play audios in the current buffer, starting with the current "
"selected item. You can go to the song's list, look for a desired song and "
"press the play button, or Ctrl+return, which is a keyboard shorcut. Take in "
"to account that there are some keyboard shorcuts that only work in the list "
"of items."
msgstr ""
"Si quieres reproducir o ver los detalles de un archivo de audio, debes "
"navegar hasta la vista de árbol y, utilizando las flechas de cursor, ubicar "
"algún buffer de audio (mis audios, populares o recomendaciones). Verás dos "
"botones extras, reproducir y reproducir todo. El botón reproducir "
"reproducirá el audio seleccionado, y el botón reproducir todo comenzará a "
"reproducir, a partir del audio seleccionado y hasta el final, todos los "
"audios del buffer. Puedes ir a la lista de canciones, buscar una canción que "
"te guste y pulsar el botón reproducir, o pulsar Control intro, que es un "
"atajo de teclado. Ten en cuenta que algunos atajos de teclado solo funcionan "
"cuando estás en la lista de elementos."
msgid ""
"You can play audio from any buffer, just press ctrl+return for making the "
"audio playback possible."
msgstr ""
"Puedes reproducir audios desde cualquier buffer, solo presiona Control intro "
"para hacer posible la reproducción."
msgid ""
"If someone has added multiple audios at once to his library, you will see "
"something like this in your newsfeed: \"(friend) has added 4 audios: audio "
"1, audio2, audio3 and audio4\". You can press return in the post for "
"opening the audio's details dialogue, where you will be able to see a list "
"with these audios. By default the first detected song is selected, which "
"means that you could read its details by pressing tab, download or add it to "
"your library. If you change the audio in the list, the information will be "
"updated and you will see details and actions will take effect in the new "
"selected audio."
msgstr ""
"Si alguien ha añadido más de un audio a su biblioteca, podrás ver algo como "
"lo siguiente: \"(alguien) ha añadido 4 audios: audio1, audio2, audio3 y "
"audio4\". Puedes pulsar intro en la publicación para abrir el diálogo del "
"visualizador de detalles de audios, donde podrás verlos todos en una lista. "
"De forma predeterminada, el primer audio detectado está seleccionado, lo que "
"significa que puedes pulsar tab para ver sus detalles, descargarlo y "
"añadirlo a la biblioteca. Si cambias la canción en la lista, notarás que la "
"información se actualizará y ahora los detalles y acciones a mostrar tendrán "
"efecto en el nuevo audio seleccionado."
msgid ""
"When an audio file is playing, you can press f5 and f6 for decreasing and "
"increasing volume, respectively, or control+shift+return for play/pause."
msgstr ""
"Cuando un archivo de audio está siendo reproducido, puedes pulsar las teclas "
"f5 y f6 para bajar y subir volumen, respectivamente. También puedes pulsar "
"Control Shift Intro para pausar/reproducir la canción."
msgid ""
"If you want to see some details for the selected audio file, you can do it "
"by pressing the return key. You will be able to read some useful "
"information (title, artist, duration and the lyric, if available). Also you "
"will be able to download the song to your hard drive, you have to press the "
"download button in the details' dialogue."
msgstr ""
"Si quieres ver algunos detalles para el audio seleccionado, pulsa intro "
"sobre él. Podrás leer información importante sobre la canción (título, "
"artista, duración y la letra, si está disponible). También podrás descargar "
"la canción a tu disco duro, solo tienes que pulsar el botón descargar en el "
"diálogo de detalles de audio."
msgid ""
"When the download starts, you can close the details dialogue and check the "
"status bar in the main window for seeing the current progress."
msgstr ""
"Cuando la descarga inicie, puedes cerrar el visualizador de detalles de "
"audio y revisar la barra de estado para ver el progreso."
msgid ""
"Additionally, you can search for audios by using the menu bar, in the buffer "
"menu, select search, then audio. It will display a dialog where you have to "
"set your search preferences."
msgstr ""
"Además, puedes hacer una búsqueda de canciones usando la barra de menú, en "
"el menú buffer, buscar, luego audio. Mostrará un diálogo donde deberás "
"establecer tus preferencias de búsqueda."
msgid ""
"If you press the menu key, you will see a menu where you will be able to do "
"some actions, for example, add the audio to an album, or add/remove the song "
"from your library."
msgstr ""
"Si presionas la tecla de aplicaciones podrás ver un menú desde el que puedes "
"realizar algunas acciones, por ejemplo mover la canción a un álbum, o "
"agregarlo/eliminarlo de tu biblioteca."
msgid "## menu Bar"
msgstr "## barra de menú"
msgid ""
"You can go to the menu bar by pressing ALT. Right now, there are three "
"menus, application, buffer and help:"
msgstr ""
"Puedes ir a la barra de menú pulsando la tecla ALT. Actualmente existen tres "
"menús: aplicación, buffer y ayuda."
msgid "### Application menu"
msgstr "### Menú aplicación"
msgid ""
"* Create. Here you can create some things in VK. The only supported item at "
"this moment is the audio album."
msgstr ""
"* Crear. Aquí puedes crear algunas cosas en VK. Actualmente solo se "
"encuentra soportada la creación de álbumes de audio."
msgid ""
"* Delete: Removes items from the VK servers. The only supported item here is "
"the audio album."
msgstr ""
"* eliminar. Elimina elementos desde el servidor de VK. Actualmente solo se "
"encuentra soportado el borrado de álbumes de audio."
msgid ""
"* you can set your preferences by opening the preferences dialog located in "
"this menu."
msgstr ""
"* Puedes establecer tus preferencias desde el diálogo de preferencias, "
"ubicado en este menú."
msgid "### Buffer menu"
msgstr "### Menú buffer"
msgid ""
"* new timeline: This option allows you to create a new timeline. This kind "
"of buffers is capable of download all posts in an user's profile."
msgstr ""
"* Nueva línea temporal: Esta opción permite crear una línea temporal para "
"otro usuario de VK. Las líneas temporales pueden descargar publicaciones de "
"otros usuarios."
msgid ""
"* search: This submenu allows you to create a new buffer, at the moment, "
"you can create only a kind of buffer, an audio search. The audio search will "
"be located in the music category and will have the last 299 results of your "
"query."
msgstr ""
"* Buscar: permite hacer una búsqueda en VK. Por el momento solo se pueden "
"buscar archivos de audio. Las búsquedas de audio se añadirán en el buffer de "
"música y contendrán los últimos 299 resultados."
msgid ""
"* Update current buffer: perform an update operation in the selected buffer, "
"which will retrieve the new items."
msgstr ""
"* Actualizar buffer: Realiza una operación de actualización en el buffer "
"actual, lo que recuperará los nuevos elementos."
msgid ""
"* Load previous items: Get the previous items for the currently focused "
"buffer."
msgstr ""
"* Cargar elementos anteriores: Carga los elementos anteriormente publicados "
"en el buffer actual."
msgid ""
"* Remove buffer: Tries to remove the current buffer. Default buffers can't "
"be removed."
msgstr ""
"* Eliminar buffer: Intenta remover el buffer actual. Los buffers "
"predeterminados no pueden eliminarse."
msgid "The help menu is self explanatory."
msgstr "El menú ayuda se explica por sí solo."
msgid "## Contributing"
msgstr "## Contribuir"
msgid ""
"If you notice some errors in this document, or features that are not "
"documented yet, you can suggest those changes by contacting me (more "
"information can be find in the following section)."
msgstr ""
"Si notas algún error en este documento, alguna sección no cubierta o "
"simplemente quieres sugerir algo, puedes hacerlo mediante las formas de "
"contacto (lee la siguiente sección)."
msgid "## contact"
msgstr "## Contacto"
msgid ""
"If you have questions, don't esitate to contact me in [Twitter,](https://"
"twitter.com/manuelcortez00) or sending me an email to "
"manuel(at)manuelcortez(dot)net. Just replace the words in parentheses with "
"the original signs."
msgstr ""
"Si tienes preguntas, no dudes en contactarme mediante [Twitter,](https://"
"twitter.com/manuelcortez00) o envíame un correo electrónico a "
"manuel(arroba)manuelcortez(punto)net. Solo asegúrate de remplazar las "
"palabras entre paréntesis por el símbolo original."

105
doc/manual.md Normal file
View File

@@ -0,0 +1,105 @@
socializer's manual
## Introduction
Socializer is an application to use [VK.com](https://vk.com) in an easy and accessible way with minimal CPU resource usage. Socializer will allow you to interact with the VK social network by giving you access to the most relevant features such as:
* Basic post creation in your wall (including photos).
* Audio addition, removal, download and search.
* audio albums management (create, delete and add audios).
* Post comments.
* like, unlike and repost other's posts.
* Open other's timelines so you could track someone's friends, posts or audio files.
* Basic chat features.
Note: When new features are added to socializer they will be added to this section.
## Running
If you are using a built version, unzip the file in a new directory with no special characters, and open the socializer.exe file. If you haven't configured your VK account, you will see a dialogue, just press yes and a new dialogue will prompt for an user email or phone number and the password for your account. Take into account that the provided information will be saved in a config file as plain text. This application will need your information for renegotiating the access token when it expires.
Note: Every time you grant access to socializer, probably You will receive an email from VK by telling you that someone has accessed to your account. It means that a new token has been negotiated between VK and socializer by using an authomatic process, you should ignore those advices, unless you receive an email when you are not logged in VK with socializer or other application. You can see your authorised applications in the configuration section in the VK website. New tokens are renegotiated every 24 hours.
## Main interface
If you have used [TWBlue](https://github.com/manuelcortez/twblue) before, the socializer's interface is quite similar. Once you have authorised your account, you will see a window with the following elements:
* A tree view at the left of the window, where you will see the list of buffers. These buffers are divided in three categories, posts, music and people. You could expand each category for seeing the child buffers. There are some additional buffers, timelines and chats, wich will be filled with timelines for your friends or with chats, when you start or receive a chat session.
* A button for making a post to your wall.
* In audio buffers, Two buttons: Play and play all.
* In audio album buffers, a button for loading music. By default, albums are empty, you have to press the load button for getting the album's items.
* A list where you will see the posts for the currently selected buffer.
* In people buffers, like the friends buffer, a button for sending a message to your friends. Pressing that button will cause a chat buffer to be created.
* A status bar where the program will put some useful information about what it's doing at the moment.
* And a menu bar.
When socializer starts, it will try to load your news items, wall, audios (your audios, recommended and populars) and friends. At the moment there are only a few supported actions for these items:
* Audio files: You can play the currently selected song, view the song's details (including lyrics, if available), add or remove from your library, and download it to a desired place in your hard drive. You can find audio files in your news feed or in your own audios buffers. You can find audios as post's attachments. You can create an audios timeline for displaying other's audios.
* News feed's post: In your news feed buffer, you can press return in any post and socializer will open a new dialogue which can be different, depending in the kind of post you are when the return key was pressed. For example it will open the post if you are focusing a "normal" post, a list of people if you are in a post wich indicates that someone has added friends, an audio displayer if you are in a post wich indicates that someone has added an audio, etc.
* Wall posts: It will show the post in a dialogue so you could interact with its attachments, view and post comments, or like/unlike/share the post.
* You can send a message to someone by pressing the send message button in the buffer where you are, if available. Deactivated accounts cannot receive messages.
### Making a post
When you press the post button, a new dialogue will show up. This dialogue allows you to post something in your wall. In this dialogue you have to write a message. You can translate your message and fix your spelling mistakes. Also you can post an URL address, socializer will try to add it as an attachment, so you will not have to worry about this. When you're ready, just press the send button and it'll be done.
If you want to add some photos, you can press the attach button, then press the kind of attachment you want to add. After this, select the file you want to add and you will see it in the list, once processed. When you are done with attachments, press the OK button, and continue with your post. When you are ready, press the send button. Your post could take some time to be published, depending in the amount of files you have added, but it should be displayed in your wall and newsfeed as soon as it is posted.
### Working with posts in news feed
You can press the return key in any post in your news feed for opening a new dialogue with some information. The information and dialogue will be different if you are viewing a friendship's notification (when someone has added some friends), an audio file, or a regular post.
If you open a regular post in your newsfeed, you will be able to see the comments in a list, indicate if you do like or dislike the post, repost or add a new comment. If the post has some attachments, you'll find a list populated with them, you can press return in an attachment to execute its default action, wich will be different depending on the kind of attachment that you are viewing.
For friend notifications, you can only view the new added friends in a list and there are some kind of posts that aren't handled. It should be improved.
Additionally, you can press the menu Key or the right click for displaying a menu with some quick actions available for the post you are focusing. These actions are different for every post type.
### Working with songs
Note: the following applies to audio timelines too.
If you want to play or view audio's details, you'll have to navigate to the tree view, and, using the down arrow, look for "my audios", "populars" or "Recommendations". You will see two more buttons, play and play all. The play button will play the currently selected audio, and the play all button will play audios in the current buffer, starting with the current selected item. You can go to the song's list, look for a desired song and press the play button, or Ctrl+return, which is a keyboard shorcut. Take in to account that there are some keyboard shorcuts that only work in the list of items.
You can play audio from any buffer, just press ctrl+return for making the audio playback possible.
If someone has added multiple audios at once to his library, you will see something like this in your newsfeed: "(friend) has added 4 audios: audio 1, audio2, audio3 and audio4". You can press return in the post for opening the audio's details dialogue, where you will be able to see a list with these audios. By default the first detected song is selected, which means that you could read its details by pressing tab, download or add it to your library. If you change the audio in the list, the information will be updated and you will see details and actions will take effect in the new selected audio.
When an audio file is playing, you can press f5 and f6 for decreasing and increasing volume, respectively, or control+shift+return for play/pause.
If you want to see some details for the selected audio file, you can do it by pressing the return key. You will be able to read some useful information (title, artist, duration and the lyric, if available). Also you will be able to download the song to your hard drive, you have to press the download button in the details' dialogue.
When the download starts, you can close the details dialogue and check the status bar in the main window for seeing the current progress.
Additionally, you can search for audios by using the menu bar, in the buffer menu, select search, then audio. It will display a dialog where you have to set your search preferences.
If you press the menu key, you will see a menu where you will be able to do some actions, for example, add the audio to an album, or add/remove the song from your library.
## menu Bar
You can go to the menu bar by pressing ALT. Right now, there are three menus, application, buffer and help:
### Application menu
* Create. Here you can create some things in VK. The only supported item at this moment is the audio album.
* Delete: Removes items from the VK servers. The only supported item here is the audio album.
* you can set your preferences by opening the preferences dialog located in this menu.
### Buffer menu
* new timeline: This option allows you to create a new timeline. This kind of buffers is capable of download all posts in an user's profile.
* search: This submenu allows you to create a new buffer, at the moment, you can create only a kind of buffer, an audio search. The audio search will be located in the music category and will have the last 299 results of your query.
* Update current buffer: perform an update operation in the selected buffer, which will retrieve the new items.
* Load previous items: Get the previous items for the currently focused buffer.
* Remove buffer: Tries to remove the current buffer. Default buffers can't be removed.
The help menu is self explanatory.
## Contributing
If you notice some errors in this document, or features that are not documented yet, you can suggest those changes by contacting me (more information can be find in the following section).
## contact
If you have questions, don't esitate to contact me in [Twitter,](https://twitter.com/manuelcortez00) or sending me an email to manuel(at)manuelcortez(dot)net. Just replace the words in parentheses with the original signs.

67
doc/strings.py Normal file
View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
documentation = [
_(u"""socializer's manual """),
"",_(u"""## Introduction"""),
"",_(u"""Socializer is an application to use [VK.com](https://vk.com) in an easy and accessible way with minimal CPU resource usage. Socializer will allow you to interact with the VK social network by giving you access to the most relevant features such as:"""),
"",_(u"""* Basic post creation in your wall (including photos)."""),
_(u"""* Audio addition, removal, download and search."""),
_(u"""* audio albums management (create, delete and add audios)."""),
_(u"""* Post comments."""),
_(u"""* like, unlike and repost other's posts."""),
_(u"""* Open other's timelines so you could track someone's friends, posts or audio files."""),
_(u"""* Basic chat features."""),
"",_(u"""Note: When new features are added to socializer they will be added to this section."""),
"",_(u"""## Running"""),
"",_(u"""If you are using a built version, unzip the file in a new directory with no special characters, and open the socializer.exe file. If you haven't configured your VK account, you will see a dialogue, just press yes and a new dialogue will prompt for an user email or phone number and the password for your account. Take into account that the provided information will be saved in a config file as plain text. This application will need your information for renegotiating the access token when it expires."""),
"",_(u"""Note: Every time you grant access to socializer, probably You will receive an email from VK by telling you that someone has accessed to your account. It means that a new token has been negotiated between VK and socializer by using an authomatic process, you should ignore those advices, unless you receive an email when you are not logged in VK with socializer or other application. You can see your authorised applications in the configuration section in the VK website. New tokens are renegotiated every 24 hours."""),
"",_(u"""## Main interface"""),
"",_(u"""If you have used [TWBlue](https://github.com/manuelcortez/twblue) before, the socializer's interface is quite similar. Once you have authorised your account, you will see a window with the following elements:"""),
"",_(u"""* A tree view at the left of the window, where you will see the list of buffers. These buffers are divided in three categories, posts, music and people. You could expand each category for seeing the child buffers. There are some additional buffers, timelines and chats, wich will be filled with timelines for your friends or with chats, when you start or receive a chat session."""),
_(u"""* A button for making a post to your wall."""),
_(u"""* In audio buffers, Two buttons: Play and play all."""),
_(u"""* In audio album buffers, a button for loading music. By default, albums are empty, you have to press the load button for getting the album's items."""),
_(u"""* A list where you will see the posts for the currently selected buffer."""),
_(u"""* In people buffers, like the friends buffer, a button for sending a message to your friends. Pressing that button will cause a chat buffer to be created."""),
_(u"""* A status bar where the program will put some useful information about what it's doing at the moment."""),
_(u"""* And a menu bar."""),
"",_(u"""When socializer starts, it will try to load your news items, wall, audios (your audios, recommended and populars) and friends. At the moment there are only a few supported actions for these items:"""),
"",_(u"""* Audio files: You can play the currently selected song, view the song's details (including lyrics, if available), add or remove from your library, and download it to a desired place in your hard drive. You can find audio files in your news feed or in your own audios buffers. You can find audios as post's attachments. You can create an audios timeline for displaying other's audios."""),
_(u"""* News feed's post: In your news feed buffer, you can press return in any post and socializer will open a new dialogue which can be different, depending in the kind of post you are when the return key was pressed. For example it will open the post if you are focusing a "normal" post, a list of people if you are in a post wich indicates that someone has added friends, an audio displayer if you are in a post wich indicates that someone has added an audio, etc."""),
_(u"""* Wall posts: It will show the post in a dialogue so you could interact with its attachments, view and post comments, or like/unlike/share the post."""),
_(u"""* You can send a message to someone by pressing the send message button in the buffer where you are, if available. Deactivated accounts cannot receive messages."""),
"",_(u"""### Making a post"""),
"",_(u"""When you press the post button, a new dialogue will show up. This dialogue allows you to post something in your wall. In this dialogue you have to write a message. You can translate your message and fix your spelling mistakes. Also you can post an URL address, socializer will try to add it as an attachment, so you will not have to worry about this. When you're ready, just press the send button and it'll be done."""),
"",_(u"""If you want to add some photos, you can press the attach button, then press the kind of attachment you want to add. After this, select the file you want to add and you will see it in the list, once processed. When you are done with attachments, press the OK button, and continue with your post. When you are ready, press the send button. Your post could take some time to be published, depending in the amount of files you have added, but it should be displayed in your wall and newsfeed as soon as it is posted."""),
"",_(u"""### Working with posts in news feed"""),
"",_(u"""You can press the return key in any post in your news feed for opening a new dialogue with some information. The information and dialogue will be different if you are viewing a friendship's notification (when someone has added some friends), an audio file, or a regular post."""),
"",_(u"""If you open a regular post in your newsfeed, you will be able to see the comments in a list, indicate if you do like or dislike the post, repost or add a new comment. If the post has some attachments, you'll find a list populated with them, you can press return in an attachment to execute its default action, wich will be different depending on the kind of attachment that you are viewing."""),
"",_(u"""For friend notifications, you can only view the new added friends in a list and there are some kind of posts that aren't handled. It should be improved."""),
"",_(u"""Additionally, you can press the menu Key or the right click for displaying a menu with some quick actions available for the post you are focusing. These actions are different for every post type."""),
"",_(u"""### Working with songs"""),
"",_(u"""Note: the following applies to audio timelines too."""),
"",_(u"""If you want to play or view audio's details, you'll have to navigate to the tree view, and, using the down arrow, look for "my audios", "populars" or "Recommendations". You will see two more buttons, play and play all. The play button will play the currently selected audio, and the play all button will play audios in the current buffer, starting with the current selected item. You can go to the song's list, look for a desired song and press the play button, or Ctrl+return, which is a keyboard shorcut. Take in to account that there are some keyboard shorcuts that only work in the list of items."""),
"",_(u"""You can play audio from any buffer, just press ctrl+return for making the audio playback possible."""),
"",_(u"""If someone has added multiple audios at once to his library, you will see something like this in your newsfeed: "(friend) has added 4 audios: audio 1, audio2, audio3 and audio4". You can press return in the post for opening the audio's details dialogue, where you will be able to see a list with these audios. By default the first detected song is selected, which means that you could read its details by pressing tab, download or add it to your library. If you change the audio in the list, the information will be updated and you will see details and actions will take effect in the new selected audio."""),
"",_(u"""When an audio file is playing, you can press f5 and f6 for decreasing and increasing volume, respectively, or control+shift+return for play/pause."""),
"",_(u"""If you want to see some details for the selected audio file, you can do it by pressing the return key. You will be able to read some useful information (title, artist, duration and the lyric, if available). Also you will be able to download the song to your hard drive, you have to press the download button in the details' dialogue."""),
"",_(u"""When the download starts, you can close the details dialogue and check the status bar in the main window for seeing the current progress."""),
"",_(u"""Additionally, you can search for audios by using the menu bar, in the buffer menu, select search, then audio. It will display a dialog where you have to set your search preferences."""),
"",_(u"""If you press the menu key, you will see a menu where you will be able to do some actions, for example, add the audio to an album, or add/remove the song from your library."""),
"",_(u"""## menu Bar"""),
"",_(u"""You can go to the menu bar by pressing ALT. Right now, there are three menus, application, buffer and help:"""),
"",_(u"""### Application menu"""),
"",_(u"""* Create. Here you can create some things in VK. The only supported item at this moment is the audio album."""),
_(u"""* Delete: Removes items from the VK servers. The only supported item here is the audio album."""),
_(u"""* you can set your preferences by opening the preferences dialog located in this menu."""),
"",_(u"""### Buffer menu"""),
"",_(u"""* new timeline: This option allows you to create a new timeline. This kind of buffers is capable of download all posts in an user's profile."""),
_(u"""* search: This submenu allows you to create a new buffer, at the moment, you can create only a kind of buffer, an audio search. The audio search will be located in the music category and will have the last 299 results of your query."""),
_(u"""* Update current buffer: perform an update operation in the selected buffer, which will retrieve the new items."""),
_(u"""* Load previous items: Get the previous items for the currently focused buffer."""),
_(u"""* Remove buffer: Tries to remove the current buffer. Default buffers can't be removed."""),
"",_(u"""The help menu is self explanatory."""),
"",_(u"""## Contributing"""),
"",_(u"""If you notice some errors in this document, or features that are not documented yet, you can suggest those changes by contacting me (more information can be find in the following section)."""),
"",_(u"""## contact"""),
"",_(u"""If you have questions, don't esitate to contact me in [Twitter,](https://twitter.com/manuelcortez00) or sending me an email to manuel(at)manuelcortez(dot)net. Just replace the words in parentheses with the original signs."""),
]

Binary file not shown.

View File

@@ -46,6 +46,11 @@ cd documentation
$pandocpath -s changelog.md -o changelog.html $pandocpath -s changelog.md -o changelog.html
rm changelog.md rm changelog.md
cd .. cd ..
cd ../doc
$pythonpath32/python.exe generator.py
mv -f en ../src/documentation/
mv -f es ../src/documentation/
cd ../src
$pythonpath32/python.exe "setup.py" "py2exe" "--quiet" $pythonpath32/python.exe "setup.py" "py2exe" "--quiet"
mv -f dist ../nightly/socializer mv -f dist ../nightly/socializer
rm -rf build rm -rf build

View File

@@ -1,3 +0,0 @@
@echo off
echo Generating application translation strings...
C:\python27x86\python.exe pygettext.py -v -d socializer ../src/*.pyw ../src/*.py ../src/*/*.py ../src/*/*.pyw ../src/*/*/*.py ../src/*/*/*.pyw ../src/*/*/*/*.py ../src/*/*/*/*.pyw ../src/*/*/*/*/*.py ../src/*/*/*/*/*.pyw

7
scripts/genpot_doc.bat Normal file
View File

@@ -0,0 +1,7 @@
@echo off
echo Generating file list..
dir ..\doc\*.py /L /B /S > %TEMP%\listfile.txt
echo Generating .POT file...
xgettext --language=Python -o socializer-documentation.pot --keyword=_ -d socializer -f %TEMP%\listfile.txt -c --no-location --no-wrap
del %TEMP%\listfile.txt
echo Done.

View File

@@ -0,0 +1,7 @@
@echo off
echo Generating file list..
dir ..\src\*.py /L /B /S > %TEMP%\listfile.txt
echo Generating .POT file...
xgettext --language=Python -o socializer.pot --keyword=_ -d socializer -f %TEMP%\listfile.txt -c --no-location --no-wrap
del %TEMP%\listfile.txt
echo Done.

View File

@@ -0,0 +1,213 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-06-29 13:33-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#. Translators: the label for the Windows default NVDA interface language.
msgid "User default"
msgstr ""
msgid "socializer's manual "
msgstr ""
msgid "## Introduction"
msgstr ""
msgid "Socializer is an application to use [VK.com](https://vk.com) in an easy and accessible way with minimal CPU resource usage. Socializer will allow you to interact with the VK social network by giving you access to the most relevant features such as:"
msgstr ""
msgid "* Basic post creation in your wall (including photos)."
msgstr ""
msgid "* Audio addition, removal, download and search."
msgstr ""
msgid "* audio albums management (create, delete and add audios)."
msgstr ""
msgid "* Post comments."
msgstr ""
msgid "* like, unlike and repost other's posts."
msgstr ""
msgid "* Open other's timelines so you could track someone's friends, posts or audio files."
msgstr ""
msgid "* Basic chat features."
msgstr ""
msgid "Note: When new features are added to socializer they will be added to this section."
msgstr ""
msgid "## Running"
msgstr ""
msgid "If you are using a built version, unzip the file in a new directory with no special characters, and open the socializer.exe file. If you haven't configured your VK account, you will see a dialogue, just press yes and a new dialogue will prompt for an user email or phone number and the password for your account. Take into account that the provided information will be saved in a config file as plain text. This application will need your information for renegotiating the access token when it expires."
msgstr ""
msgid "Note: Every time you grant access to socializer, probably You will receive an email from VK by telling you that someone has accessed to your account. It means that a new token has been negotiated between VK and socializer by using an authomatic process, you should ignore those advices, unless you receive an email when you are not logged in VK with socializer or other application. You can see your authorised applications in the configuration section in the VK website. New tokens are renegotiated every 24 hours."
msgstr ""
msgid "## Main interface"
msgstr ""
msgid "If you have used [TWBlue](https://github.com/manuelcortez/twblue) before, the socializer's interface is quite similar. Once you have authorised your account, you will see a window with the following elements:"
msgstr ""
msgid "* A tree view at the left of the window, where you will see the list of buffers. These buffers are divided in three categories, posts, music and people. You could expand each category for seeing the child buffers. There are some additional buffers, timelines and chats, wich will be filled with timelines for your friends or with chats, when you start or receive a chat session."
msgstr ""
msgid "* A button for making a post to your wall."
msgstr ""
msgid "* In audio buffers, Two buttons: Play and play all."
msgstr ""
msgid "* In audio album buffers, a button for loading music. By default, albums are empty, you have to press the load button for getting the album's items."
msgstr ""
msgid "* A list where you will see the posts for the currently selected buffer."
msgstr ""
msgid "* In people buffers, like the friends buffer, a button for sending a message to your friends. Pressing that button will cause a chat buffer to be created."
msgstr ""
msgid "* A status bar where the program will put some useful information about what it's doing at the moment."
msgstr ""
msgid "* And a menu bar."
msgstr ""
msgid "When socializer starts, it will try to load your news items, wall, audios (your audios, recommended and populars) and friends. At the moment there are only a few supported actions for these items:"
msgstr ""
msgid "* Audio files: You can play the currently selected song, view the song's details (including lyrics, if available), add or remove from your library, and download it to a desired place in your hard drive. You can find audio files in your news feed or in your own audios buffers. You can find audios as post's attachments. You can create an audios timeline for displaying other's audios."
msgstr ""
msgid "* News feed's post: In your news feed buffer, you can press return in any post and socializer will open a new dialogue which can be different, depending in the kind of post you are when the return key was pressed. For example it will open the post if you are focusing a \"normal\" post, a list of people if you are in a post wich indicates that someone has added friends, an audio displayer if you are in a post wich indicates that someone has added an audio, etc."
msgstr ""
msgid "* Wall posts: It will show the post in a dialogue so you could interact with its attachments, view and post comments, or like/unlike/share the post."
msgstr ""
msgid "* You can send a message to someone by pressing the send message button in the buffer where you are, if available. Deactivated accounts cannot receive messages."
msgstr ""
msgid "### Making a post"
msgstr ""
msgid "When you press the post button, a new dialogue will show up. This dialogue allows you to post something in your wall. In this dialogue you have to write a message. You can translate your message and fix your spelling mistakes. Also you can post an URL address, socializer will try to add it as an attachment, so you will not have to worry about this. When you're ready, just press the send button and it'll be done."
msgstr ""
msgid "If you want to add some photos, you can press the attach button, then press the kind of attachment you want to add. After this, select the file you want to add and you will see it in the list, once processed. When you are done with attachments, press the OK button, and continue with your post. When you are ready, press the send button. Your post could take some time to be published, depending in the amount of files you have added, but it should be displayed in your wall and newsfeed as soon as it is posted."
msgstr ""
msgid "### Working with posts in news feed"
msgstr ""
msgid "You can press the return key in any post in your news feed for opening a new dialogue with some information. The information and dialogue will be different if you are viewing a friendship's notification (when someone has added some friends), an audio file, or a regular post."
msgstr ""
msgid "If you open a regular post in your newsfeed, you will be able to see the comments in a list, indicate if you do like or dislike the post, repost or add a new comment. If the post has some attachments, you'll find a list populated with them, you can press return in an attachment to execute its default action, wich will be different depending on the kind of attachment that you are viewing."
msgstr ""
msgid "For friend notifications, you can only view the new added friends in a list and there are some kind of posts that aren't handled. It should be improved."
msgstr ""
msgid "Additionally, you can press the menu Key or the right click for displaying a menu with some quick actions available for the post you are focusing. These actions are different for every post type."
msgstr ""
msgid "### Working with songs"
msgstr ""
msgid "Note: the following applies to audio timelines too."
msgstr ""
msgid "If you want to play or view audio's details, you'll have to navigate to the tree view, and, using the down arrow, look for \"my audios\", \"populars\" or \"Recommendations\". You will see two more buttons, play and play all. The play button will play the currently selected audio, and the play all button will play audios in the current buffer, starting with the current selected item. You can go to the song's list, look for a desired song and press the play button, or Ctrl+return, which is a keyboard shorcut. Take in to account that there are some keyboard shorcuts that only work in the list of items."
msgstr ""
msgid "You can play audio from any buffer, just press ctrl+return for making the audio playback possible."
msgstr ""
msgid "If someone has added multiple audios at once to his library, you will see something like this in your newsfeed: \"(friend) has added 4 audios: audio 1, audio2, audio3 and audio4\". You can press return in the post for opening the audio's details dialogue, where you will be able to see a list with these audios. By default the first detected song is selected, which means that you could read its details by pressing tab, download or add it to your library. If you change the audio in the list, the information will be updated and you will see details and actions will take effect in the new selected audio."
msgstr ""
msgid "When an audio file is playing, you can press f5 and f6 for decreasing and increasing volume, respectively, or control+shift+return for play/pause."
msgstr ""
msgid "If you want to see some details for the selected audio file, you can do it by pressing the return key. You will be able to read some useful information (title, artist, duration and the lyric, if available). Also you will be able to download the song to your hard drive, you have to press the download button in the details' dialogue."
msgstr ""
msgid "When the download starts, you can close the details dialogue and check the status bar in the main window for seeing the current progress."
msgstr ""
msgid "Additionally, you can search for audios by using the menu bar, in the buffer menu, select search, then audio. It will display a dialog where you have to set your search preferences."
msgstr ""
msgid "If you press the menu key, you will see a menu where you will be able to do some actions, for example, add the audio to an album, or add/remove the song from your library."
msgstr ""
msgid "## menu Bar"
msgstr ""
msgid "You can go to the menu bar by pressing ALT. Right now, there are three menus, application, buffer and help:"
msgstr ""
msgid "### Application menu"
msgstr ""
msgid "* Create. Here you can create some things in VK. The only supported item at this moment is the audio album."
msgstr ""
msgid "* Delete: Removes items from the VK servers. The only supported item here is the audio album."
msgstr ""
msgid "* you can set your preferences by opening the preferences dialog located in this menu."
msgstr ""
msgid "### Buffer menu"
msgstr ""
msgid "* new timeline: This option allows you to create a new timeline. This kind of buffers is capable of download all posts in an user's profile."
msgstr ""
msgid "* search: This submenu allows you to create a new buffer, at the moment, you can create only a kind of buffer, an audio search. The audio search will be located in the music category and will have the last 299 results of your query."
msgstr ""
msgid "* Update current buffer: perform an update operation in the selected buffer, which will retrieve the new items."
msgstr ""
msgid "* Load previous items: Get the previous items for the currently focused buffer."
msgstr ""
msgid "* Remove buffer: Tries to remove the current buffer. Default buffers can't be removed."
msgstr ""
msgid "The help menu is self explanatory."
msgstr ""
msgid "## Contributing"
msgstr ""
msgid "If you notice some errors in this document, or features that are not documented yet, you can suggest those changes by contacting me (more information can be find in the following section)."
msgstr ""
msgid "## contact"
msgstr ""
msgid "If you have questions, don't esitate to contact me in [Twitter,](https://twitter.com/manuelcortez00) or sending me an email to manuel(at)manuelcortez(dot)net. Just replace the words in parentheses with the original signs."
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
name = "Socializer" name = "Socializer"
version = "0.13" version = "0.14"
author = u"Manuel Cortéz" author = u"Manuel Cortéz"
authorEmail = "manuel@manuelcortez.net" authorEmail = "manuel@manuelcortez.net"
copyright = u"Copyright (C) 2016, Manuel cortéz." copyright = u"Copyright (C) 2016, Manuel cortéz."

View File

@@ -20,6 +20,7 @@ class attach(object):
imageInfo = {"type": "photo", "file": image, "description": os.path.basename(image)} imageInfo = {"type": "photo", "file": image, "description": os.path.basename(image)}
log.debug("Image data to upload: %r" % (imageInfo,)) log.debug("Image data to upload: %r" % (imageInfo,))
self.attachments.append(imageInfo) self.attachments.append(imageInfo)
# Translators: This is the text displayed in the attachments dialog, when the user adds a photo.
info = [_(u"Photo"), os.path.basename(image)] info = [_(u"Photo"), os.path.basename(image)]
self.dialog.attachments.insert_item(False, *info) self.dialog.attachments.insert_item(False, *info)
self.dialog.remove.Enable(True) self.dialog.remove.Enable(True)

View File

@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import languageHandler
import arrow
import wx import wx
import widgetUtils import widgetUtils
import messages import messages
@@ -7,11 +9,12 @@ import posts
import player import player
import output import output
import logging import logging
import selector
from wxUI.tabs import home from wxUI.tabs import home
from pubsub import pub from pubsub import pub
from sessionmanager import session from sessionmanager import session
from mysc.thread_utils import call_threaded from mysc.thread_utils import call_threaded
from wxUI import commonMessages from wxUI import commonMessages, menus
from vk import upload from vk import upload
from vk.exceptions import VkAPIMethodError from vk.exceptions import VkAPIMethodError
@@ -19,6 +22,10 @@ log = logging.getLogger("controller.buffers")
class baseBuffer(object): class baseBuffer(object):
""" a basic representation of a buffer. Other buffers should be derived from this class""" """ a basic representation of a buffer. Other buffers should be derived from this class"""
def get_post(self):
return self.session.db[self.name]["items"][self.tab.list.get_selected()]
def __init__(self, parent=None, name="", session=None, composefunc=None, *args, **kwargs): def __init__(self, parent=None, name="", session=None, composefunc=None, *args, **kwargs):
""" parent wx.Treebook: parent for the buffer panel, """ parent wx.Treebook: parent for the buffer panel,
name str: Name for saving this buffer's data in the local storage variable, name str: Name for saving this buffer's data in the local storage variable,
@@ -36,6 +43,9 @@ class baseBuffer(object):
self.update_function = "get_page" self.update_function = "get_page"
self.name = name self.name = name
self.connect_events() self.connect_events()
self.user_key = "source_id"
self.post_key = "post_id"
self.can_get_items = True
def create_tab(self, parent): def create_tab(self, parent):
""" Creates the Wx panel.""" """ Creates the Wx panel."""
@@ -50,6 +60,7 @@ class baseBuffer(object):
""" Retrieves items from the VK API. This function is called repeatedly by the main controller and users could call it implicitly as well with the update buffer option. """ Retrieves items from the VK API. This function is called repeatedly by the main controller and users could call it implicitly as well with the update buffer option.
show_nextpage boolean: If it's true, it will try to load previous results. show_nextpage boolean: If it's true, it will try to load previous results.
""" """
if self.can_get_items == False: return
retrieved = True # Control variable for handling unauthorised/connection errors. retrieved = True # Control variable for handling unauthorised/connection errors.
try: try:
num = getattr(self.session, "get_newsfeed")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs) num = getattr(self.session, "get_newsfeed")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs)
@@ -111,6 +122,80 @@ class baseBuffer(object):
def connect_events(self): def connect_events(self):
widgetUtils.connect_event(self.tab.post, widgetUtils.BUTTON_PRESSED, self.post) widgetUtils.connect_event(self.tab.post, widgetUtils.BUTTON_PRESSED, self.post)
widgetUtils.connect_event(self.tab.list.list, widgetUtils.KEYPRESS, self.get_event) widgetUtils.connect_event(self.tab.list.list, widgetUtils.KEYPRESS, self.get_event)
widgetUtils.connect_event(self.tab.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu)
widgetUtils.connect_event(self.tab.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key)
self.tab.set_focus_function(self.onFocus)
def show_menu(self, ev, pos=0, *args, **kwargs):
if self.tab.list.get_count() == 0: return
menu = self.get_menu()
if pos != 0:
self.tab.PopupMenu(menu, pos)
else:
self.tab.PopupMenu(menu, ev.GetPosition())
def show_menu_by_key(self, ev):
if self.tab.list.get_count() == 0:
return
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
self.show_menu(widgetUtils.MENU, pos=self.tab.list.list.GetPosition())
def get_menu(self):
m = menus.postMenu()
p = self.get_post()
if p.has_key("likes") == False:
m.like.Enable(False)
elif p["likes"]["user_likes"] == 1:
m.like.Enable(False)
m.dislike.Enable(True)
if p.has_key("comments") == False:
m.comment.Enable(False)
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_post, menuitem=m.open)
widgetUtils.connect_event(m, widgetUtils.MENU, self.do_like, menuitem=m.like)
widgetUtils.connect_event(m, widgetUtils.MENU, self.do_dislike, menuitem=m.dislike)
widgetUtils.connect_event(m, widgetUtils.MENU, self.do_comment, menuitem=m.comment)
return m
def do_like(self, *args, **kwargs):
post = self.get_post()
user = post[self.user_key]
id = post[self.post_key]
if post.has_key("type"):
type_ = post["type"]
else:
type_ = "post"
l = self.session.vk.client.likes.add(owner_id=user, item_id=id, type=type_)
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["count"] = l["likes"]
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["user_likes"] = 1
# Translators: This will be used when user presses like.
output.speak(_(u"You liked this"))
def do_dislike(self, *args, **kwargs):
post = self.get_post()
user = post[self.user_key]
id = post[self.post_key]
if post.has_key("type"):
type_ = post["type"]
else:
type_ = "post"
l = self.session.vk.client.likes.delete(owner_id=user, item_id=id, type=type_)
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["count"] = l["likes"]
self.session.db[self.name]["items"][self.tab.list.get_selected()]["likes"]["user_likes"] = 2
# Translators: This will be user in 'dislike'
output.speak(_(u"You don't like this"))
def do_comment(self, *args, **kwargs):
comment = messages.comment(title=_(u"Add a comment"), caption="", text="")
if comment.message.get_response() == widgetUtils.OK:
msg = comment.message.get_text().encode("utf-8")
post = self.get_post()
try:
user = post[self.user_key]
id = post[self.post_key]
self.session.vk.client.wall.addComment(owner_id=user, post_id=id, text=msg)
output.speak(_(u"You've posted a comment"))
except Exception as msg:
print msg
def get_event(self, ev): def get_event(self, ev):
if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown() and ev.ShiftDown(): event = "pause_audio" if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown() and ev.ShiftDown(): event = "pause_audio"
@@ -138,7 +223,7 @@ class baseBuffer(object):
if post.has_key("type") and post["type"] == "audio": if post.has_key("type") and post["type"] == "audio":
pub.sendMessage("play-audio", audio_object=post["audio"]["items"][0]) pub.sendMessage("play-audio", audio_object=post["audio"]["items"][0])
def open_post(self): def open_post(self, *args, **kwargs):
post = self.session.db[self.name]["items"][self.tab.list.get_selected()] post = self.session.db[self.name]["items"][self.tab.list.get_selected()]
if post.has_key("type") and post["type"] == "audio": if post.has_key("type") and post["type"] == "audio":
a = posts.audio(self.session, post["audio"]["items"]) a = posts.audio(self.session, post["audio"]["items"])
@@ -161,9 +246,19 @@ class baseBuffer(object):
else: else:
return [post["source_id"]] return [post["source_id"]]
def onFocus(self, *args,**kwargs):
""" Function executed when the item in a list is selected.
For this buffer it updates the date of posts in the list."""
post = self.session.db[self.name]["items"][self.tab.list.get_selected()]
original_date = arrow.get(post["date"])
created_at = original_date.humanize(locale=languageHandler.getLanguage())
self.tab.list.list.SetStringItem(self.tab.list.get_selected(), 2, created_at)
class feedBuffer(baseBuffer): class feedBuffer(baseBuffer):
def get_items(self, show_nextpage=False): def get_items(self, show_nextpage=False):
if self.can_get_items == False: return
retrieved = True retrieved = True
try: try:
num = getattr(self.session, "get_page")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs) num = getattr(self.session, "get_page")(show_nextpage=show_nextpage, name=self.name, *self.args, **self.kwargs)
@@ -197,6 +292,11 @@ class feedBuffer(baseBuffer):
else: else:
return False return False
def __init__(self, *args, **kwargs):
super(feedBuffer, self).__init__(*args, **kwargs)
self.user_key = "from_id"
self.post_key = "id"
class audioBuffer(feedBuffer): class audioBuffer(feedBuffer):
def create_tab(self, parent): def create_tab(self, parent):
self.tab = home.audioTab(parent) self.tab = home.audioTab(parent)
@@ -210,7 +310,7 @@ class audioBuffer(feedBuffer):
selected = self.tab.list.get_selected() selected = self.tab.list.get_selected()
pub.sendMessage("play-audio", audio_object=self.session.db[self.name]["items"][selected]) pub.sendMessage("play-audio", audio_object=self.session.db[self.name]["items"][selected])
def open_post(self): def open_post(self, *args, **kwargs):
selected = self.tab.list.get_selected() selected = self.tab.list.get_selected()
audios = [self.session.db[self.name]["items"][selected]] audios = [self.session.db[self.name]["items"][selected]]
a = posts.audio(self.session, audios) a = posts.audio(self.session, audios)
@@ -240,8 +340,75 @@ class audioBuffer(feedBuffer):
return False return False
def get_more_items(self, *args, **kwargs): def get_more_items(self, *args, **kwargs):
# Translators: Some buffers can't use the get previous item feature due to API limitations.
output.speak(_(u"This buffer doesn't support getting more items.")) output.speak(_(u"This buffer doesn't support getting more items."))
def onFocus(self, *args, **kwargs):
pass
def add_to_library(self, *args, **kwargs):
post = self.get_post()
args = {}
args["audio_id"] = post["id"]
if post.has_key("album_id"):
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:
output.speak(_(u"Audio added to your library"))
def remove_from_library(self, *args, **kwargs):
post = self.get_post()
args = {}
args["audio_id"] = post["id"]
args["owner_id"] = self.session.user_id
result = self.session.vk.client.audio.delete(**args)
if int(result) == 1:
output.speak(_(u"Removed audio from library"))
self.tab.list.remove_item(self.tab.list.get_selected())
def move_to_album(self, *args, **kwargs):
album = selector.audioAlbum(_(u"Select the album where you want to move this song"), self.session)
if album.item == None: return
id = self.get_post()["id"]
response = self.session.vk.client.audio.moveToAlbum(album_id=album.item, audio_ids=id)
if response == 1:
# Translators: Used when the user has moved an audio to an album.
output.speak(_(u"Moved"))
def get_menu(self):
p = self.get_post()
m = menus.audioMenu()
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_post, menuitem=m.open)
widgetUtils.connect_event(m, widgetUtils.MENU, self.play_audio, menuitem=m.play)
widgetUtils.connect_event(m, widgetUtils.MENU, self.move_to_album, menuitem=m.move)
# if owner_id is the current user, the audio is added to the user's audios.
if p["owner_id"] == self.session.user_id:
m.library.SetItemLabel(_(u"&Remove from library"))
widgetUtils.connect_event(m, widgetUtils.MENU, self.remove_from_library, menuitem=m.library)
else:
widgetUtils.connect_event(m, widgetUtils.MENU, self.add_to_library, menuitem=m.library)
return m
class audioAlbum(audioBuffer):
def create_tab(self, parent):
self.tab = home.audioAlbumTab(parent)
self.tab.play.Enable(False)
self.tab.play_all.Enable(False)
def connect_events(self):
super(audioAlbum, self).connect_events()
widgetUtils.connect_event(self.tab.load, widgetUtils.BUTTON_PRESSED, self.load_album)
def load_album(self, *args, **kwargs):
output.speak(_(u"Loading album..."))
self.can_get_items = True
self.tab.load.Enable(False)
wx.CallAfter(self.get_items)
self.tab.play.Enable(True)
self.tab.play_all.Enable(True)
class empty(object): class empty(object):
def __init__(self, name=None, parent=None, *args, **kwargs): def __init__(self, name=None, parent=None, *args, **kwargs):
@@ -258,13 +425,21 @@ class empty(object):
class chatBuffer(baseBuffer): class chatBuffer(baseBuffer):
def onFocus(self, *args, **kwargs):
msg = self.session.db[self.name]["items"][-1]
if msg.has_key("read_state") and msg["read_state"] == 0 and msg["id"] not in self.reads:
self.reads.append(msg["id"])
self.session.db[self.name]["items"][-1]["read_state"] = 1
def create_tab(self, parent): def create_tab(self, parent):
self.tab = home.chatTab(parent) self.tab = home.chatTab(parent)
def connect_events(self): def connect_events(self):
widgetUtils.connect_event(self.tab.send, widgetUtils.BUTTON_PRESSED, self.send_chat_to_user) widgetUtils.connect_event(self.tab.send, widgetUtils.BUTTON_PRESSED, self.send_chat_to_user)
self.tab.set_focus_function(self.onFocus)
def get_items(self, show_nextpage=False): def get_items(self, show_nextpage=False):
if self.can_get_items == False: return
retrieved = True # Control variable for handling unauthorised/connection errors. retrieved = True # Control variable for handling unauthorised/connection errors.
try: try:
num = getattr(self.session, "get_messages")(name=self.name, *self.args, **self.kwargs) num = getattr(self.session, "get_messages")(name=self.name, *self.args, **self.kwargs)
@@ -290,6 +465,10 @@ class chatBuffer(baseBuffer):
if text == "": return if text == "": return
response = self.session.vk.client.messages.send(user_id=self.kwargs["user_id"], message=text) response = self.session.vk.client.messages.send(user_id=self.kwargs["user_id"], message=text)
def __init__(self, *args, **kwargs):
super(chatBuffer, self).__init__(*args, **kwargs)
self.reads = []
class peopleBuffer(feedBuffer): class peopleBuffer(feedBuffer):
def create_tab(self, parent): def create_tab(self, parent):
@@ -302,3 +481,26 @@ class peopleBuffer(feedBuffer):
def new_chat(self, *args, **kwargs): def new_chat(self, *args, **kwargs):
user_id = self.session.db[self.name]["items"][self.tab.list.get_selected()]["id"] user_id = self.session.db[self.name]["items"][self.tab.list.get_selected()]["id"]
pub.sendMessage("new-chat", user_id=user_id) pub.sendMessage("new-chat", user_id=user_id)
def onFocus(self, *args, **kwargs):
post = self.session.db[self.name]["items"][self.tab.list.get_selected()]
if post.has_key("last_seen") == False: return
original_date = arrow.get(post["last_seen"]["time"])
created_at = original_date.humanize(locale=languageHandler.getLanguage())
self.tab.list.list.SetStringItem(self.tab.list.get_selected(), 1, created_at)
def open_timeline(self, *args, **kwargs):
pass
def get_menu(self, *args, **kwargs):
m = menus.peopleMenu()
widgetUtils.connect_event(m, widgetUtils.MENU, self.new_chat, menuitem=m.message)
widgetUtils.connect_event(m, widgetUtils.MENU, self.open_timeline, menuitem=m.timeline)
return m
def open_post(self, *args, **kwargs): pass
def play_audio(self, *args, **kwargs): pass
def pause_audio(self, *args, **kwargs): pass

View File

@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import time
import os import os
import wx import wx
import utils import utils
@@ -11,13 +12,16 @@ import posts
import webbrowser import webbrowser
import logging import logging
import longpoolthread import longpoolthread
import selector
from vk.exceptions import VkAuthError
from pubsub import pub from pubsub import pub
from mysc.repeating_timer import RepeatingTimer from mysc.repeating_timer import RepeatingTimer
from mysc.thread_utils import call_threaded from mysc.thread_utils import call_threaded
from mysc import localization
from sessionmanager import session from sessionmanager import session
from wxUI import (mainWindow, commonMessages) from wxUI import (mainWindow, commonMessages)
from wxUI.dialogs import search as searchDialogs from wxUI.dialogs import search as searchDialogs
from wxUI.dialogs import timeline from wxUI.dialogs import timeline, creation
from update import updater from update import updater
log = logging.getLogger("controller.main") log = logging.getLogger("controller.main")
@@ -55,18 +59,27 @@ class Controller(object):
log.debug("Creating controls for the window...") log.debug("Creating controls for the window...")
posts_ = buffers.empty(parent=self.window.tb, name="posts") posts_ = buffers.empty(parent=self.window.tb, name="posts")
self.buffers.append(posts_) self.buffers.append(posts_)
# Translators: Name for the posts tab in the tree view.
self.window.add_buffer(posts_.tab, _(u"Posts")) self.window.add_buffer(posts_.tab, _(u"Posts"))
home = buffers.baseBuffer(parent=self.window.tb, name="home_timeline", session=self.session, composefunc="compose_new", endpoint="newsfeed", count=self.session.settings["buffers"]["count_for_wall_buffers"]) home = buffers.baseBuffer(parent=self.window.tb, name="home_timeline", session=self.session, composefunc="compose_new", endpoint="newsfeed", count=self.session.settings["buffers"]["count_for_wall_buffers"])
self.buffers.append(home) self.buffers.append(home)
# Translators: Newsfeed's name in the tree view.
self.window.insert_buffer(home.tab, _(u"Home"), self.window.search("posts")) self.window.insert_buffer(home.tab, _(u"Home"), self.window.search("posts"))
self.repeatedUpdate = RepeatingTimer(180, self.update_all_buffers) self.repeatedUpdate = RepeatingTimer(180, self.update_all_buffers)
self.repeatedUpdate.start() self.repeatedUpdate.start()
self.readMarker = RepeatingTimer(120, self.mark_as_read)
self.readMarker.start()
feed = buffers.feedBuffer(parent=self.window.tb, name="me_feed", composefunc="compose_status", session=self.session, endpoint="get", parent_endpoint="wall", extended=1, count=self.session.settings["buffers"]["count_for_wall_buffers"]) feed = buffers.feedBuffer(parent=self.window.tb, name="me_feed", composefunc="compose_status", session=self.session, endpoint="get", parent_endpoint="wall", extended=1, count=self.session.settings["buffers"]["count_for_wall_buffers"])
self.buffers.append(feed) self.buffers.append(feed)
# Translators: Own user's wall name in the tree view.
self.window.insert_buffer(feed.tab, _(u"My wall"), self.window.search("posts")) self.window.insert_buffer(feed.tab, _(u"My wall"), self.window.search("posts"))
audios = buffers.empty(parent=self.window.tb, name="audios") audios = buffers.empty(parent=self.window.tb, name="audios")
self.buffers.append(audios) self.buffers.append(audios)
# Translators: name for the music category in the tree view.
self.window.add_buffer(audios.tab, _(u"Music")) self.window.add_buffer(audios.tab, _(u"Music"))
audio = buffers.audioBuffer(parent=self.window.tb, name="me_audio", composefunc="compose_audio", session=self.session, endpoint="get", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"]) audio = buffers.audioBuffer(parent=self.window.tb, name="me_audio", composefunc="compose_audio", session=self.session, endpoint="get", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"])
self.buffers.append(audio) self.buffers.append(audio)
self.window.insert_buffer(audio.tab, _(u"My audios"), self.window.search("audios")) self.window.insert_buffer(audio.tab, _(u"My audios"), self.window.search("audios"))
@@ -76,6 +89,9 @@ class Controller(object):
r_audio = buffers.audioBuffer(parent=self.window.tb, name="recommended_audio", composefunc="compose_audio", session=self.session, endpoint="getRecommendations", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"]) r_audio = buffers.audioBuffer(parent=self.window.tb, name="recommended_audio", composefunc="compose_audio", session=self.session, endpoint="getRecommendations", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"])
self.buffers.append(r_audio) self.buffers.append(r_audio)
self.window.insert_buffer(r_audio.tab, _(u"Recommendations"), self.window.search("audios")) self.window.insert_buffer(r_audio.tab, _(u"Recommendations"), self.window.search("audios"))
albums = buffers.empty(parent=self.window.tb, name="albums")
self.buffers.append(albums)
self.window.insert_buffer(albums.tab, _(u"Albums"), self.window.search("audios"))
people = buffers.empty(parent=self.window.tb, name="people") people = buffers.empty(parent=self.window.tb, name="people")
self.buffers.append(people) self.buffers.append(people)
self.window.add_buffer(people.tab, _(u"People")) self.window.add_buffer(people.tab, _(u"People"))
@@ -88,6 +104,7 @@ class Controller(object):
timelines = buffers.empty(parent=self.window.tb, name="timelines") timelines = buffers.empty(parent=self.window.tb, name="timelines")
self.buffers.append(timelines) self.buffers.append(timelines)
self.window.add_buffer(timelines.tab, _(u"Timelines")) self.window.add_buffer(timelines.tab, _(u"Timelines"))
self.window.realize()
def connect_events(self): def connect_events(self):
log.debug("Connecting events to responses...") log.debug("Connecting events to responses...")
@@ -98,6 +115,7 @@ class Controller(object):
pub.subscribe(self.view_post, "open-post") pub.subscribe(self.view_post, "open-post")
pub.subscribe(self.update_status_bar, "update-status-bar") pub.subscribe(self.update_status_bar, "update-status-bar")
pub.subscribe(self.chat_from_id, "new-chat") pub.subscribe(self.chat_from_id, "new-chat")
pub.subscribe(self.authorisation_failed, "authorisation-failed")
widgetUtils.connect_event(self.window, widgetUtils.CLOSE_EVENT, self.exit) widgetUtils.connect_event(self.window, widgetUtils.CLOSE_EVENT, self.exit)
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.update_buffer, menuitem=self.window.update_buffer) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.update_buffer, menuitem=self.window.update_buffer)
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.check_for_updates, menuitem=self.window.check_for_updates) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.check_for_updates, menuitem=self.window.check_for_updates)
@@ -108,6 +126,9 @@ class Controller(object):
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.changelog, menuitem=self.window.changelog) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.changelog, menuitem=self.window.changelog)
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.configuration, menuitem=self.window.settings_dialog) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.configuration, menuitem=self.window.settings_dialog)
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.new_timeline, menuitem=self.window.timeline) widgetUtils.connect_event(self.window, widgetUtils.MENU, self.new_timeline, menuitem=self.window.timeline)
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.create_audio_album, menuitem=self.window.audio_album)
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.delete_audio_album, menuitem=self.window.delete_audio_album)
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.check_documentation, menuitem=self.window.documentation)
pub.subscribe(self.get_chat, "order-sent-message") pub.subscribe(self.get_chat, "order-sent-message")
def disconnect_events(self): def disconnect_events(self):
@@ -115,21 +136,31 @@ class Controller(object):
pub.unsubscribe(self.in_post, "posted") pub.unsubscribe(self.in_post, "posted")
pub.unsubscribe(self.download, "download-file") pub.unsubscribe(self.download, "download-file")
pub.unsubscribe(self.play_audio, "play-audio") pub.unsubscribe(self.play_audio, "play-audio")
pub.unsubscribe(self.authorisation_failed, "authorisation-failed")
pub.unsubscribe(self.play_audios, "play-audios") pub.unsubscribe(self.play_audios, "play-audios")
pub.unsubscribe(self.view_post, "open-post") pub.unsubscribe(self.view_post, "open-post")
pub.unsubscribe(self.update_status_bar, "update-status-bar") pub.unsubscribe(self.update_status_bar, "update-status-bar")
def authorisation_failed(self):
commonMessages.bad_authorisation()
def login(self): def login(self):
self.window.change_status(_(u"Logging in VK")) self.window.change_status(_(u"Logging in VK"))
self.session.login() self.session.login()
self.window.change_status(_(u"Ready")) self.window.change_status(_(u"Ready"))
for i in self.buffers: for i in self.buffers:
if hasattr(i, "get_items"): if hasattr(i, "get_items"):
# Translators: {0} will be replaced with the name of a buffer.
self.window.change_status(_(u"Loading items for {0}").format(i.name,)) self.window.change_status(_(u"Loading items for {0}").format(i.name,))
i.get_items() i.get_items()
self.window.change_status(_(u"Ready")) self.window.change_status(_(u"Ready"))
self.longpool = longpoolthread.worker(self.session) self.longpool = longpoolthread.worker(self.session)
self.longpool.start() self.longpool.start()
self.status_setter = RepeatingTimer(900, self.set_online)
self.status_setter.start()
self.set_online()
self.create_unread_messages()
wx.CallAfter(self.get_audio_albums, self.session.user_id)
def in_post(self, buffer): def in_post(self, buffer):
buffer = self.search(buffer) buffer = self.search(buffer)
@@ -139,6 +170,7 @@ class Controller(object):
def update_all_buffers(self): def update_all_buffers(self):
log.debug("Updating buffers...") log.debug("Updating buffers...")
self.session.audio_albums = self.session.vk.client.audio.getAlbums(owner_id=self.session.user_id)["items"]
for i in self.buffers: for i in self.buffers:
if hasattr(i, "get_items"): if hasattr(i, "get_items"):
i.get_items() i.get_items()
@@ -155,7 +187,6 @@ class Controller(object):
player.player.play_all(audios) player.player.play_all(audios)
def view_post(self, post_object, controller_): def view_post(self, post_object, controller_):
# print post_object
p = getattr(posts, controller_)(self.session, post_object) p = getattr(posts, controller_)(self.session, post_object)
p.dialog.get_response() p.dialog.get_response()
p.dialog.Destroy() p.dialog.Destroy()
@@ -191,6 +222,7 @@ class Controller(object):
newbuff = buffers.audioBuffer(parent=self.window.tb, name=u"{0}_audiosearch".format(q.decode("utf-8"),), session=self.session, composefunc="compose_audio", parent_endpoint="audio", endpoint="search", q=q, count=count, auto_complete=auto_complete, lyrics=lyrics, performer_only=performer_only, sort=sort) newbuff = buffers.audioBuffer(parent=self.window.tb, name=u"{0}_audiosearch".format(q.decode("utf-8"),), session=self.session, composefunc="compose_audio", parent_endpoint="audio", endpoint="search", q=q, count=count, auto_complete=auto_complete, lyrics=lyrics, performer_only=performer_only, sort=sort)
self.buffers.append(newbuff) self.buffers.append(newbuff)
call_threaded(newbuff.get_items) call_threaded(newbuff.get_items)
# Translators: {0} will be replaced with the search term.
self.window.insert_buffer(newbuff.tab, _(u"Search for {0}").format(q.decode("utf-8"),), self.window.search("audios")) self.window.insert_buffer(newbuff.tab, _(u"Search for {0}").format(q.decode("utf-8"),), self.window.search("audios"))
def update_status_bar(self, status): def update_status_bar(self, status):
@@ -221,12 +253,9 @@ class Controller(object):
b = self.get_current_buffer() b = self.get_current_buffer()
if not hasattr(b, "get_users"): if not hasattr(b, "get_users"):
b = self.search("home_timeline") b = self.search("home_timeline")
# ids = b.get_users()
d = [] d = []
# for i in ids:
# d.append((i, self.session.get_user_name(i)))
for i in self.session.db["users"]: for i in self.session.db["users"]:
d.append((i, self.session.get_user_name(i))) d.append((i, self.session.get_user_name(i, "nom")))
for i in self.session.db["groups"]: for i in self.session.db["groups"]:
d.append((-i, self.session.get_user_name(-i))) d.append((-i, self.session.get_user_name(-i)))
a = timeline.timelineDialog([i[1] for i in d]) a = timeline.timelineDialog([i[1] for i in d])
@@ -240,12 +269,19 @@ class Controller(object):
if user_id == None: if user_id == None:
commonMessages.no_user_exist() commonMessages.no_user_exist()
return return
print user_id
if buffertype == "audio": if buffertype == "audio":
buffer = buffers.audioBuffer(parent=self.window.tb, name="{0}_audio".format(user_id,), composefunc="compose_audio", session=self.session, endpoint="get", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"], user_id=user_id) buffer = buffers.audioBuffer(parent=self.window.tb, name="{0}_audio".format(user_id,), composefunc="compose_audio", session=self.session, endpoint="get", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"], owner_id=user_id)
name_ = _(u"{0}'s audios").format(user,) # Translators: {0} will be replaced with an user.
name_ = _(u"{0}'s audios").format(self.session.get_user_name(user_id, "gen"),)
elif buffertype == "wall": elif buffertype == "wall":
buffer = buffers.feedBuffer(parent=self.window.tb, name="{0}_feed".format(user_id,), composefunc="compose_status", session=self.session, endpoint="get", parent_endpoint="wall", extended=1, count=self.session.settings["buffers"]["count_for_wall_buffers"], owner_id=user_id) buffer = buffers.feedBuffer(parent=self.window.tb, name="{0}_feed".format(user_id,), composefunc="compose_status", session=self.session, endpoint="get", parent_endpoint="wall", extended=1, count=self.session.settings["buffers"]["count_for_wall_buffers"], owner_id=user_id)
name_ = _(u"{0}'s wall posts").format(user,) # Translators: {0} will be replaced with an user.
name_ = _(u"{0}'s wall posts").format(self.session.get_user_name(user_id, "gen"),)
elif buffertype == "friends":
buffer = buffers.peopleBuffer(parent=self.window.tb, name="friends_{0}".format(user_id,), composefunc="compose_person", session=self.session, endpoint="get", parent_endpoint="friends", count=5000, fields="uid, first_name, last_name, last_seen", user_id=user_id)
# Translators: {0} will be replaced with an user.
name_ = _(u"{0}'s friends").format(self.session.get_user_name(user_id, "friends"),)
self.buffers.append(buffer) self.buffers.append(buffer)
call_threaded(self.complete_buffer_creation, buffer=buffer, name_=name_, position=self.window.search("timelines")) call_threaded(self.complete_buffer_creation, buffer=buffer, name_=name_, position=self.window.search("timelines"))
@@ -264,19 +300,23 @@ class Controller(object):
if i.kwargs.has_key("user_id") and i.kwargs["user_id"] == user_id: return i if i.kwargs.has_key("user_id") and i.kwargs["user_id"] == user_id: return i
return None return None
def chat_from_id(self, user_id): def chat_from_id(self, user_id, setfocus=True):
b = self.search_chat_buffer(user_id) b = self.search_chat_buffer(user_id)
if b != None: if b != None:
pos = self.window.search(b.name) pos = self.window.search(b.name)
self.window.change_buffer(pos) if setfocus:
return b.tab.text.SetFocus() self.window.change_buffer(pos)
return b.tab.text.SetFocus()
return
buffer = buffers.chatBuffer(parent=self.window.tb, name="{0}_messages".format(user_id,), composefunc="compose_message", session=self.session, count=200, user_id=user_id, rev=1) buffer = buffers.chatBuffer(parent=self.window.tb, name="{0}_messages".format(user_id,), composefunc="compose_message", session=self.session, count=200, user_id=user_id, rev=1)
self.buffers.append(buffer) self.buffers.append(buffer)
self.window.insert_buffer(buffer.tab, _(u"Chat with {0}").format(self.session.get_user_name(user_id,)), self.window.search("chats")) # Translators: {0} will be replaced with an user.
pos = self.window.search(buffer.name) self.window.insert_buffer(buffer.tab, _(u"Chat with {0}").format(self.session.get_user_name(user_id, "ins")), self.window.search("chats"))
self.window.change_buffer(pos) if setfocus:
pos = self.window.search(buffer.name)
self.window.change_buffer(pos)
wx.CallAfter(buffer.get_items) wx.CallAfter(buffer.get_items)
buffer.tab.text.SetFocus() if setfocus: buffer.tab.text.SetFocus()
return True return True
def get_chat(self, obj=None): def get_chat(self, obj=None):
@@ -302,3 +342,72 @@ class Controller(object):
num = self.session.order_buffer(buffer.name, data, True) num = self.session.order_buffer(buffer.name, data, True)
buffer.insert(self.session.db[buffer.name]["items"][-1], False) buffer.insert(self.session.db[buffer.name]["items"][-1], False)
self.session.soundplayer.play("chat.ogg") self.session.soundplayer.play("chat.ogg")
def set_online(self):
try:
r = self.session.vk.client.account.setOnline()
except:
log.error("Error in setting online for the current user")
def create_unread_messages(self):
msgs = self.session.vk.client.messages.getDialogs(count=200, unread=1)
for i in msgs["items"]:
wx.CallAfter(self.chat_from_id, i["message"]["user_id"], setfocus=False)
def mark_as_read(self):
ids = ""
for i in self.buffers:
if hasattr(i, "reads"):
for z in i.reads:
ids = ids+"%d," % (z,)
i.reads = []
if ids != "":
response = self.session.vk.client.messages.markAsRead(message_ids=ids)
def get_audio_albums(self, user_id=None):
albums = self.session.vk.client.audio.getAlbums(owner_id=user_id)
self.session.audio_albums = albums["items"]
for i in albums["items"]:
buffer = buffers.audioAlbum(parent=self.window.tb, name="{0}_audio_album".format(i["id"],), composefunc="compose_audio", session=self.session, endpoint="get", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"], user_id=user_id, album_id=i["id"])
buffer.can_get_items = False
# Translators: {0} Will be replaced with an audio album's title.
name_ = _(u"Album: {0}").format(i["title"],)
self.buffers.append(buffer)
self.window.insert_buffer(buffer.tab, name_, self.window.search("albums"))
buffer.get_items()
# inserts a pause of 1 second here, so we'll avoid errors 6 in VK.
def create_audio_album(self, *args, **kwargs):
d = creation.audio_album()
if d.get_response() == widgetUtils.OK and d.get("title") != "":
response = self.session.vk.client.audio.addAlbum(title=d.get("title"))
if response.has_key("album_id") == False: return
album_id = response["album_id"]
buffer = buffers.audioAlbum(parent=self.window.tb, name="{0}_audio_album".format(album_id,), composefunc="compose_audio", session=self.session, endpoint="get", parent_endpoint="audio", full_list=True, count=self.session.settings["buffers"]["count_for_audio_buffers"], user_id=self.session.user_id, album_id=album_id)
buffer.can_get_items = False
# Translators: {0} will be replaced with an audio album's title.
name_ = _(u"Album: {0}").format(d.get("title"),)
self.buffers.append(buffer)
self.window.insert_buffer(buffer.tab, name_, self.window.search("albums"))
buffer.get_items()
self.session.audio_albums = self.session.vk.client.audio.getAlbums(owner_id=self.session.user_id)["items"]
def delete_audio_album(self, *args, **kwargs):
answer = selector.audioAlbum(_(u"Select the album you want to delete"), self.session)
if answer.item == None:
return
response = commonMessages.delete_audio_album()
if response != widgetUtils.YES: return
removal = self.session.vk.client.audio.deleteAlbum(album_id=answer.item)
buffer = self.search("{0}_audio_album".format(answer.item,))
buff = self.window.search(buffer.name)
self.window.remove_buffer(buff)
self.buffers.remove(buffer)
del buffer
self.session.audio_albums = self.session.vk.client.audio.getAlbums(owner_id=self.session.user_id)["items"]
def check_documentation(self, *args, **kwargs):
lang = localization.get("documentation")
os.chdir("documentation/%s" % (lang,))
webbrowser.open("manual.html")
os.chdir("../../")

View File

@@ -34,6 +34,7 @@ class audioPlayer(object):
if self.is_working == False: if self.is_working == False:
self.is_working = True self.is_working = True
self.stream = URLStream(url=url["url"]) self.stream = URLStream(url=url["url"])
# Translators: {0} will be replaced with a song's title and {1} with the artist.
msg = _(u"Playing {0} by {1}").format(url["title"], url["artist"]) msg = _(u"Playing {0} by {1}").format(url["title"], url["artist"])
pub.sendMessage("update-status-bar", status=msg) pub.sendMessage("update-status-bar", status=msg)
self.stream.volume = self.vol/100.0 self.stream.volume = self.vol/100.0
@@ -80,7 +81,7 @@ class audioPlayer(object):
self.worker.start() self.worker.start()
def player_function(self): def player_function(self):
if self.stream != None and self.stream.is_playing == False and self.stopped == False: if self.stream != None and self.stream.is_playing == False and self.stopped == False and len(self.stream) == self.stream.position:
if len(self.queue) == 0: if len(self.queue) == 0:
self.worker.cancel() self.worker.cancel()
return return

View File

@@ -23,6 +23,7 @@ def get_user(id, profiles):
for i in profiles: for i in profiles:
if i["id"] == id: if i["id"] == id:
return u"{0} {1}".format(i["first_name"], i["last_name"]) return u"{0} {1}".format(i["first_name"], i["last_name"])
# Translators: This string is user when socializer can't find the right user information.
return _(u"Unknown username") return _(u"Unknown username")
def add_attachment(attachment): def add_attachment(attachment):
@@ -89,6 +90,9 @@ class postController(object):
comments_ = [] comments_ = []
for i in self.comments["items"]: for i in self.comments["items"]:
from_ = get_user(i["from_id"], self.comments["profiles"]) from_ = get_user(i["from_id"], self.comments["profiles"])
if i.has_key("reply_to_user"):
extra_info = get_user(i["reply_to_user"], self.comments["profiles"])
from_ = _(u"{0} Has replied to {1}").format(from_, extra_info)
if len(i["text"]) > 140: if len(i["text"]) > 140:
text = i["text"][:141] text = i["text"][:141]
else: else:
@@ -102,9 +106,11 @@ class postController(object):
def get_post_information(self): def get_post_information(self):
from_ = self.session.get_user_name(self.post[self.user_identifier]) from_ = self.session.get_user_name(self.post[self.user_identifier])
if self.post.has_key("copy_history"): if self.post.has_key("copy_history"):
# Translators: {0} will be replaced with an user.
title = _(u"repost from {0}").format(from_,) title = _(u"repost from {0}").format(from_,)
else: else:
if self.post.has_key("from_id") and self.post.has_key("owner_id"): if self.post.has_key("from_id") and self.post.has_key("owner_id"):
# Translators: {0} will be replaced with the user who is posting, and {2} with the wall owner.
title = _(u"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"])) title = _(u"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: else:
title = _(u"Post from {0}").format(from_,) title = _(u"Post from {0}").format(from_,)
@@ -151,7 +157,7 @@ class postController(object):
self.get_reposts() self.get_reposts()
self.get_comments() self.get_comments()
if self.post["comments"]["can_post"] == 0: if self.post["comments"]["can_post"] == 0:
self.dialog.disable("add_comment") self.dialog.disable("comment")
if self.post["likes"]["can_like"] == 0 and self.post["likes"]["user_likes"] == 0: if self.post["likes"]["can_like"] == 0 and self.post["likes"]["user_likes"] == 0:
self.dialog.disable("like") self.dialog.disable("like")
elif self.post["likes"]["user_likes"] == 1: elif self.post["likes"]["user_likes"] == 1:

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
import widgetUtils
from wxUI.dialogs import selector as gui
class audioAlbum(object):
def __init__(self, title, session):
super(audioAlbum, self).__init__()
self.item = None
self.session = session
self.dialog = gui.selectAlbum(title=title, albums=self.get_albums_as_string())
response = self.dialog.get_response()
if response == widgetUtils.OK:
self.item = self.search_item(self.dialog.get_string())
def get_albums_as_string(self):
return [i["title"] for i in self.session.audio_albums]
def search_item(self, item):
for i in self.session.audio_albums:
if i["title"] == item:
return i["id"]
return None

View File

@@ -1,6 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys
import fix_requests import fix_requests
import fix_win32com
def setup(): def setup():
fix_requests.fix() fix_requests.fix()
if hasattr(sys, "frozen"):
fix_win32com.fix()

View File

@@ -0,0 +1,5 @@
import win32com.client
def fix():
if win32com.client.gencache.is_readonly == True:
win32com.client.gencache.is_readonly = False
win32com.client.gencache.Rebuild()

View File

@@ -1,7 +1,7 @@
from pywintypes import com_error from pywintypes import com_error
import win32com import win32com
import paths import paths
win32com.__gen_path__=paths.data_path(u"com_cache") win32com.__gen_path__=paths.com_path()
import sys import sys
import os import os
sys.path.append(os.path.join(win32com.__gen_path__, ".")) sys.path.append(os.path.join(win32com.__gen_path__, "."))
@@ -32,3 +32,9 @@ def load_com(*names):
raise com_error("Unable to load any of the provided com objects.") raise com_error("Unable to load any of the provided com objects.")
return result return result
def preexec():
global fixed
if fixed==False:
gencache._GetModule=patched_getmodule
fixed=True

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logger
import sys import sys
import fixes import fixes
if hasattr(sys, "frozen"): if hasattr(sys, "frozen"):
@@ -9,7 +10,6 @@ import widgetUtils
import paths import paths
import config import config
import output import output
import logger
import logging import logging
import keys import keys
import application import application

View File

@@ -1,28 +1,37 @@
# *- coding: utf-8 -*- # *- coding: utf-8 -*-
import logging as original_logging import logging as original_logging
logging = original_logging.getLogger('core.output') logger = original_logging.getLogger('core.output')
from accessible_output2 import outputs from accessible_output2 import outputs
import sys import sys
speaker = None speaker = None
retries = 0
def speak(text, interrupt=0): def speak(text, interrupt=0):
global speaker global speaker, retries
if not speaker: if not speaker:
setup() setup()
speaker.speak(text, interrupt) try:
speaker.braille(text) speaker.speak(text, interrupt)
except:
if retries < 5:
retries = retries + 1
speak(text)
# speaker.braille(text)
def setup (): def setup ():
global speaker global speaker
logging.debug("Initializing output subsystem.") logger.debug("Initializing output subsystem.")
try: try:
# speaker = speech.Speaker(speech.outputs.Sapi5()) # speaker = speech.Speaker(speech.outputs.Sapi5())
# else: # else:
speaker = outputs.auto.Auto() speaker = outputs.auto.Auto()
except: except:
return logging.exception("Output: Error during initialization.") logger.exception("Output: Error during initialization.")
def enable_sapi():
speaker = outputs.sapi.SAPI5()
def copy(text): def copy(text):
import win32clipboard import win32clipboard

View File

@@ -2,7 +2,7 @@
import platform import platform
import os import os
import sys import sys
import logging #import logging
from platform_utils import paths as paths_ from platform_utils import paths as paths_
from functools import wraps from functools import wraps
@@ -10,7 +10,7 @@ from functools import wraps
mode = "portable" mode = "portable"
directory = None directory = None
log = logging.getLogger("paths") #log = logging.getLogger("paths")
def merge_paths(func): def merge_paths(func):
@wraps(func) @wraps(func)
@@ -31,7 +31,7 @@ def config_path():
elif mode == "installed": elif mode == "installed":
path = data_path("config") path = data_path("config")
if not os.path.exists(path): if not os.path.exists(path):
log.debug("%s path does not exist, creating..." % (path,)) # log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path) os.mkdir(path)
return path return path
@@ -44,7 +44,7 @@ def logs_path():
elif mode == "installed": elif mode == "installed":
path = data_path("logs") path = data_path("logs")
if not os.path.exists(path): if not os.path.exists(path):
log.debug("%s path does not exist, creating..." % (path,)) # log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path) os.mkdir(path)
return path return path
@@ -65,3 +65,16 @@ def locale_path():
@merge_paths @merge_paths
def sound_path(): def sound_path():
return app_path(u"sounds") return app_path(u"sounds")
@merge_paths
def com_path():
global mode, directory
if mode == "portable":
if directory != None: path = os.path.join(directory, "com_cache")
elif directory == None: path = app_path(u"com_cache")
elif mode == "installed":
path = data_path(u"com_cache")
if not os.path.exists(path):
# log.debug("%s path does not exist, creating..." % (path,))
os.mkdir(path)
return path

View File

@@ -8,6 +8,8 @@ import logging
import utils import utils
import sound import sound
from config_utils import Configuration, ConfigurationResetException from config_utils import Configuration, ConfigurationResetException
from pubsub import pub
log = logging.getLogger("session") log = logging.getLogger("session")
sessions = {} sessions = {}
@@ -17,15 +19,6 @@ sessions = {}
# I've added the Date identifier (this is a field in unix time format), for special objects (like friendship indicators) because these objects doesn't have an own identifier. # I've added the Date identifier (this is a field in unix time format), for special objects (like friendship indicators) because these objects doesn't have an own identifier.
identifiers = ["aid", "gid", "uid", "pid", "id", "post_id", "nid", "date"] identifiers = ["aid", "gid", "uid", "pid", "id", "post_id", "nid", "date"]
platforms = {1: _(u"Movile application"),
2: _(u"iPhone"),
3: _(u"iPad"),
4: _(u"Android"),
5: _(u"Windows phone"),
6: _(u"Windows 8"),
7: _(u"Web or desktop app")
}
def find_item(list, item): def find_item(list, item):
""" Finds an item in a list by taking an identifier""" """ Finds an item in a list by taking an identifier"""
# determines the kind of identifier that we are using # determines the kind of identifier that we are using
@@ -52,9 +45,9 @@ def add_attachment(attachment):
elif attachment["type"] == "photo": elif attachment["type"] == "photo":
msg = attachment["photo"]["text"] msg = attachment["photo"]["text"]
if msg == "": if msg == "":
return "photo with no description available" return _(u"photo with no description available")
elif attachment["type"] == "video": elif attachment["type"] == "video":
msg = u"video: {0}".format(attachment["video"]["title"],) msg = _(u"video: {0}").format(attachment["video"]["title"],)
return msg return msg
def add_text(status): def add_text(status):
@@ -71,14 +64,17 @@ def add_text(status):
return message return message
def compose_person(status, session): def compose_person(status, session):
global platforms if status.has_key("last_seen"):
original_date = arrow.get(status["last_seen"]["time"]) original_date = arrow.get(status["last_seen"]["time"])
last_seen = _(u"{0} from {1}").format(original_date.humanize(locale=languageHandler.getLanguage()), platforms[status["last_seen"]["platform"]]) # Translators: This is the date of last seen
last_seen = _(u"{0}").format(original_date.humanize(locale=languageHandler.getLanguage()),)
elif status.has_key("last_seen") == False and status.has_key("deactivated"):
last_seen = _(u"Account deactivated")
return [u"{0} {1}".format(status["first_name"], status["last_name"]), last_seen] return [u"{0} {1}".format(status["first_name"], status["last_name"]), last_seen]
def compose_new(status, session): def compose_new(status, session):
""" This method is used to compose an item of the news feed.""" """ This method is used to compose an item of the news feed."""
user = session.get_user_name(status["source_id"]) user = session.get_user_name(status["source_id"], case_name="nom")
if status.has_key("copy_history"): if status.has_key("copy_history"):
user = _(u"{0} has shared the {1}'s post").format(user, session.get_user_name(status["copy_history"][0]["owner_id"])) user = _(u"{0} has shared the {1}'s post").format(user, session.get_user_name(status["copy_history"][0]["owner_id"]))
message = "" message = ""
@@ -91,6 +87,8 @@ def compose_new(status, session):
if message == "": if message == "":
message = "no description available" message = "no description available"
elif status["type"] == "audio": elif status["type"] == "audio":
# removes deleted audios.
status["audio"] = clean_audio(status["audio"])
if status["audio"]["count"] == 1: if status["audio"]["count"] == 1:
message = _(u"{0} has added an audio: {1}").format(user, u", ".join(compose_audio(status["audio"]["items"][0], session)),) message = _(u"{0} has added an audio: {1}").format(user, u", ".join(compose_audio(status["audio"]["items"][0], session)),)
else: else:
@@ -102,7 +100,7 @@ def compose_new(status, session):
elif status["type"] == "friend": elif status["type"] == "friend":
msg_users = u"" msg_users = u""
for i in status["friends"]["items"]: for i in status["friends"]["items"]:
msg_users = msg_users + u"{0}, ".format(session.get_user_name(i["user_id"])) msg_users = msg_users + u"{0}, ".format(session.get_user_name(i["user_id"], "nom"))
message = _(u"{0} hadded friends: {1}").format(user, msg_users) message = _(u"{0} hadded friends: {1}").format(user, msg_users)
elif status["type"] == "video": elif status["type"] == "video":
if status["video"]["count"] == 1: if status["video"]["count"] == 1:
@@ -117,15 +115,22 @@ def compose_new(status, session):
if status["type"] != "post": print status if status["type"] != "post": print status
return [user, message, created_at] return [user, message, created_at]
def clean_audio(audio):
for i in audio["items"][:]:
if type(i) == bool:
audio["items"].remove(i)
audio["count"] = audio["count"] -1
return audio
def compose_message(message, session): def compose_message(message, session):
user = session.get_user_name(message["from_id"]) user = session.get_user_name(message["from_id"], "nom")
original_date = arrow.get(message["date"]) original_date = arrow.get(message["date"])
created_at = original_date.format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage()) created_at = original_date.format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage())
body = message["body"] body = message["body"]
return [u"{2}, {0} {1}".format(body, created_at, user)] return [u"{2}, {0} {1}".format(body, created_at, user)]
def compose_status(status, session): def compose_status(status, session):
user = session.get_user_name(status["from_id"]) user = session.get_user_name(status["from_id"], "nom")
if status.has_key("copy_history"): if status.has_key("copy_history"):
user = _(u"{0} has shared the {1}'s post").format(user, session.get_user_name(status["copy_history"][0]["owner_id"])) user = _(u"{0} has shared the {1}'s post").format(user, session.get_user_name(status["copy_history"][0]["owner_id"]))
message = "" message = ""
@@ -220,9 +225,15 @@ class vkSession(object):
self.get_my_data() self.get_my_data()
def authorise(self): def authorise(self):
self.vk.login(self.settings["vk"]["user"], self.settings["vk"]["password"]) try:
self.settings["vk"]["token"] = self.vk.client._session.access_token self.vk.login(self.settings["vk"]["user"], self.settings["vk"]["password"])
self.settings.write() self.settings["vk"]["token"] = self.vk.client._session.access_token
self.settings.write()
except:
self.settings["vk"]["user"] = ""
self.settings["vk"]["password"] = ""
self.settings.write()
pub.sendMessage("authorisation-failed")
def post_wall_status(self, message, *args, **kwargs): def post_wall_status(self, message, *args, **kwargs):
""" Sends a post to an user, group or community wall.""" """ Sends a post to an user, group or community wall."""
@@ -258,9 +269,11 @@ class vkSession(object):
if data != None: if data != None:
if type(data) == dict: if type(data) == dict:
num = self.order_buffer(name, data["items"], show_nextpage) num = self.order_buffer(name, data["items"], show_nextpage)
if data["items"][0].has_key("first_name"): if len(data["items"]) > 0 and data["items"][0].has_key("first_name"):
data2 = {"profiles": [], "groups": []}
for i in data["items"]: for i in data["items"]:
self.db["users"][i["id"]] = u"{0} {1}".format(i["first_name"], i["last_name"]) data2["profiles"].append(i)
self.process_usernames(data2)
if data.has_key("profiles") and data.has_key("groups"): if data.has_key("profiles") and data.has_key("groups"):
self.process_usernames(data) self.process_usernames(data)
else: else:
@@ -273,15 +286,18 @@ class vkSession(object):
num = self.order_buffer(name, data["items"], False) num = self.order_buffer(name, data["items"], False)
return num return num
def get_user_name(self, user_id): def get_user_name(self, user_id, case_name="gen"):
if user_id > 0: if user_id > 0:
if self.db["users"].has_key(user_id): if self.db["users"].has_key(user_id):
return self.db["users"][user_id] if self.db["users"][user_id].has_key(case_name):
return self.db["users"][user_id][case_name]
else:
return self.db["users"][user_id]["nom"]
else: else:
return "no specified user" return "no specified user"
else: else:
if self.db["groups"].has_key(abs(user_id)): if self.db["groups"].has_key(abs(user_id)):
return self.db["groups"][abs(user_id)] return self.db["groups"][abs(user_id)]["nom"]
else: else:
return "no specified community" return "no specified community"
@@ -297,14 +313,34 @@ class vkSession(object):
self.db["groups"][i["id"]] = i["name"] self.db["groups"][i["id"]] = i["name"]
def process_usernames(self, data): def process_usernames(self, data):
""" processes user IDS and saves them in a local storage system.
Every function wich needs to convert from an ID to user or community name will have to call the get_user_name function in this session object.
Every function that needs to save a set ot user ids for a future use needs to pass a data dictionary with a profiles key being a list of user objects.
For russian, it gets the genitive case of every name for future use."""
log.debug("Adding usernames to the local database...") log.debug("Adding usernames to the local database...")
ids = ""
for i in data["profiles"]: for i in data["profiles"]:
self.db["users"][i["id"]] = u"{0} {1}".format(i["first_name"], i["last_name"]) if self.db["users"].has_key(i["id"]) == False:
self.db["users"][i["id"]] = dict(nom=u"{0} {1}".format(i["first_name"], i["last_name"]))
ids = ids + "{0},".format(i["id"],)
gids = ""
for i in data["groups"]: for i in data["groups"]:
self.db["groups"][i["id"]] = i["name"] self.db["groups"][i["id"]] = dict(nom=i["name"])
gids = "{0},".format(i["id"],)
if not "ru" in languageHandler.getLanguage():
return
if ids != "":
users_genitive = self.vk.client.users.get(user_ids=ids, fields="first_name, last_name", name_case="gen")
users_instrumental = self.vk.client.users.get(user_ids=ids, fields="first_name, last_name", name_case="ins")
for i in users_genitive:
if self.db["users"].has_key(i["id"]):
self.db["users"][i["id"]]["gen"] = u"{0} {1}".format(i["first_name"], i["last_name"])
for i in users_instrumental:
if self.db["users"].has_key(i["id"]):
self.db["users"][i["id"]]["ins"] = u"{0} {1}".format(i["first_name"], i["last_name"])
def get_my_data(self): def get_my_data(self):
log.debug("Getting user identifier...") log.debug("Getting user identifier...")
user = self.vk.client.users.get(fields="uid, first_name, last_name") user = self.vk.client.users.get(fields="uid, first_name, last_name")
self.user_id = user[0]["id"] self.user_id = user[0]["id"]
self.db["users"][self.user_id] = u"{0} {1}".format(user[0]["first_name"], user[0]["last_name"]) # self.db["users"][self.user_id] = u"{0} {1}".format(user[0]["first_name"], user[0]["last_name"])

View File

@@ -28,10 +28,11 @@ class sessionManagerController(object):
strconfig = "%s/session.conf" % (paths.config_path(i)) strconfig = "%s/session.conf" % (paths.config_path(i))
config_test = Configuration(strconfig) config_test = Configuration(strconfig)
name = config_test["vk"]["user"] name = config_test["vk"]["user"]
self.session = i if name != "" and config_test["vk"]["password"] != "":
s = session.vkSession(self.session) self.session = i
s.get_configuration() s = session.vkSession(self.session)
session.sessions[self.session] = s s.get_configuration()
session.sessions[self.session] = s
def manage_new_account(self): def manage_new_account(self):
if view.new_account_dialog() == widgetUtils.YES: if view.new_account_dialog() == widgetUtils.YES:

View File

@@ -8,7 +8,7 @@ class vkObject(object):
def __init__(self): def __init__(self):
self.api_key = keys.keyring.get_api_key() self.api_key = keys.keyring.get_api_key()
self.api_version = 5.45 self.api_version = 5.52
log.debug("Created vkSession using VK API Version %s" % (self.api_version,)) log.debug("Created vkSession using VK API Version %s" % (self.api_version,))
def login(self, user, password): def login(self, user, password):

View File

@@ -23,6 +23,7 @@ class newSessionDialog(widgetUtils.BaseDialog):
sizer.Add(b1, 0, wx.ALL, 5) sizer.Add(b1, 0, wx.ALL, 5)
sizer.Add(b2, 0, wx.ALL, 5) sizer.Add(b2, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK) ok = wx.Button(panel, wx.ID_OK)
ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL) cancel = wx.Button(panel, wx.ID_CANCEL)
btnb = wx.BoxSizer(wx.HORIZONTAL) btnb = wx.BoxSizer(wx.HORIZONTAL)
btnb.Add(ok, 0, wx.ALL, 5) btnb.Add(ok, 0, wx.ALL, 5)

View File

@@ -141,7 +141,7 @@ class list(object):
self.list.SetColumnWidth(column, characters_max*2) self.list.SetColumnWidth(column, characters_max*2)
def set_size(self): def set_size(self):
self.list.SetSize((self.list.GetBestSize()[0], 728)) self.list.SetSize((self.list.GetBestSize()[0], 1000))
def create_list(self, parent): def create_list(self, parent):
self.list = wx.ListCtrl(parent, -1, **self.listArguments) self.list = wx.ListCtrl(parent, -1, **self.listArguments)

View File

@@ -21,3 +21,9 @@ def show_error_code(code):
title = _(u"Restricted access") title = _(u"Restricted access")
message = _(u"Access to user's audio is denied by the owner. Error code {0}").format(code,) message = _(u"Access to user's audio is denied by the owner. Error code {0}").format(code,)
return wx.MessageDialog(None, message, title, style=wx.ICON_ERROR).ShowModal() return wx.MessageDialog(None, message, title, style=wx.ICON_ERROR).ShowModal()
def bad_authorisation():
return wx.MessageDialog(None, _(u"authorisation failed. Your configuration will not be saved. Please close and open again the application for authorising your account. Make sure you have typed your credentials correctly."), _(u"Error"), style=wx.ICON_ERROR).ShowModal()
def delete_audio_album():
return wx.MessageDialog(None, _(u"Do you really want to delete this Album? this will be deleted from VK too."), _(u"Attention"), style=wx.ICON_QUESTION|wx.YES_NO).ShowModal()

View File

@@ -0,0 +1,24 @@
import wx
import widgetUtils
class audio_album(widgetUtils.BaseDialog):
def __init__(self, *args, **kwargs):
super(audio_album, self).__init__(title=_(u"Create a new album"), parent=None)
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
lbl = wx.StaticText(panel, wx.NewId(), _(u"Album title"))
self.title = wx.TextCtrl(panel, wx.NewId())
box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(lbl, 1, wx.ALL, 5)
box.Add(self.title, 1, wx.ALL, 5)
sizer.Add(box, 1, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK, _(u"&OK"))
ok.SetDefault()
cancel = wx.Button(panel, wx.ID_CANCEL, _(u"&Close"))
btnsizer = wx.BoxSizer()
btnsizer.Add(ok, 0, wx.ALL, 5)
btnsizer.Add(cancel, 0, wx.ALL, 5)
sizer.Add(btnsizer, 0, wx.ALL, 5)
panel.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())

View File

@@ -2,8 +2,8 @@
import wx import wx
class selectAlbum(wx.Dialog): class selectAlbum(wx.Dialog):
def __init__(self, albums): def __init__(self, title, albums):
super(selectAlbum, self).__init__(parent=None, title=_(u"Select the album where you will upload the photo")) super(selectAlbum, self).__init__(parent=None, title=title)
panel = wx.Panel(self) panel = wx.Panel(self)
self.lista = wx.ListBox(panel, -1, choices=albums) self.lista = wx.ListBox(panel, -1, choices=albums)
self.lista.SetFocus() self.lista.SetFocus()

View File

@@ -16,10 +16,12 @@ class timelineDialog(widgetUtils.BaseDialog):
userSizer.Add(self.cb, 0, wx.ALL, 5) userSizer.Add(self.cb, 0, wx.ALL, 5)
actionsstatic = wx.StaticBox(panel, label=_(u"Buffer type")) actionsstatic = wx.StaticBox(panel, label=_(u"Buffer type"))
self.wall = wx.RadioButton(panel, wx.NewId(), _(u"&Wall posts"), style=wx.RB_GROUP) self.wall = wx.RadioButton(panel, wx.NewId(), _(u"&Wall posts"), style=wx.RB_GROUP)
self.audio = wx.RadioButton(panel, wx.NewId(), _(u"&Audio")) self.audio = wx.RadioButton(panel, wx.NewId(), _(u"Audio"))
self.friends = wx.RadioButton(panel, wx.NewId(), _(u"Friends"))
radioSizer = wx.StaticBoxSizer(actionsstatic, wx.HORIZONTAL) radioSizer = wx.StaticBoxSizer(actionsstatic, wx.HORIZONTAL)
radioSizer.Add(self.wall, 0, wx.ALL, 5) radioSizer.Add(self.wall, 0, wx.ALL, 5)
radioSizer.Add(self.audio, 0, wx.ALL, 5) radioSizer.Add(self.audio, 0, wx.ALL, 5)
radioSizer.Add(self.friends, 0, wx.ALL, 5)
sizer.Add(radioSizer, 0, wx.ALL, 5) sizer.Add(radioSizer, 0, wx.ALL, 5)
ok = wx.Button(panel, wx.ID_OK, _(u"&OK")) ok = wx.Button(panel, wx.ID_OK, _(u"&OK"))
ok.SetDefault() ok.SetDefault()
@@ -39,3 +41,5 @@ class timelineDialog(widgetUtils.BaseDialog):
return "audio" return "audio"
elif self.wall.GetValue() == True: elif self.wall.GetValue() == True:
return "wall" return "wall"
elif self.friends.GetValue() == True:
return "friends"

View File

@@ -6,12 +6,18 @@ class mainWindow(wx.Frame):
def makeMenu(self): def makeMenu(self):
mb = wx.MenuBar() mb = wx.MenuBar()
app_ = wx.Menu() app_ = wx.Menu()
create = wx.Menu()
self.audio_album = create.Append(wx.NewId(), _(u"Audio album"))
app_.AppendMenu(wx.NewId(), _(u"Create"), create)
delete = wx.Menu()
self.delete_audio_album = delete.Append(wx.NewId(), _(u"Audio album"))
app_.AppendMenu(wx.NewId(), _(u"Delete"), delete)
self.settings_dialog = app_.Append(wx.NewId(), _(u"Preferences")) self.settings_dialog = app_.Append(wx.NewId(), _(u"Preferences"))
buffer = wx.Menu() buffer = wx.Menu()
self.new_buffer = wx.Menu() search = wx.Menu()
self.search_audios = self.new_buffer.Append(wx.NewId(), _(u"Audio")) self.search_audios = search.Append(wx.NewId(), _(u"Audio"))
buffer.AppendMenu(wx.NewId(), _(u"Search"), self.new_buffer)
self.timeline = buffer.Append(wx.NewId(), _(u"&New timeline")) self.timeline = buffer.Append(wx.NewId(), _(u"&New timeline"))
buffer.AppendMenu(wx.NewId(), _(u"Search"), search)
self.update_buffer = buffer.Append(wx.NewId(), _(u"Update current buffer")) self.update_buffer = buffer.Append(wx.NewId(), _(u"Update current buffer"))
self.load_previous_items = buffer.Append(wx.NewId(), _(u"Load previous items")) self.load_previous_items = buffer.Append(wx.NewId(), _(u"Load previous items"))
self.remove_buffer_ = buffer.Append(wx.NewId(), _(u"&Remove buffer")) self.remove_buffer_ = buffer.Append(wx.NewId(), _(u"&Remove buffer"))
@@ -19,6 +25,7 @@ class mainWindow(wx.Frame):
mb.Append(buffer, _(u"Buffer")) mb.Append(buffer, _(u"Buffer"))
help_ = wx.Menu() help_ = wx.Menu()
self.about = help_.Append(wx.NewId(), _(u"About {0}").format(application.name,)) self.about = help_.Append(wx.NewId(), _(u"About {0}").format(application.name,))
self.documentation = help_.Append(wx.NewId(), _(u"Manual"))
self.check_for_updates = help_.Append(wx.NewId(), _(u"Check for updates")) self.check_for_updates = help_.Append(wx.NewId(), _(u"Check for updates"))
self.changelog = help_.Append(wx.NewId(), _(u"Chan&gelog")) self.changelog = help_.Append(wx.NewId(), _(u"Chan&gelog"))
mb.Append(help_, _(u"Help")) mb.Append(help_, _(u"Help"))
@@ -26,16 +33,19 @@ class mainWindow(wx.Frame):
def __init__(self): def __init__(self):
super(mainWindow, self).__init__(parent=None, id=wx.NewId(), title=application.name) super(mainWindow, self).__init__(parent=None, id=wx.NewId(), title=application.name)
self.Maximize()
self.makeMenu() self.makeMenu()
self.panel = wx.Panel(self) self.panel = wx.Panel(self)
self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sb = self.CreateStatusBar() self.sb = self.CreateStatusBar()
self.tb = wx.Treebook(self.panel, -1) self.tb = wx.Treebook(self.panel, -1)
self.sizer.Add(self.tb, 0, wx.ALL, 5) self.sizer.Add(self.tb, 1, wx.ALL|wx.EXPAND, 5)
def realize(self): def realize(self):
self.panel.SetSizer(self.sizer) self.panel.SetSizer(self.sizer)
self.SetClientSize(self.sizer.CalcMin()) self.SetClientSize(self.sizer.CalcMin())
self.Layout()
self.SetSize(self.GetBestSize())
def change_status(self, status): def change_status(self, status):
self.sb.SetStatusText(status) self.sb.SetStatusText(status)

View File

@@ -8,13 +8,14 @@ class postMenu(wx.Menu):
self.AppendItem(self.open) self.AppendItem(self.open)
self.like = wx.MenuItem(self, wx.NewId(), _(u"Like")) self.like = wx.MenuItem(self, wx.NewId(), _(u"Like"))
self.AppendItem(self.like) self.AppendItem(self.like)
self.unlike = wx.MenuItem(self, wx.NewId(), _(u"Unlike")) self.dislike = wx.MenuItem(self, wx.NewId(), _(u"Dislike"))
self.AppendItem(self.unlike) self.dislike.Enable(False)
self.AppendItem(self.dislike)
self.comment = wx.MenuItem(self, wx.NewId(), _(u"Add comment")) self.comment = wx.MenuItem(self, wx.NewId(), _(u"Add comment"))
self.AppendItem(self.comment) self.AppendItem(self.comment)
self.post_in_wall = self.Append(wx.NewId(), _(u"Post to this profile")) self.post_in_wall = wx.MenuItem(self, wx.NewId(), _(u"Post to this profile"))
self.AppendItem(self.post_in_wall)
self.post_in_wall.Enable(False) self.post_in_wall.Enable(False)
self.AppendItem(self.post_in_wall)
def create_specific_post_options(self): def create_specific_post_options(self):
self.update = wx.MenuItem(self, wx.NewId(), _(u"Update")) self.update = wx.MenuItem(self, wx.NewId(), _(u"Update"))
@@ -22,6 +23,30 @@ class postMenu(wx.Menu):
self.delete = wx.MenuItem(self, wx.NewId(), _(u"Delete")) self.delete = wx.MenuItem(self, wx.NewId(), _(u"Delete"))
self.AppendItem(self.delete) self.AppendItem(self.delete)
class audioMenu(wx.Menu):
def __init__(self, *args, **kwargs):
super(audioMenu, self).__init__(*args, **kwargs)
self.open = wx.MenuItem(self, wx.NewId(), _(u"&Open"))
self.AppendItem(self.open)
self.play = wx.MenuItem(self, wx.NewId(), _(u"&Play"))
self.AppendItem(self.play)
self.library = wx.MenuItem(self, wx.NewId(), _(u"&Add to library"))
self.AppendItem(self.library)
self.move = wx.MenuItem(self, wx.NewId(), _(u"Move to album"))
self.AppendItem(self.move)
class peopleMenu(wx.Menu):
def __init__(self, *args, **kwargs):
super(peopleMenu, self).__init__(*args, **kwargs)
self.view_profile = wx.MenuItem(self, wx.NewId(), _(u"View profile"))
self.AppendItem(self.view_profile)
self.message = wx.MenuItem(self, wx.NewId(), _(u"Send a message"))
self.AppendItem(self.message)
self.timeline = wx.MenuItem(self, wx.NewId(), _(u"Open timeline"))
self.AppendItem(self.timeline)
self.view_profile.Enable(False)
class commentMenu(wx.Menu): class commentMenu(wx.Menu):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(commentMenu, self).__init__(*args, **kwargs) super(commentMenu, self).__init__(*args, **kwargs)
@@ -41,20 +66,3 @@ class notificationsMenu(wx.Menu):
super(notificationsMenu, self).__init__() super(notificationsMenu, self).__init__()
self.mark_as_read = wx.MenuItem(self, wx.NewId(), _(u"Mark as read")) self.mark_as_read = wx.MenuItem(self, wx.NewId(), _(u"Mark as read"))
self.AppendItem(self.mark_as_read) self.AppendItem(self.mark_as_read)
class toolsMenu(wx.Menu):
def __init__(self, *args, **kwargs):
super(toolsMenu, self).__init__(*args, **kwargs)
self.url = wx.MenuItem(self, -1, _(u"Open URL"))
self.AppendItem(self.url)
# self.url.Enable(False)
self.translate = wx.MenuItem(self, -1, _(u"Translate"))
self.AppendItem(self.translate)
self.CheckSpelling = wx.MenuItem(self, -1, _(u"Check Spelling"))
self.AppendItem(self.CheckSpelling)
class attachMenu(wx.Menu):
def __init__(self):
super(attachMenu, self).__init__()
self.photo = wx.MenuItem(self, wx.NewId(), _(u"Picture"))
self.AppendItem(self.photo)

View File

@@ -8,9 +8,9 @@ class homeTab(wx.Panel):
def create_list(self): def create_list(self):
self.lbl = wx.StaticText(self, wx.NewId(), _(u"Po&sts")) self.lbl = wx.StaticText(self, wx.NewId(), _(u"Po&sts"))
self.list = widgetUtils.list(self, *[_(u"User"), _(u"Text"), _(u"Date")], style=wx.LC_REPORT) self.list = widgetUtils.list(self, *[_(u"User"), _(u"Text"), _(u"Date")], style=wx.LC_REPORT)
self.list.set_windows_size(0, 80) self.list.set_windows_size(0, 200)
self.list.set_windows_size(1, 190) self.list.set_windows_size(1, 300)
self.list.set_windows_size(2, 40) self.list.set_windows_size(2, 250)
self.list.set_size() self.list.set_size()
self.list.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnKeyDown) self.list.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnKeyDown)
@@ -26,22 +26,26 @@ class homeTab(wx.Panel):
sizer.Add(self.postBox, 0, wx.ALL, 5) sizer.Add(self.postBox, 0, wx.ALL, 5)
self.create_list() self.create_list()
sizer.Add(self.lbl, 0, wx.ALL, 5) sizer.Add(self.lbl, 0, wx.ALL, 5)
sizer.Add(self.list.list, 0, wx.ALL, 5) sizer.Add(self.list.list, 1, wx.EXPAND, 5)
self.SetSizer(sizer) self.SetSizer(sizer)
self.SetClientSize(sizer.CalcMin())
def OnKeyDown(self, ev=None): def OnKeyDown(self, ev=None):
pub.sendMessage("show-current-status", buffer=self.name) pub.sendMessage("show-current-status", buffer=self.name)
ev.Skip() ev.Skip()
def showMenu(self, ev): def showMenu(self, ev):
if self.results.get_count() == 0: return if self.list.get_count() == 0: return
pub.sendMessage("show-menu", position=ev.GetPosition()) pub.sendMessage("show-menu", position=ev.GetPosition())
def showMenuByKey(self, ev): def showMenuByKey(self, ev):
if self.results.get_count() == 0: return if self.list.get_count() == 0: return
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU: if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
pub.sendMessage("show-menu", position=self.results.list.GetPosition()) pub.sendMessage("show-menu", position=self.results.list.GetPosition())
def set_focus_function(self, focus_function):
self.list.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, focus_function)
class feedTab(homeTab): class feedTab(homeTab):
def __init__(self, parent): def __init__(self, parent):
super(feedTab, self).__init__(parent=parent) super(feedTab, self).__init__(parent=parent)
@@ -51,9 +55,9 @@ class audioTab(homeTab):
def create_list(self): def create_list(self):
self.lbl = wx.StaticText(self, wx.NewId(), _(u"Mu&sic")) self.lbl = wx.StaticText(self, wx.NewId(), _(u"Mu&sic"))
self.list = widgetUtils.list(self, *[_(u"Title"), _(u"Artist"), _(u"Duration")], style=wx.LC_REPORT) self.list = widgetUtils.list(self, *[_(u"Title"), _(u"Artist"), _(u"Duration")], style=wx.LC_REPORT)
self.list.set_windows_size(0, 80) self.list.set_windows_size(0, 160)
self.list.set_windows_size(1, 190) self.list.set_windows_size(1, 380)
self.list.set_windows_size(2, 40) self.list.set_windows_size(2, 80)
self.list.set_size() self.list.set_size()
self.list.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnKeyDown) self.list.list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnKeyDown)
@@ -66,6 +70,18 @@ class audioTab(homeTab):
self.postBox.Add(self.play, 0, wx.ALL, 5) self.postBox.Add(self.play, 0, wx.ALL, 5)
self.postBox.Add(self.play_all, 0, wx.ALL, 5) self.postBox.Add(self.play_all, 0, wx.ALL, 5)
class audioAlbumTab(audioTab):
def create_post_buttons(self):
self.load = wx.Button(self, wx.NewId(), _(u"Load album"))
self.post = wx.Button(self, -1, _(u"&Post"))
self.play = wx.Button(self, -1, _(u"P&lay"))
self.play_all = wx.Button(self, -1, _(u"Play &All"))
self.postBox = wx.BoxSizer(wx.HORIZONTAL)
self.postBox.Add(self.post, 0, wx.ALL, 5)
self.postBox.Add(self.play, 0, wx.ALL, 5)
self.postBox.Add(self.play_all, 0, wx.ALL, 5)
class notificationsTab(homeTab): class notificationsTab(homeTab):
def __init__(self, parent): def __init__(self, parent):
super(notificationsTab, self).__init__(parent=parent) super(notificationsTab, self).__init__(parent=parent)
@@ -139,6 +155,9 @@ class chatTab(wx.Panel):
box.Add(self.text, 0, wx.ALL, 5) box.Add(self.text, 0, wx.ALL, 5)
return box return box
def set_focus_function(self, focus_function):
self.list.list.Bind(wx.EVT_LIST_ITEM_FOCUSED, focus_function)
class peopleTab(homeTab): class peopleTab(homeTab):
def create_list(self): def create_list(self):

View File

@@ -1,4 +1,4 @@
{"current_version": "0.13", {"current_version": "0.14",
"description": "Some bugfixes, included a changelog which can be accessed through the help menu.", "description": "Added management for audio albums. Bugfixes. Updated translations. Added a context menu for some items. Unread chats will be opened at startup.",
"downloads": "downloads":
{"Windows32": "https://github.com/manuelcortez/socializer/blob/master/nightly/socializer-nightly-build.zip?raw=true"}} {"Windows32": "https://github.com/manuelcortez/socializer/blob/master/nightly/socializer-nightly-build.zip?raw=true"}}