Threaded adding/removing friends, and made it a little more robust. Still buggy, but it always was.
This commit is contained in:
parent
5c642bd479
commit
e4ff126d12
2
TODO
2
TODO
|
@ -2,13 +2,13 @@ This is a list of things that still need doing. It includes short-, medium-, an
|
||||||
|
|
||||||
features:
|
features:
|
||||||
|
|
||||||
* Make all API calls threaded
|
|
||||||
* Make the buttons prettier
|
* Make the buttons prettier
|
||||||
* Add a graphical options menu
|
* Add a graphical options menu
|
||||||
* Come up with a better bloody name
|
* Come up with a better bloody name
|
||||||
* Status bar icon
|
* Status bar icon
|
||||||
* Support viewing a list of friends and unfollowing them
|
* Support viewing a list of friends and unfollowing them
|
||||||
* Support creating new lists and adding users to it (as well as removing users and deleting lists)
|
* Support creating new lists and adding users to it (as well as removing users and deleting lists)
|
||||||
|
* Changing the active user needs to be more 'work'... for instance, user tabs need to be re-checked for followship...
|
||||||
|
|
||||||
|
|
||||||
bugs:
|
bugs:
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import re
|
import re
|
||||||
import gtk, gobject
|
import gtk, gobject
|
||||||
from threading import Thread,RLock
|
from threading import Thread,RLock
|
||||||
|
import twitter_pb2
|
||||||
from twitter import Api
|
from twitter import Api
|
||||||
from urllib2 import HTTPError,URLError
|
from urllib2 import HTTPError,URLError
|
||||||
import avcache
|
import avcache
|
||||||
|
@ -304,6 +305,46 @@ class PostRetweet(ApiThread):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeFriendship(ApiThread):
|
||||||
|
def __init__(self, api, pane, user_name, follow=True):
|
||||||
|
ApiThread.__init__(self, api)
|
||||||
|
self.sig_proxy = SigProxy()
|
||||||
|
self.user_name = user_name
|
||||||
|
self.follow = follow
|
||||||
|
self.pane = pane
|
||||||
|
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
with self.api.lock:
|
||||||
|
if self.follow:
|
||||||
|
user = self.api.CreateFriendship(self.user_name)
|
||||||
|
else:
|
||||||
|
user = self.api.DestroyFriendship(self.user_name)
|
||||||
|
|
||||||
|
if user.__class__ == twitter_pb2.User:
|
||||||
|
success = True
|
||||||
|
else:
|
||||||
|
success = False
|
||||||
|
|
||||||
|
except (HTTPError, URLError):
|
||||||
|
success = False
|
||||||
|
|
||||||
|
gtk.gdk.threads_enter()
|
||||||
|
try:
|
||||||
|
if self.follow:
|
||||||
|
self.pane.set_following(success)
|
||||||
|
else:
|
||||||
|
self.pane.set_following(not success)
|
||||||
|
finally:
|
||||||
|
gtk.gdk.threads_leave()
|
||||||
|
|
||||||
|
self.sig_proxy.emit('friendship-changed', {'user_name': self.user_name, 'follow': self.follow, 'success': success})
|
||||||
|
|
||||||
|
### End class ChangeFriendship
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SigProxy(gtk.Alignment):
|
class SigProxy(gtk.Alignment):
|
||||||
"""
|
"""
|
||||||
This little class exists just so that we can have a gtk class in our
|
This little class exists just so that we can have a gtk class in our
|
||||||
|
@ -328,6 +369,10 @@ gobject.signal_new("retweet-posted", SigProxy,
|
||||||
gobject.SIGNAL_RUN_LAST,
|
gobject.SIGNAL_RUN_LAST,
|
||||||
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
|
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
|
||||||
|
|
||||||
|
gobject.signal_new("friendship-changed", SigProxy,
|
||||||
|
gobject.SIGNAL_RUN_LAST,
|
||||||
|
gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
|
||||||
|
|
||||||
|
|
||||||
# We use these classes to emulate a Status object when we need
|
# We use these classes to emulate a Status object when we need
|
||||||
# one to be built out of something else.
|
# one to be built out of something else.
|
||||||
|
|
53
mytwitter.py
53
mytwitter.py
|
@ -40,6 +40,10 @@ class MyTwitter():
|
||||||
config.write(config_filehandle)
|
config.write(config_filehandle)
|
||||||
config_filehandle.close()
|
config_filehandle.close()
|
||||||
|
|
||||||
|
if config.has_option('global', 'debug') and config.get('global', 'debug') == '1':
|
||||||
|
debug = True
|
||||||
|
|
||||||
|
|
||||||
if len(config.sections()) < 2:
|
if len(config.sections()) < 2:
|
||||||
print "Error: You must define at least one [account] section in " + config_file
|
print "Error: You must define at least one [account] section in " + config_file
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@ -175,7 +179,7 @@ class MyTwitter():
|
||||||
|
|
||||||
|
|
||||||
def update_window_callback(self, widget):
|
def update_window_callback(self, widget):
|
||||||
pane = self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page())
|
pane = self.get_current_pane()
|
||||||
self.update_single_window(pane)
|
self.update_single_window(pane)
|
||||||
|
|
||||||
|
|
||||||
|
@ -267,6 +271,10 @@ class MyTwitter():
|
||||||
self.remove_view(name, single_tweet, conversation)
|
self.remove_view(name, single_tweet, conversation)
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_pane(self):
|
||||||
|
return self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page())
|
||||||
|
|
||||||
|
|
||||||
def add_to_notebook(self, name, single_tweet=None, conversation=False):
|
def add_to_notebook(self, name, single_tweet=None, conversation=False):
|
||||||
# If it already exists, don't add it, just switch to it
|
# If it already exists, don't add it, just switch to it
|
||||||
for i in range(self.tweet_notebook.get_n_pages()):
|
for i in range(self.tweet_notebook.get_n_pages()):
|
||||||
|
@ -372,26 +380,29 @@ class MyTwitter():
|
||||||
|
|
||||||
|
|
||||||
def on_following_button_clicked(self, event):
|
def on_following_button_clicked(self, event):
|
||||||
current_pane = self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page())
|
current_pane = self.get_current_pane()
|
||||||
user_name = re.sub('^user: ', '', current_pane.get_list_name())
|
user_name = re.sub('^user: ', '', current_pane.get_list_name())
|
||||||
if current_pane.get_following():
|
if current_pane.get_following():
|
||||||
with self.api.lock:
|
follow = False # destroy the friendship
|
||||||
try:
|
|
||||||
self.api.DestroyFriendship(user_name)
|
|
||||||
except HTTPError,URLError:
|
|
||||||
self.update_status_bar('Failed to unfollow user.')
|
|
||||||
return
|
|
||||||
current_pane.set_following(False)
|
|
||||||
else:
|
else:
|
||||||
with self.api.lock:
|
follow = True
|
||||||
try:
|
|
||||||
self.api.CreateFriendship(user_name)
|
|
||||||
except HTTPError,URLError:
|
|
||||||
self.update_status_bar('Failed to follow user.')
|
|
||||||
return
|
|
||||||
current_pane.set_following(True)
|
|
||||||
|
|
||||||
self.update_follow_button(current_pane)
|
thread = apithreads.ChangeFriendship(self.api, current_pane, user_name, follow)
|
||||||
|
thread.sig_proxy.connect('friendship-changed', self.on_friendship_changed)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
|
||||||
|
def on_friendship_changed(self, widget, data):
|
||||||
|
if data['success']:
|
||||||
|
if data['follow']:
|
||||||
|
self.update_status_bar('Now following ' + data['user_name'])
|
||||||
|
else:
|
||||||
|
self.update_status_bar('No longer following ' + data['user_name'])
|
||||||
|
else: # didn't succeed
|
||||||
|
if data['follow']:
|
||||||
|
self.update_status_bar('Failed to follow ' + data['user_name'])
|
||||||
|
else:
|
||||||
|
self.update_status_bar('Failed to unfollow ' + data['user_name'])
|
||||||
|
|
||||||
|
|
||||||
# pane should be the currently active pane
|
# pane should be the currently active pane
|
||||||
|
@ -423,7 +434,7 @@ class MyTwitter():
|
||||||
|
|
||||||
|
|
||||||
def on_at_button_clicked(self, widget):
|
def on_at_button_clicked(self, widget):
|
||||||
current_pane = self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page())
|
current_pane = self.get_current_pane()
|
||||||
user_name = re.sub('^user: ', '', current_pane.get_list_name())
|
user_name = re.sub('^user: ', '', current_pane.get_list_name())
|
||||||
self.add_to_notebook('@' + user_name)
|
self.add_to_notebook('@' + user_name)
|
||||||
|
|
||||||
|
@ -459,13 +470,13 @@ class MyTwitter():
|
||||||
scrolltype = gtk.SCROLL_END
|
scrolltype = gtk.SCROLL_END
|
||||||
|
|
||||||
if scrolltype:
|
if scrolltype:
|
||||||
self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page()).emit('scroll-child', scrolltype, False)
|
self.get_current_pane().emit('scroll-child', scrolltype, False)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def close_current_tab(self):
|
def close_current_tab(self):
|
||||||
current_pane = self.tweet_notebook.get_nth_page(self.tweet_notebook.get_current_page())
|
current_pane = self.get_current_pane()
|
||||||
self.remove_view(current_pane.get_list_name(), current_pane.get_single_tweet(), current_pane.get_conversation())
|
self.remove_view(current_pane.get_list_name(), current_pane.get_single_tweet(), current_pane.get_conversation())
|
||||||
|
|
||||||
|
|
||||||
|
@ -527,6 +538,8 @@ class MyTwitter():
|
||||||
|
|
||||||
|
|
||||||
# main
|
# main
|
||||||
|
debug = False # global debug variable
|
||||||
|
|
||||||
parser = optparse.OptionParser()
|
parser = optparse.OptionParser()
|
||||||
parser.add_option('-c' ,'--config', dest="filename", default="~/.mytwitter.conf", help="read configuration from FILENAME instead of the default ~/.mytwitter.conf")
|
parser.add_option('-c' ,'--config', dest="filename", default="~/.mytwitter.conf", help="read configuration from FILENAME instead of the default ~/.mytwitter.conf")
|
||||||
parser.add_option('-n' ,'--no-resize', dest="resize", action='store_false', default=True, help="use the default window size instead of the size from the last session")
|
parser.add_option('-n' ,'--no-resize', dest="resize", action='store_false', default=True, help="use the default window size instead of the size from the last session")
|
||||||
|
|
Reference in New Issue
Block a user