From 1d2a7de3a5fae080b0457de83000c01e189bcc73 Mon Sep 17 00:00:00 2001 From: Morgan McMillian Date: Mon, 21 Dec 2020 18:18:11 -0800 Subject: [PATCH] wire basic post functions --- README.md | 2 +- src/main.py | 10 +++++ src/widgets.py | 116 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 122 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 55861d8..b60dd09 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ A nut obsessed saber-toothed client for pnut.io - [x] Menu (about, refresh, logout) - [x] Keyboard shortcuts - [x] Avatars -- [ ] Post actions (reply, bookmark, repost, quote, copy, delete) +- [x] Post actions (reply, bookmark, repost, quote, copy, delete) - [ ] Loading indicator - [ ] Load newer posts - [ ] Load older posts diff --git a/src/main.py b/src/main.py index 56b48dd..376c286 100644 --- a/src/main.py +++ b/src/main.py @@ -149,15 +149,19 @@ class Application(Gtk.Application): # TODO: find better icons unified = Timeline('unified') + unified.connect('reply', self.on_reply_post) self.stack.add_titled(unified, "unified", "Timeline") self.stack.child_set_property(unified, "icon-name", "user-home-symbolic") mentions = Timeline('mentions') + mentions.connect('reply', self.on_reply_post) self.stack.add_titled(mentions, "mentions", "Mentions") self.stack.child_set_property(mentions, "icon-name", "goa-panel-symbolic") bookmarks = Timeline('bookmarks') + bookmarks.connect('reply', self.on_reply_post) self.stack.add_titled(bookmarks, "bookmarks", "Bookmarks") self.stack.child_set_property(bookmarks, "icon-name", "user-bookmarks-symbolic") global_tl = Timeline('global') + global_tl.connect('reply', self.on_reply_post) self.stack.add_titled(global_tl, "global", "Global") self.stack.child_set_property(global_tl, "icon-name", "network-workgroup-symbolic") @@ -179,6 +183,12 @@ class Application(Gtk.Application): compose = ComposeWindow() compose.set_transient_for(self.win) + def on_reply_post(self, widget, post_id, text): + compose = ComposeWindow() + compose.set_post(text) + compose.set_reply_to(post_id) + compose.set_transient_for(self.win) + def on_main_popover(self, button): self.main_popover.popup() diff --git a/src/widgets.py b/src/widgets.py index 324b6b6..6be58c5 100644 --- a/src/widgets.py +++ b/src/widgets.py @@ -27,7 +27,7 @@ from dateutil.tz import tzlocal gi.require_version('GdkPixbuf', '2.0') gi.require_version('Gdk', '3.0') gi.require_version('Gtk', '3.0') -from gi.repository import GObject, GdkPixbuf, Gdk, Gtk +from gi.repository import GObject, GdkPixbuf, Gdk, Gtk, Gio gi.require_version('Handy', '1') from gi.repository import Handy @@ -39,6 +39,8 @@ class ComposeWindow(Handy.Window): self.set_default_size(500, 300) self.set_type_hint(Gdk.WindowTypeHint.DIALOG) + self.reply_to = None + box = Gtk.Box(orientation='vertical') header = Handy.HeaderBar(show_close_button=False) @@ -94,11 +96,20 @@ class ComposeWindow(Handy.Window): self.counter = self.max_length - self.buffer.get_char_count() self.counter_label.set_text(str(self.counter)) + def set_post(self, text): + self.buffer.set_text(text, -1) + + def set_reply_to(self, reply_to): + self.reply_to = reply_to + def send_post(self, button): start = self.buffer.get_start_iter() end = self.buffer.get_end_iter() text = self.buffer.get_text(start, end, False) - pnutpy.api.create_post(data={'text': text}) + data = {'text': text} + if self.reply_to is not None: + data['reply_to'] = self.reply_to + pnutpy.api.create_post(data=data) self.close() def cancel_post(self, button): @@ -175,12 +186,15 @@ class LoginPage(Gtk.Box): class Timeline(Gtk.Box): __gsignals__ = { - 'refresh': (GObject.SIGNAL_RUN_FIRST, None, ()) + 'refresh': (GObject.SIGNAL_RUN_FIRST, None, ()), + 'reply': (GObject.SIGNAL_RUN_FIRST, None, (int,str,)) } def __init__(self, stream): super().__init__(orientation='vertical') + self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) + scroller = Gtk.ScrolledWindow( halign='fill', kinetic_scrolling=True @@ -194,6 +208,39 @@ class Timeline(Gtk.Box): self.stream = stream self.load_timeline() + self.view.connect('button-press-event', self.on_button_pressed) + + action_group = Gio.SimpleActionGroup() + + action = Gio.SimpleAction.new('reply', None) + action.connect('activate', self.on_reply) + action_group.add_action(action) + + action = Gio.SimpleAction.new('replyall', None) + action.connect('activate', self.on_reply_all) + action_group.add_action(action) + + action = Gio.SimpleAction.new('bookmark', None) + action.connect('activate', self.on_bookmark) + action_group.add_action(action) + + action = Gio.SimpleAction.new('repost', None) + action.connect('activate', self.on_repost) + action_group.add_action(action) + + action = Gio.SimpleAction.new('quote', None) + action.connect('activate', self.on_quote) + action_group.add_action(action) + + action = Gio.SimpleAction.new('copy', None) + action.connect('activate', self.on_copy) + action_group.add_action(action) + + self.insert_action_group('win', action_group) + + builder = Gtk.Builder.new_from_resource("/dev/thrrgilag/squeak/menu.ui") + self.menu = builder.get_object("post-menu") + def load_timeline(self): if self.stream == 'unified': posts, meta = pnutpy.api.users_post_streams_unified(include_raw=1) @@ -207,7 +254,9 @@ class Timeline(Gtk.Box): for item in posts: if 'is_deleted' in item: continue - self.view.add(PostItem(item)) + postitem = PostItem(item) + postitem.connect('menu-pressed', self.show_menu) + self.view.add(postitem) def do_refresh(self): rows = self.view.get_children() @@ -216,8 +265,55 @@ class Timeline(Gtk.Box): self.load_timeline() self.show_all() + def on_button_pressed(self, widget, event): + logging.debug("-blarp-") + if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3: + logging.debug("-blarp- right button") + + def show_menu(self, widget, index): + self.post_index = index + self.post_data = widget.post + popover = Gtk.Popover() + popover.set_position(Gtk.PositionType.BOTTOM) + popover.set_relative_to(widget.menu_button) + popover.bind_model(self.menu, None) + popover.popup() + + def on_reply(self, action, param): + replyuser = "@" + self.post_data.user.username + " " + self.emit('reply', self.post_data.id, replyuser) + + def on_reply_all(self, action, param): + replyuser = "@" + self.post_data.user.username + " " + self.emit('reply', self.post_data.id, replyuser) + + def on_bookmark(self, action, param): + if self.post_data.you_bookmarked: + pnutpy.api.unbookmark_post(self.post_data.id) + else: + pnutpy.api.bookmark_post(self.post_data.id) + + def on_repost(self, action, param): + if self.post_data.you_bookmarked: + pnutpy.api.unrepost_post(self.post_data.id) + else: + pnutpy.api.repost_post(self.post_data.id) + + def on_quote(self, action, param): + quote = " >> @" + self.post_data.user.username + ": " + quote += self.post_data.content.text + logging.debug(quote) + self.emit('reply', self.post_data.id, quote) + + def on_copy(self, action, param): + self.clipboard.set_text(self.post_data.content.text, -1) + class PostItem(Gtk.ListBoxRow): + __gsignals__ = { + 'menu-pressed': (GObject.SIGNAL_RUN_FIRST, None, (int,)) + } + def __init__(self, post): super(Gtk.ListBoxRow, self).__init__() self.post = post @@ -225,6 +321,10 @@ class PostItem(Gtk.ListBoxRow): self.box = Gtk.Box(orientation='vertical') self.add(self.box) + # post menu + self.menu_button = Gtk.Button.new_from_icon_name('view-more-symbolic', 1) + self.menu_button.connect('clicked', self.show_menu) + # name container self.name_box = Gtk.Box(orientation='vertical') self.username = Gtk.Label(label="@" + post.user.username, xalign=0) @@ -265,11 +365,14 @@ class PostItem(Gtk.ListBoxRow): # footer container self.f_box = Gtk.Box(orientation='horizontal') + self.f_box.pack_end(self.menu_button, False, False, 10) + + # datetime post_date_local = post.created_at.astimezone(tzlocal()) datetime_label = Gtk.Label(label=post_date_local.strftime("%Y-%m-%d %H:%M"), xalign=1) self.f_box.pack_end(datetime_label, False, False, 10) pad = Gtk.Label(label="") - self.f_box.pack_start(pad, False, False, 10) + self.f_box.pack_start(pad, False, False, 5) if post.id != int(post.thread_id): thread_icon = Gtk.Image.new_from_icon_name("user-available-symbolic", Gtk.IconSize.SMALL_TOOLBAR) @@ -315,3 +418,6 @@ class PostItem(Gtk.ListBoxRow): pixbuf = loader.get_pixbuf() return pixbuf.scale_simple(256,new_height,GdkPixbuf.InterpType.BILINEAR) + def show_menu(self, widget): + self.emit('menu-pressed', self.get_index()) +