This repository has been archived on 2023-02-02. You can view files and clone it, but cannot push or open issues or pull requests.
barkshark-web/barkshark_web/component/status_bar.py
2022-10-05 13:30:39 -04:00

523 lines
14 KiB
Python

import asyncio
from izzylib.misc import random_str
from .. import cache, var
from ..base import ComponentBase
from ..database import default_permissions
from ..exceptions import AccountNotFoundError, NoAccountsError
from ..functions import connect, get_buffer_text
from ..objects import SavedLoginRow
SITEOPTIONS = [
'instance',
'adblock',
'fullscreen',
'autoplay',
'dialog',
'notification',
'microphone',
'location',
'camera'
]
class StatusBar(ComponentBase):
def __init__(self, window):
ComponentBase.__init__(self, 'statusbar')
self.window = window
self.siteoptions_handler_ids = []
self.bookmark_row = None
self.theme_enabled = False
self.toot_acct = None
self.toot_post = None
self.toot_max_len = 500
self.unsaved_logins = []
self.setup()
@property
def tab(self):
return self.window.active_tab
def bookmark_get_data(self):
data = DotDict()
for k,v in self.bookmark_fields.items():
if k == 'description':
data[k] = get_buffer_text(v.get_buffer())
else:
data[k] = v.get_text()
return data
def bookmark_refresh_categories(self):
menu = self['bookmark-category-menu']
menu.foreach(lambda child: child.destroy())
with self.db.session as s:
for category in s.get_categories():
item = Gtk.MenuItem.new_with_label(category)
item.show()
connect(item, 'activate', self.handle_bookmark_set_category, category)
menu.add(item)
def bookmark_set_data(self, name=None, url=None, category=None, description=None):
data = dict(name=name, url=url, category=category, description=description)
for k,v in data.items():
value = v if v != None else ''
if k == 'description':
self.bookmark_fields[k].get_buffer().set_text(value)
else:
self.bookmark_fields[k].set_text(value)
def login_unsaved_del_row(self, row):
self.logins.unsaved.remove(row['container'])
self.unsaved_logins.remove(row)
def login_unsaved_get_row(self, widget):
for row in self.unsaved_logins:
if widget == row['container']:
return row
def login_unsaved_new(self, data):
self.logins.unsaved.add(SavedLoginRow(data))
def login_unsaved_refresh(self):
for child in self.logins.unsaved.get_children():
self.logins.unsaved.remove(child)
child.destroy()
for row in self.unsaved_logins:
self.logins.unsaved(UnsavedLoginRow(row)['container'])
def toot_close(self, *args):
self['toot-popover'].popdown()
def toot_clear(self, *args):
self.toot_fields.spoiler.set_text('')
self.toot_fields.content.get_buffer().set_text('')
self.toot_fields.visibility.set_active(0)
self.toot_update_count()
self.toot_set_reply()
def toot_set_account(self):
try:
self.toot_account = self.app.get_default_account()
if self.toot_account.avatar.exists():
avatar = GdkPixbuf.Pixbuf.new_from_file_at_scale(self.toot_account.avatar, -1, 24, True)
self['toot-avatar'].set_from_pixbuf(avatar)
self['toot-avatar'].set_tooltip_text(f'{self.toot_account.data.display_name} ({self.toot_account.fullhandle})')
except NoAccountsError:
self.window.notification('No active fedi accounts', 'error')
return False
return True
def toot_get_info(self):
return DotDict(
spoiler = self.toot_fields.spoiler.get_text(),
content = get_buffer_text(self.toot_fields.content.get_buffer()),
visibility = self.toot_fields.visibility.get_active_text()
)
def toot_send(self, *args):
data = self.toot_get_info()
options = {
'visibility': data.visibility.lower()
}
if not (data.spoiler or data.content):
return self.window.notification('Unwilling to send empty post', level='error')
if data.spoiler:
options['spoiler_text'] = data.spoiler
if self['toot-reply-scroll'].get_visible():
options['in_reply_to_id'] = self.toot_post.id
try:
self.toot_account.api.status_post(data.content, **options)
except Exception as e:
logging.error(f'{type(e).__name__}: {e}')
self.window.notification('Failed to send toot')
return
self.window.notification('Sent toot')
self['toot-popover'].popdown()
self.toot_clear()
def toot_set_reply(self, toot=None):
self.toot_post = toot
reply = self.toot_fields.reply
scroll = self['toot-reply-scroll']
privacy = self['toot-visibility']
account = self.toot_post.get('account') if toot else None
if not toot and not account:
scroll.hide()
return
text_buffer = reply.get_buffer()
text_buffer.set_text(f'Reply to: {account.display_name} ({account.acct}):\n\n{toot.content}')
reply.set_buffer(text_buffer)
privacy.set_active_id(toot.get('visibility', 'public'))
scroll.show()
def toot_update_count(self, *args):
spoiler = len(self.toot_fields.spoiler.get_text())
content = self.toot_fields.content.get_buffer().get_char_count()
num = spoiler + content
self.toot_fields.count.set_text(str(self.toot_max_len - num))
def handle_cookie_domains(self, data_manager, result):
data = data_manager.fetch_finish(result)
print(set(item.get_name() for item in data))
def handle_status_button(self, name):
try:
if not self[name].get_active():
return
except AttributeError:
pass
tab = self.tab
if name == 'debug':
#self.window.notification('Merp!', 'INFO', timeout=0, system=True)
print(asyncio.get_running_loop())
#if self.window.themes.current:
#self.window.themes.unset()
#else:
#self.window.themes.set('test')
elif name == 'bookmark':
if not tab.url:
return
self['bookmark-popover'].grab_focus()
with self.db.session as s:
self.bookmark_row = s.get_bookmark(tab.url)
if not self.bookmark_row:
self['bookmark-delete'].set_sensitive(False)
return self.bookmark_set_data(
name = tab.title,
url = tab.url,
category = 'Default'
)
self['bookmark-delete'].set_sensitive(True)
self.bookmark_set_data(
name = self.bookmark_row.name,
url = self.bookmark_row.url,
category = self.bookmark_row.category,
description = self.bookmark_row.description
)
elif name == 'siteoptions':
if not self['siteoptions'].get_active() or not tab.url.hostname():
return
with self.db.session as s:
row = s.get_permission(tab.url.hostname())
self['siteoptions-domain'].set_text(tab.url.hostname())
self['siteoptions-reset'].set_sensitive(True if row != None else False)
self.siteoptions_row = row
with self.block_signals(*[f'siteoptions-{name}' for name in SITEOPTIONS]):
for k, v in default_permissions.items():
value = row.get(k, v)
self[f'siteoptions-{k}'].set_state(value)
self['siteoptions-reset'].set_sensitive(row and row.id != None)
self['siteoptions-reset'].grab_focus()
elif name == 'logins':
self['logins-saved-list'].grab_focus()
self.handle_logins_refresh()
elif name == 'toot':
if not self.toot_set_account():
return self['toot-popover'].popdown()
self.toot_max_len = self.toot_account.toot_limit
self.toot_update_count()
self.toot_set_reply(self.toot_post)
self['toot-content'].grab_focus()
def handle_bookmark_button(self, name):
with self.db.session as s:
if name == 'save':
data = self.bookmark_get_data()
if self.bookmark_row:
s.put_bookmark_row(self.bookmark_row, **data)
else:
s.put_bookmark(**data)
elif name == 'delete':
if self.bookmark_row:
s.remove_row(self.bookmark_row)
self['bookmark-popover'].popdown()
def handle_bookmark_category_button(self):
menu = self['bookmark-category-menu']
menu.popup_at_widget(
widget = self['bookmark-category'],
widget_anchor = Gdk.Gravity.NORTH_EAST,
menu_anchor = Gdk.Gravity.SOUTH_EAST,
trigger_event = None
)
def handle_bookmark_set_category(self, category):
self['bookmark-category'].set_text(category)
def handle_fedi_button(self, name):
post = self.tab.fedi_post
if not post or not self.toot_set_account():
return
if name == 'reply':
#self.toot_set_reply(post)
self.toot_post = post
self['toot'].activate()
elif name == 'favorite':
if post.favourited == True:
if self.toot_account.api.status_unfavourite(post.id):
post.favourited = False
self.window.notification('Unfavorited post')
else:
self.window.notification('Failed to unfavorite post', 'error')
else:
if self.toot_account.api.status_favourite(post.id):
post.favourited = True
self.window.notification('Favorited post')
else:
self.window.notification('Failed to favorite post', 'error')
elif name == 'boost':
if post.reblogged == True:
if self.toot_account.api.status_unreblog(post.id):
post.reblogged = False
self.window.notification('Unboosted post')
else:
self.window.notification('Failed to unboost post', 'error')
else:
if self.toot_account.api.status_reblog(post.id):
post.reblogged = True
self.window.notification('Boosted post')
else:
self.window.notification('Failed to boost post', 'error')
if post:
cache.posts.store(self.tab.url, post)
def handle_siteoptions_switch(self, name):
active = self[f'siteoptions-{name}'].get_active()
try:
host = self.tab.url.hostname()
except:
return
with self.db.session as s:
s.put_permission(host, name, active)
logging.verbose(f'siteoptions: set {name}: {active}')
self['siteoptions-reset'].set_sensitive(True)
def handle_siteoptions_button(self, name):
if name == 'reset':
host = self.tab.url.hostname()
with self.db.session as s:
s.del_permission(host)
self.handle_status_button('siteoptions')
elif name == 'close':
self['siteoptions-popover'].popdown()
def handle_logins_button(self, name):
if name == 'clear':
for widget in self['logins-unsaved-list']:
widget.handle_cancel()
elif name == 'passgen':
self.app.clipboard.set_text(random_str(extra=r'!@#$%^&*()_+-={}[]<>;:'), -1)
self.window.notification('Copied newly-generated password to clipboard', system=False)
self['logins-popover'].popdown()
def handle_logins_refresh(self):
login_list = self['logins-saved-list']
url = self.tab.url
unsaved = len(self['logins-unsaved-list'])
for child in login_list.get_children():
child.destroy()
for row in self.app.password.fetch(domain=url.hostname()):
## todo: fix searching by domain
if row.domain == url.hostname():
login_list.add(SavedLoginRow(row, url)['container'])
for name in ['scroll', 'label', 'clear']:
widget = self[f'logins-unsaved-{name}']
if unsaved:
widget.show()
else:
widget.hide()
def handle_toot_key_press(self, textview, event, *args):
keyname = Gdk.keyval_name(event.keyval)
if keyname.lower() == 'return' and event.state == Gdk.ModifierType.CONTROL_MASK:
self.toot_send()
return True
def handle_toot_spoiler_activate(self, *args):
self['toot-content'].grab_focus()
def setup(self):
self.bookmark_fields = DotDict(
name = self['bookmark-title'],
url = self['bookmark-url'],
category = self['bookmark-category'],
description = self['bookmark-description']
)
self.toot_fields = DotDict(
reply = self['toot-reply'],
spoiler = self['toot-spoiler'],
content = self['toot-content'],
visibility = self['toot-visibility'],
count = self['toot-count']
)
self.logins = DotDict(
unsaved = self['logins-unsaved-list'],
saved = self['logins-saved-list']
)
## Status bar
self.connect('debug', 'clicked', self.handle_status_button, 'debug')
self.connect('toot', 'toggled', self.handle_status_button, 'toot')
self.connect('reply', 'clicked', self.handle_fedi_button, 'reply')
self.connect('boost', 'clicked', self.handle_fedi_button, 'boost')
self.connect('favorite', 'clicked', self.handle_fedi_button, 'favorite')
self.connect('logins', 'toggled', self.handle_status_button, 'logins')
self.connect('bookmark', 'toggled', self.handle_status_button, 'bookmark')
self.connect('siteoptions', 'toggled', self.handle_status_button, 'siteoptions')
## Toot
self.connect('toot-spoiler', 'changed', self.toot_update_count)
self.connect('toot-spoiler', 'activate', self.handle_toot_spoiler_activate)
self.connect('toot-reset', 'clicked', self.toot_clear)
self.connect('toot-send', 'clicked', self.toot_send)
self.connect('toot-close', 'clicked', self.toot_close)
self.connect('toot-content', 'key-press-event', self.handle_toot_key_press)
connect(self['toot-content'].get_buffer(), 'changed', self.toot_update_count)
## Logins
self.connect('logins-close', 'clicked', self.handle_logins_button, 'close')
self.connect('logins-unsaved-clear', 'clicked', self.handle_logins_button, 'clear')
self.connect('logins-saved-passgen', 'clicked', self.handle_logins_button, 'passgen')
## Bookmarks
self.connect('bookmark-save', 'clicked', self.handle_bookmark_button, 'save')
self.connect('bookmark-delete', 'clicked', self.handle_bookmark_button, 'delete')
self.connect('bookmark-close', 'clicked', self.handle_bookmark_button, 'close')
self.connect('bookmark-category', 'icon-press', self.handle_bookmark_category_button)
## Siteoptions
self.connect('siteoptions-reset', 'clicked', self.handle_siteoptions_button, 'reset')
self.connect('siteoptions-close', 'clicked', self.handle_siteoptions_button, 'close')
# extra work needs to be done to toggle webview settings
self.permissions = DotDict({
'instance': False,
'adblock': True,
'fullscreen': True,
'autoplay': False,
'dialog': True,
'notification': False,
'microphone': False,
'location': False,
'camera': False,
#'javascript': True,
#'images': True,
#'autoplay': False,
#'insecure': False
})
for name in self.permissions:
self.connect(f'siteoptions-{name}', 'state-set', self.handle_siteoptions_switch, name)
self.bookmark_refresh_categories()