2020-11-27 19:52:03 +00:00
|
|
|
# widgets.py
|
|
|
|
#
|
|
|
|
# Copyright 2020 Morgan McMillian
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import gi
|
|
|
|
import os
|
|
|
|
import pnutpy
|
|
|
|
import logging
|
2020-12-17 01:17:05 +00:00
|
|
|
import requests
|
2020-12-28 19:22:54 +00:00
|
|
|
import timeago
|
|
|
|
import datetime
|
2020-11-27 19:52:03 +00:00
|
|
|
|
2020-12-17 05:30:04 +00:00
|
|
|
from dateutil.tz import tzlocal
|
|
|
|
|
2020-12-17 01:17:05 +00:00
|
|
|
gi.require_version('GdkPixbuf', '2.0')
|
2020-11-27 19:52:03 +00:00
|
|
|
gi.require_version('Gdk', '3.0')
|
|
|
|
gi.require_version('Gtk', '3.0')
|
2020-12-27 23:30:00 +00:00
|
|
|
from gi.repository import GObject, GdkPixbuf, Gdk, Gtk, Gio, GLib
|
2020-11-27 19:52:03 +00:00
|
|
|
|
|
|
|
gi.require_version('Handy', '1')
|
|
|
|
from gi.repository import Handy
|
|
|
|
|
2020-11-28 18:00:04 +00:00
|
|
|
class ComposeWindow(Handy.Window):
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__(modal=True)
|
|
|
|
self.set_default_size(500, 300)
|
|
|
|
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
|
|
|
|
|
2020-12-22 02:18:11 +00:00
|
|
|
self.reply_to = None
|
|
|
|
|
2020-11-28 18:00:04 +00:00
|
|
|
box = Gtk.Box(orientation='vertical')
|
|
|
|
header = Handy.HeaderBar(show_close_button=False)
|
|
|
|
|
|
|
|
cancel_button = Gtk.Button(label='Cancel')
|
|
|
|
cancel_button.connect('clicked', self.cancel_post)
|
|
|
|
post_button = Gtk.Button(label='Post')
|
|
|
|
post_button.connect('clicked', self.send_post)
|
|
|
|
|
|
|
|
header.set_title('New Post')
|
|
|
|
header.pack_start(cancel_button)
|
|
|
|
header.pack_end(post_button)
|
|
|
|
|
|
|
|
scroller = Gtk.ScrolledWindow(halign='fill')
|
|
|
|
textarea = Gtk.TextView(
|
|
|
|
left_margin=8,
|
|
|
|
right_margin=8,
|
|
|
|
top_margin=8,
|
|
|
|
bottom_margin=8
|
|
|
|
)
|
|
|
|
textarea.set_wrap_mode(Gtk.WrapMode.WORD)
|
|
|
|
scroller.add(textarea)
|
|
|
|
self.buffer = textarea.get_buffer()
|
|
|
|
|
|
|
|
self.max_length = 256
|
|
|
|
actionbar = Gtk.ActionBar()
|
|
|
|
self.counter_label = Gtk.Label()
|
|
|
|
self.counter_label.set_text(str(self.max_length))
|
|
|
|
actionbar.pack_end(self.counter_label)
|
|
|
|
|
|
|
|
self.buffer.connect('changed', self.validate)
|
|
|
|
|
|
|
|
box.pack_start(header, False, False, 0)
|
|
|
|
box.pack_start(scroller, True, True, 0)
|
|
|
|
box.pack_end(actionbar, False, False, 0)
|
|
|
|
self.add(box)
|
|
|
|
|
|
|
|
self.show_all()
|
2020-12-16 20:42:34 +00:00
|
|
|
textarea.grab_focus()
|
2020-11-28 18:00:04 +00:00
|
|
|
|
2020-12-16 07:00:45 +00:00
|
|
|
self.connect('key-release-event', self.on_key_release)
|
2020-12-16 20:42:34 +00:00
|
|
|
self.connect('key-press-event', self.on_key_press)
|
|
|
|
|
|
|
|
def on_key_press(self, widget, ev, data=None):
|
|
|
|
ctrl = (ev.state & Gdk.ModifierType.CONTROL_MASK)
|
|
|
|
if ctrl and ev.keyval == Gdk.KEY_Return:
|
|
|
|
self.send_post(None)
|
2020-12-16 07:00:45 +00:00
|
|
|
|
|
|
|
def on_key_release(self, widget, ev, data=None):
|
|
|
|
if ev.keyval == Gdk.KEY_Escape:
|
|
|
|
self.close()
|
|
|
|
|
2020-11-28 18:00:04 +00:00
|
|
|
def validate(self, widget):
|
|
|
|
self.counter = self.max_length - self.buffer.get_char_count()
|
|
|
|
self.counter_label.set_text(str(self.counter))
|
|
|
|
|
2020-12-22 02:18:11 +00:00
|
|
|
def set_post(self, text):
|
|
|
|
self.buffer.set_text(text, -1)
|
|
|
|
|
|
|
|
def set_reply_to(self, reply_to):
|
|
|
|
self.reply_to = reply_to
|
|
|
|
|
2020-11-28 18:00:04 +00:00
|
|
|
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)
|
2020-12-22 02:18:11 +00:00
|
|
|
data = {'text': text}
|
|
|
|
if self.reply_to is not None:
|
|
|
|
data['reply_to'] = self.reply_to
|
|
|
|
pnutpy.api.create_post(data=data)
|
2020-11-28 18:00:04 +00:00
|
|
|
self.close()
|
|
|
|
|
|
|
|
def cancel_post(self, button):
|
|
|
|
self.close()
|
|
|
|
|
2020-11-27 19:52:03 +00:00
|
|
|
class LoginPage(Gtk.Box):
|
|
|
|
|
|
|
|
__gsignals__ = {
|
|
|
|
'login': (GObject.SIGNAL_RUN_FIRST, None, (str,))
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__(orientation='vertical')
|
|
|
|
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
|
|
|
|
|
|
|
client_id = "1PiUzxfX_CQxKvtz93lUzPX9-FMtz-va"
|
|
|
|
redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
|
2021-01-07 02:56:49 +00:00
|
|
|
scope = "basic,stream,write_post,follow,presence,messages:io.pnut.core.chat,messages:io.pnut.core.pm,files:squeak.thrrgilag,polls"
|
2020-11-27 19:52:03 +00:00
|
|
|
|
|
|
|
uri = "https://pnut.io/oauth/authenticate"
|
|
|
|
uri += "?client_id=" + client_id
|
|
|
|
uri += "&redirect_uri=" + redirect_uri
|
|
|
|
uri += "&scope=" + scope
|
|
|
|
uri += "&response_type=token"
|
|
|
|
|
|
|
|
self.login_button = Gtk.LinkButton.new_with_label(uri, "Log In to pnut.io")
|
|
|
|
self.login_button.connect("clicked", self.prompt_code)
|
|
|
|
|
|
|
|
self.set_center_widget(self.login_button)
|
|
|
|
|
|
|
|
def prompt_code(self, button):
|
|
|
|
self.remove(self.login_button)
|
|
|
|
|
|
|
|
label = Gtk.Label()
|
|
|
|
label.set_markup('<span font="20">Enter authorization code</span>')
|
|
|
|
self.code = Gtk.Entry()
|
|
|
|
|
|
|
|
paste_button = Gtk.Button(label="Paste from clipboard")
|
|
|
|
paste_button.connect("clicked", self.paste_code)
|
|
|
|
|
|
|
|
cancel_button = Gtk.Button(label="Cancel")
|
|
|
|
cancel_button.connect("clicked", self.cancel_login)
|
|
|
|
confirm_button = Gtk.Button(label="Confirm")
|
|
|
|
confirm_button.connect("clicked", self.confirm_login)
|
|
|
|
lbox = Gtk.Box(orientation='horizontal')
|
|
|
|
lbox.pack_start(cancel_button, True, True, 0)
|
|
|
|
lbox.pack_start(confirm_button, True, True, 0)
|
|
|
|
|
|
|
|
vbox = Gtk.Box(orientation='vertical')
|
|
|
|
vbox.pack_start(label, False, False, 10)
|
|
|
|
vbox.pack_start(self.code, False, False, 10)
|
|
|
|
vbox.pack_start(paste_button, False, False, 10)
|
|
|
|
vbox.add(lbox)
|
|
|
|
|
|
|
|
hbox = Gtk.Box(orientation='horizontal')
|
|
|
|
hbox.set_center_widget(vbox)
|
|
|
|
|
|
|
|
self.set_center_widget(hbox)
|
|
|
|
self.show_all()
|
|
|
|
|
|
|
|
def paste_code(self, button):
|
|
|
|
text = self.clipboard.wait_for_text()
|
|
|
|
if text is not None:
|
|
|
|
self.code.set_text(text)
|
|
|
|
|
|
|
|
def cancel_login(self, button):
|
|
|
|
# TODO: something actually useful here
|
|
|
|
logging.debug("uh cancel i guess")
|
|
|
|
|
|
|
|
def confirm_login(self, button):
|
|
|
|
code = self.code.get_text()
|
|
|
|
self.emit('login', code)
|
|
|
|
|
|
|
|
class Timeline(Gtk.Box):
|
|
|
|
|
|
|
|
__gsignals__ = {
|
2020-12-22 02:18:11 +00:00
|
|
|
'refresh': (GObject.SIGNAL_RUN_FIRST, None, ()),
|
2020-12-23 01:02:31 +00:00
|
|
|
'top': (GObject.SIGNAL_RUN_FIRST, None, ()),
|
2020-12-22 02:18:11 +00:00
|
|
|
'reply': (GObject.SIGNAL_RUN_FIRST, None, (int,str,))
|
2020-11-27 19:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, stream):
|
|
|
|
super().__init__(orientation='vertical')
|
|
|
|
|
2020-12-22 02:18:11 +00:00
|
|
|
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
2020-12-23 00:32:32 +00:00
|
|
|
self.max_id = 0
|
|
|
|
self.min_id = 0
|
2020-12-22 02:18:11 +00:00
|
|
|
|
2020-12-23 01:02:31 +00:00
|
|
|
self.scroller = Gtk.ScrolledWindow(
|
2020-11-27 19:52:03 +00:00
|
|
|
halign='fill',
|
|
|
|
kinetic_scrolling=True
|
|
|
|
)
|
|
|
|
self.view = Gtk.ListBox(
|
|
|
|
selection_mode=Gtk.SelectionMode.NONE
|
|
|
|
)
|
2020-12-23 01:02:31 +00:00
|
|
|
self.scroller.add(self.view)
|
|
|
|
self.pack_start(self.scroller, True, True, 0)
|
2020-11-27 19:52:03 +00:00
|
|
|
|
|
|
|
self.stream = stream
|
|
|
|
self.load_timeline()
|
|
|
|
|
2020-12-22 02:18:11 +00:00
|
|
|
self.view.connect('button-press-event', self.on_button_pressed)
|
2020-12-23 01:02:31 +00:00
|
|
|
self.scroller.connect('edge-reached', self.on_edge_reached)
|
2020-12-22 02:18:11 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2021-01-01 21:26:29 +00:00
|
|
|
action = Gio.SimpleAction.new('copylink', None)
|
|
|
|
action.connect('activate', self.on_copy_link)
|
|
|
|
action_group.add_action(action)
|
|
|
|
|
|
|
|
action = Gio.SimpleAction.new('openlink', None)
|
|
|
|
action.connect('activate', self.on_open_link)
|
|
|
|
action_group.add_action(action)
|
|
|
|
|
2020-12-22 02:18:11 +00:00
|
|
|
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")
|
|
|
|
|
2020-12-23 00:32:32 +00:00
|
|
|
def load_timeline(self, older=False):
|
|
|
|
params = {
|
2021-01-07 02:56:50 +00:00
|
|
|
'include_post_raw': 1
|
2020-12-23 00:32:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if older:
|
|
|
|
params['before_id'] = self.min_id
|
|
|
|
|
2020-11-27 19:52:03 +00:00
|
|
|
if self.stream == 'unified':
|
2020-12-23 00:32:32 +00:00
|
|
|
posts, meta = pnutpy.api.users_post_streams_unified(**params)
|
2020-11-27 19:52:03 +00:00
|
|
|
elif self.stream == 'mentions':
|
2020-12-23 00:32:32 +00:00
|
|
|
posts, meta = pnutpy.api.users_mentioned_posts('me', **params)
|
2020-11-27 19:52:03 +00:00
|
|
|
elif self.stream == 'bookmarks':
|
2020-12-23 00:32:32 +00:00
|
|
|
posts, meta = pnutpy.api.users_bookmarked_posts('me', **params)
|
2020-11-27 19:52:03 +00:00
|
|
|
else:
|
2020-12-23 00:32:32 +00:00
|
|
|
posts, meta = pnutpy.api.posts_streams_global(**params)
|
|
|
|
|
|
|
|
self.max_id = meta.max_id
|
|
|
|
self.min_id = meta.min_id
|
2020-11-27 19:52:03 +00:00
|
|
|
|
|
|
|
for item in posts:
|
|
|
|
if 'is_deleted' in item:
|
|
|
|
continue
|
2020-12-22 02:18:11 +00:00
|
|
|
postitem = PostItem(item)
|
|
|
|
postitem.connect('menu-pressed', self.show_menu)
|
|
|
|
self.view.add(postitem)
|
2020-11-27 19:52:03 +00:00
|
|
|
|
2020-12-23 00:32:32 +00:00
|
|
|
self.show_all()
|
|
|
|
|
2020-11-27 19:52:03 +00:00
|
|
|
def do_refresh(self):
|
2020-12-23 01:02:31 +00:00
|
|
|
self.do_top()
|
2020-11-27 19:52:03 +00:00
|
|
|
rows = self.view.get_children()
|
|
|
|
for item in rows:
|
|
|
|
self.view.remove(item)
|
|
|
|
self.load_timeline()
|
|
|
|
self.show_all()
|
|
|
|
|
2020-12-23 01:02:31 +00:00
|
|
|
def do_top(self):
|
|
|
|
vadjustment = self.scroller.get_vadjustment()
|
|
|
|
vadjustment.set_value(0)
|
|
|
|
|
2020-12-23 00:32:32 +00:00
|
|
|
def on_edge_reached(self, widget, pos):
|
|
|
|
if pos == Gtk.PositionType.BOTTOM:
|
|
|
|
self.load_timeline(True)
|
|
|
|
|
2020-12-22 02:18:11 +00:00
|
|
|
def on_button_pressed(self, widget, event):
|
|
|
|
if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
|
2020-12-23 00:32:32 +00:00
|
|
|
pass
|
2020-12-22 02:18:11 +00:00
|
|
|
|
|
|
|
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 + " "
|
2020-12-22 02:50:55 +00:00
|
|
|
for mention in self.post_data.content.entities.mentions:
|
|
|
|
replyuser += "@" + mention.text + " "
|
2020-12-22 02:18:11 +00:00
|
|
|
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)
|
|
|
|
|
2021-01-01 21:26:29 +00:00
|
|
|
def on_copy_link(self, action, param):
|
|
|
|
post_url = f"https://posts.pnut.io/{self.post_data.id}"
|
|
|
|
self.clipboard.set_text(post_url, -1)
|
|
|
|
|
|
|
|
def on_open_link(self, action, param):
|
|
|
|
logging.debug("open_link")
|
|
|
|
post_url = f"https://posts.pnut.io/{self.post_data.id}"
|
|
|
|
opened = Gtk.show_uri_on_window(None, post_url, Gdk.CURRENT_TIME)
|
|
|
|
logging.debug(opened)
|
|
|
|
|
2020-11-27 19:52:03 +00:00
|
|
|
class PostItem(Gtk.ListBoxRow):
|
|
|
|
|
2020-12-22 02:18:11 +00:00
|
|
|
__gsignals__ = {
|
|
|
|
'menu-pressed': (GObject.SIGNAL_RUN_FIRST, None, (int,))
|
|
|
|
}
|
|
|
|
|
2020-11-27 19:52:03 +00:00
|
|
|
def __init__(self, post):
|
|
|
|
super(Gtk.ListBoxRow, self).__init__()
|
2021-01-01 23:25:18 +00:00
|
|
|
if 'repost_of' in post:
|
|
|
|
reposted_by = post.user
|
|
|
|
post = post.repost_of
|
|
|
|
else:
|
|
|
|
reposted_by = None
|
2020-11-27 19:52:03 +00:00
|
|
|
self.post = post
|
|
|
|
|
2020-12-28 05:10:40 +00:00
|
|
|
# Avatar
|
|
|
|
#self.avatar = Handy.Avatar(size=48, text=post.user.username, show_initials=True)
|
|
|
|
#self.avatar.set_image_load_func(self.get_avatar, post.user.content.avatar_image)
|
|
|
|
self.avatar = Gtk.Image.new_from_pixbuf(self.get_avatar(48, post.user.content.avatar_image))
|
|
|
|
|
|
|
|
# Source
|
|
|
|
self.source = Gtk.Label(label=post.source.name, xalign=1)
|
|
|
|
|
|
|
|
self.username = Gtk.Label(label="@" + post.user.username, xalign=0)
|
|
|
|
self.name = Gtk.Label(xalign=0)
|
|
|
|
if 'name' in post.user:
|
|
|
|
self.name.set_markup(f"<b>{post.user.name}</b>")
|
|
|
|
|
|
|
|
# datetime
|
2020-12-28 19:22:54 +00:00
|
|
|
now = datetime.datetime.now(tzlocal())
|
2020-12-28 05:10:40 +00:00
|
|
|
post_date_local = post.created_at.astimezone(tzlocal())
|
2020-12-28 19:22:54 +00:00
|
|
|
#datetime_label = Gtk.Label(label=post_date_local.strftime("%Y-%m-%d %H:%M"), xalign=1)
|
|
|
|
datetime_label = Gtk.Label(xalign=1)
|
|
|
|
datetime_label.set_markup('<span size="small">' + timeago.format(post_date_local, now) + '</span>')
|
2020-11-27 19:52:03 +00:00
|
|
|
|
2020-12-22 02:18:11 +00:00
|
|
|
# post menu
|
|
|
|
self.menu_button = Gtk.Button.new_from_icon_name('view-more-symbolic', 1)
|
|
|
|
self.menu_button.connect('clicked', self.show_menu)
|
|
|
|
|
2020-12-28 05:10:40 +00:00
|
|
|
self.box = Gtk.Box(orientation='vertical')
|
|
|
|
self.add(self.box)
|
|
|
|
|
2020-11-27 19:52:03 +00:00
|
|
|
# name container
|
|
|
|
self.name_box = Gtk.Box(orientation='vertical')
|
|
|
|
self.name_box.pack_start(self.name, True, True, 0)
|
|
|
|
self.name_box.pack_start(self.username, True, True, 0)
|
|
|
|
|
|
|
|
# header container
|
|
|
|
self.h_box = Gtk.Box(orientation='horizontal')
|
2020-12-21 17:38:48 +00:00
|
|
|
self.h_box.pack_start(self.avatar, False, False, 10)
|
2020-11-27 19:52:03 +00:00
|
|
|
self.h_box.pack_start(self.name_box, False, False, 0)
|
2020-12-28 05:10:40 +00:00
|
|
|
#self.h_box.pack_end(self.source, False, False, 10)
|
2020-12-28 19:22:54 +00:00
|
|
|
#self.h_box.pack_end(datetime_label, False, False, 10)
|
2020-11-27 19:52:03 +00:00
|
|
|
|
|
|
|
# content container
|
2020-12-17 01:17:05 +00:00
|
|
|
self.c_box = Gtk.Box(orientation='vertical')
|
|
|
|
self.t_box = Gtk.Box(orientation='horizontal')
|
2020-11-27 19:52:03 +00:00
|
|
|
self.content = Gtk.Label(wrap=True, xalign=0)
|
|
|
|
# TODO: parse content links
|
|
|
|
if 'content' in post:
|
2020-12-28 05:10:40 +00:00
|
|
|
self.content.set_text(post.content.text)
|
2020-12-21 17:38:48 +00:00
|
|
|
self.t_box.pack_start(self.content, False, False, 10)
|
|
|
|
self.c_box.pack_start(self.t_box, False, False, 10)
|
2020-12-17 01:17:05 +00:00
|
|
|
|
|
|
|
if 'raw' in post:
|
|
|
|
for raw in post.raw:
|
2020-12-22 22:55:05 +00:00
|
|
|
# TODO: hide this under toggle?
|
|
|
|
if raw.type == "nl.chimpnut.blog.post":
|
|
|
|
longpost = raw.value
|
|
|
|
if 'title' in longpost:
|
|
|
|
lp_title = Gtk.Label(wrap=True)
|
|
|
|
lp_title.set_markup(f"<b>{longpost.title}</b>")
|
|
|
|
self.c_box.pack_start(lp_title, False, False, 10)
|
|
|
|
lp_body = Gtk.Label(wrap=True)
|
|
|
|
lp_body.set_text(longpost.body)
|
|
|
|
self.c_box.pack_start(lp_body, False, False, 10)
|
|
|
|
|
|
|
|
# TODO: open full photo in seperate window
|
2020-12-17 01:17:05 +00:00
|
|
|
if raw.type == "io.pnut.core.oembed":
|
|
|
|
oembed = raw.value
|
|
|
|
if oembed.type == "photo":
|
2020-12-17 05:29:23 +00:00
|
|
|
photo = Gtk.Image.new_from_pixbuf(self.get_oembed_thumb(oembed))
|
2020-12-21 17:38:48 +00:00
|
|
|
self.c_box.pack_end(photo, False, False, 10)
|
2020-11-27 19:52:03 +00:00
|
|
|
|
2021-01-01 23:25:18 +00:00
|
|
|
if reposted_by is not None:
|
|
|
|
reposted_label_text = f'<span size="small"><i>reposted by @{reposted_by.username}</i></span>'
|
|
|
|
reposted_label = Gtk.Label(xalign=0)
|
|
|
|
reposted_label.set_margin_left(10)
|
|
|
|
reposted_label.set_margin_top(5)
|
|
|
|
reposted_label.set_markup(reposted_label_text)
|
|
|
|
self.c_box.pack_end(reposted_label, False, False, 0)
|
|
|
|
|
2020-12-17 05:30:04 +00:00
|
|
|
# footer container
|
|
|
|
self.f_box = Gtk.Box(orientation='horizontal')
|
2020-12-28 19:22:54 +00:00
|
|
|
self.f_box.pack_end(self.menu_button, False, False, 5)
|
|
|
|
self.f_box.pack_end(datetime_label, False, False, 5)
|
|
|
|
#self.f_box.pack_end(self.source, False, False, 5)
|
2020-12-22 02:18:11 +00:00
|
|
|
|
2020-12-17 18:27:52 +00:00
|
|
|
pad = Gtk.Label(label="")
|
2020-12-22 02:18:11 +00:00
|
|
|
self.f_box.pack_start(pad, False, False, 5)
|
2020-12-17 18:27:52 +00:00
|
|
|
|
|
|
|
if post.id != int(post.thread_id):
|
|
|
|
thread_icon = Gtk.Image.new_from_icon_name("user-available-symbolic", Gtk.IconSize.SMALL_TOOLBAR)
|
2020-12-21 17:38:48 +00:00
|
|
|
self.f_box.pack_start(thread_icon, False, False, 5)
|
2020-12-17 18:27:52 +00:00
|
|
|
if post.counts.bookmarks > 0:
|
|
|
|
if post.you_bookmarked:
|
|
|
|
star_icon = Gtk.Image.new_from_icon_name("starred-symbolic", Gtk.IconSize.SMALL_TOOLBAR)
|
|
|
|
else:
|
|
|
|
star_icon = Gtk.Image.new_from_icon_name("non-starred-symbolic", Gtk.IconSize.SMALL_TOOLBAR)
|
|
|
|
star_count = Gtk.Label(label=post.counts.bookmarks)
|
2020-12-21 17:38:48 +00:00
|
|
|
self.f_box.pack_start(star_icon, False, False, 5)
|
2020-12-17 18:27:52 +00:00
|
|
|
self.f_box.pack_start(star_count, False, False, 0)
|
|
|
|
if post.counts.reposts > 0:
|
|
|
|
repost_icon = Gtk.Image.new_from_icon_name("media-playlist-repeat-symbolic", Gtk.IconSize.SMALL_TOOLBAR)
|
|
|
|
repost_count = Gtk.Label(label=post.counts.reposts)
|
2020-12-21 17:38:48 +00:00
|
|
|
self.f_box.pack_start(repost_icon, False, False, 5)
|
2020-12-17 18:27:52 +00:00
|
|
|
self.f_box.pack_start(repost_count, False, False, 0)
|
2020-12-17 05:30:04 +00:00
|
|
|
|
2020-11-27 19:52:03 +00:00
|
|
|
self.box.pack_start(self.h_box, True, True, 10)
|
|
|
|
self.box.pack_start(self.c_box, True, True, 10)
|
2020-12-17 05:30:04 +00:00
|
|
|
self.box.pack_start(self.f_box, True, True, 10)
|
2020-11-27 19:52:03 +00:00
|
|
|
|
2020-12-22 15:59:03 +00:00
|
|
|
def get_avatar(self, size, avatar):
|
2020-12-27 23:30:00 +00:00
|
|
|
# TODO: age out cache
|
|
|
|
cache_dir = os.path.join(GLib.get_user_cache_dir(), 'avatars')
|
|
|
|
link_hash = avatar.link.rsplit('/', 1)[-1]
|
|
|
|
file_hash = os.path.join(cache_dir, link_hash)
|
|
|
|
if not os.path.exists(cache_dir):
|
|
|
|
os.mkdir(cache_dir)
|
|
|
|
|
|
|
|
if os.path.exists(file_hash):
|
|
|
|
scaled_img = GdkPixbuf.Pixbuf.new_from_file(file_hash)
|
|
|
|
else:
|
|
|
|
r = requests.get(avatar.link, stream=True)
|
|
|
|
loader = GdkPixbuf.PixbufLoader()
|
|
|
|
loader.write(r.content)
|
|
|
|
loader.close()
|
|
|
|
pixbuf = loader.get_pixbuf()
|
|
|
|
old_width = avatar.width
|
|
|
|
old_height = avatar.height
|
|
|
|
ratio = old_width / old_height
|
|
|
|
new_height = size / ratio
|
|
|
|
scaled_img = pixbuf.scale_simple(size,new_height,GdkPixbuf.InterpType.BILINEAR)
|
|
|
|
scaled_img.savev(file_hash, 'jpeg', ["quality"], ["100"])
|
|
|
|
|
|
|
|
return scaled_img
|
2020-12-17 01:17:05 +00:00
|
|
|
|
2020-12-17 05:29:23 +00:00
|
|
|
def get_oembed_thumb(self, oembed):
|
|
|
|
url = oembed.thumbnail_url
|
|
|
|
old_width = oembed.thumbnail_width
|
|
|
|
old_height = oembed.thumbnail_height
|
|
|
|
ratio = old_width / old_height
|
|
|
|
new_height = 256 / ratio
|
|
|
|
r = requests.get(url)
|
|
|
|
loader = GdkPixbuf.PixbufLoader()
|
|
|
|
loader.write(r.content)
|
|
|
|
loader.close()
|
|
|
|
pixbuf = loader.get_pixbuf()
|
|
|
|
return pixbuf.scale_simple(256,new_height,GdkPixbuf.InterpType.BILINEAR)
|
|
|
|
|
2020-12-22 02:18:11 +00:00
|
|
|
def show_menu(self, widget):
|
|
|
|
self.emit('menu-pressed', self.get_index())
|
|
|
|
|