squeak/src/main.py
2021-05-13 14:55:00 -07:00

220 lines
7.7 KiB
Python

# main.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
gi.require_version('Gdk', '3.0')
gi.require_version('Gtk', '3.0')
from gi.repository import GObject, Gdk, Gtk, Gio, GLib
gi.require_version('Handy', '1')
from gi.repository import Handy
Handy.init()
from .widgets import LoginPage, Timeline, PostItem, ComposeWindow
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='dev.thrrgilag.squeak',
flags=Gio.ApplicationFlags.FLAGS_NONE)
def do_startup(self):
Gtk.Application.do_startup(self)
self.authorized = False
self.keyfile = GLib.KeyFile()
self.config_dir = GLib.get_user_config_dir()
self.config_file = os.path.join(self.config_dir, "squeak")
try:
self.keyfile.load_from_file(self.config_file,
GLib.KeyFileFlags.KEEP_COMMENTS)
access_token = self.keyfile.get_string("GENERAL", "ACCESS_TOKEN")
if len(access_token) > 0:
pnutpy.api.add_authorization_token(access_token)
self.authorized = True
except GLib.Error:
pass
action = Gio.SimpleAction.new('newpost', None)
action.connect('activate', self.on_new_post)
self.add_action(action)
self.set_accels_for_action('app.newpost',["<Ctrl>n"])
action = Gio.SimpleAction.new('top', None)
action.connect('activate', self.on_top)
self.add_action(action)
action = Gio.SimpleAction.new('refresh', None)
action.connect('activate', self.on_refresh)
self.add_action(action)
self.set_accels_for_action('app.refresh',["<Ctrl>r"])
action = Gio.SimpleAction.new('preferences', None)
action.connect('activate', self.on_preferences)
self.add_action(action)
# TODO: this shortcut might need adjustment
self.set_accels_for_action('app.preferences',["<Ctrl>,"])
action = Gio.SimpleAction.new('about', None)
action.connect('activate', self.on_about)
self.add_action(action)
action = Gio.SimpleAction.new('quit', None)
action.connect('activate', self.on_quit)
self.add_action(action)
self.set_accels_for_action('app.quit',["<Ctrl>q"])
self.builder = Gtk.Builder.new_from_resource("/dev/thrrgilag/squeak/menu.ui")
def do_activate(self):
self.win = self.props.active_window
if not self.win:
self.win = Gtk.ApplicationWindow(application=self)
self.win.set_default_size(320, 480)
title_bar = Handy.TitleBar()
self.win.set_titlebar(title_bar)
self.header = Handy.HeaderBar(show_close_button=True)
title_bar.add(self.header)
self.stack = Gtk.Stack()
stack_switcher_bar = Handy.ViewSwitcherBar()
stack_switcher_bar.set_stack(self.stack)
switcher_title = Handy.ViewSwitcherTitle()
switcher_title.set_stack(self.stack)
self.header.set_custom_title(switcher_title)
self.header.bind_property("title", switcher_title, "title",
GObject.BindingFlags.SYNC_CREATE)
self.header.bind_property("subtitle", switcher_title, "subtitle",
GObject.BindingFlags.SYNC_CREATE)
switcher_title.bind_property("title-visible", stack_switcher_bar,
"reveal", GObject.BindingFlags.SYNC_CREATE)
if self.authorized:
self.show_main_page()
else:
self.show_login_page()
vbox = Gtk.Box(orientation='vertical')
vbox.pack_start(self.stack, True, True, 0)
vbox.pack_end(stack_switcher_bar, False, False, 0)
self.win.add(vbox)
self.win.show_all()
def handle_login(self, args, code):
# TODO: should do some actual error handling here
self.keyfile.set_string("GENERAL", "ACCESS_TOKEN", code)
self.keyfile.save_to_file(self.config_file)
pnutpy.api.add_authorization_token(code)
self.authorized = True
self.show_main_page()
def show_login_page(self):
login_page = LoginPage()
login_page.connect("login", self.handle_login)
self.stack.add_titled(login_page, "login", "Login")
self.header.show_all()
def show_main_page(self):
login_page = self.stack.get_child_by_name("login")
if login_page is not None:
self.stack.remove(login_page)
# 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")
new_post_button = Gtk.Button.new_from_icon_name('list-add-symbolic', 1)
new_post_button.connect('clicked', self.on_new_post)
self.header.pack_start(new_post_button)
menu = self.builder.get_object("app-menu")
menu_button = Gtk.Button.new_from_icon_name('open-menu-symbolic', 1)
menu_button.connect('clicked', self.on_main_popover)
self.main_popover = Gtk.Popover.new_from_model(menu_button, menu)
self.header.pack_end(menu_button)
update_button = Gtk.Button.new_from_icon_name('view-refresh-symbolic', 1)
update_button.connect('clicked', self.on_refresh)
self.header.pack_end(update_button)
self.header.show_all()
self.stack.show_all()
def on_new_post(self, widget, param=None):
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()
def on_refresh(self, action, param=None):
timeline = self.stack.get_visible_child()
timeline.emit('refresh')
def on_top(self, action, param):
timeline = self.stack.get_visible_child()
timeline.emit('top')
def on_preferences(self, action, param):
pass
def on_about(self, action, param):
pass
def on_quit(self, action, param):
self.quit()
def main(version):
logging.basicConfig(level=logging.DEBUG)
app = Application()
return app.run(sys.argv)