Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial libsoup async implementation #236

Merged
merged 17 commits into from
Feb 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions data/resources/window.ui
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@
</child>
<child>
<object class="AdwStatusPage" id="error_page">
<property name="title">Could not load the translator service</property>
<property name="vexpand">True</property>
<property name="child">
<object class="GtkBox">
Expand All @@ -102,7 +101,59 @@
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Open preferences</property>
<property name="label" translatable="yes">Open Preferences</property>
<property name="action-name">app.preferences</property>
<style>
<class name="pill" />
</style>
</object>
</child>
</object>
</property>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">api-key</property>
<property name="child">
<object class="GtkWindowHandle">
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="AdwHeaderBar">
<style>
<class name="flat" />
</style>
</object>
</child>
<child>
<object class="AdwStatusPage" id="key_page">
<property name="icon-name">dialog-password-symbolic</property>
<property name="vexpand">True</property>
<property name="child">
<object class="GtkBox">
<property name="spacing">12</property>
<property name="halign">center</property>
<child>
<object class="GtkButton" id="rmv_key_btn">
<property name="visible">False</property>
<property name="label" translatable="yes">Remove Key and Retry</property>
<style>
<class name="pill" />
<class name="suggested-action" />
</style>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Open Preferences</property>
<property name="action-name">app.preferences</property>
<style>
<class name="pill" />
Expand Down
13 changes: 12 additions & 1 deletion dialect/lang_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
@Gtk.Template(resource_path=f'{RES_PATH}/lang-selector.ui')
class DialectLangSelector(Gtk.Popover):
__gtype_name__ = 'DialectLangSelector'
__gsignals__ = {
'user-selection-changed': (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, ())
}

# Get widgets
search = Gtk.Template.Child()
Expand Down Expand Up @@ -55,6 +58,14 @@ def __init__(self, **kwargs):
self.lang_list.set_model(selection_model)
self.lang_list.set_factory(self.factory)

def get_selected(self):
return self.get_property('selected')

def set_selected(self, lang_code, notify=True):
self.set_property('selected', lang_code)
if notify:
self.emit('user-selection-changed')

def set_languages(self, languages):
# Clear list
self.lang_model.remove_all()
Expand All @@ -80,7 +91,7 @@ def _activated(self, list_view, index):
model = list_view.get_model()
lang = model.get_selected_item()
# Set selected property
self.set_property('selected', lang.code)
self.set_selected(lang.code)

def _closed(self, _popover):
# Reset scroll
Expand Down
1 change: 1 addition & 0 deletions dialect/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ sources = [
'window.py',
'preferences.py',
'lang_selector.py',
'session.py',
'settings.py',
'shortcuts.py',
]
Expand Down
197 changes: 106 additions & 91 deletions dialect/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
# Copyright 2020-2021 Rafael Mardojai CM
# SPDX-License-Identifier: GPL-3.0-or-later

import logging
import os
import re
import threading
from gettext import gettext as _

from gi.repository import Adw, Gio, GLib, GObject, Gtk
from gi.repository import Adw, Gio, GLib, GObject, Gtk, Soup

from dialect.define import RES_PATH
from dialect.session import Session
from dialect.settings import Settings
from dialect.translators import TRANSLATORS
from dialect.tts import TTS
Expand Down Expand Up @@ -161,7 +163,7 @@ def _on_settings_changed(self, _settings, key):
if key == 'instance-url' and TRANSLATORS[backend].supported_features['change-instance']:
Settings.get().reset_src_langs()
Settings.get().reset_dest_langs()
self.parent.change_backends(backend)
self.parent.reload_backends()

def _toggle_dark_mode(self, switch, _active):
active = switch.get_active()
Expand Down Expand Up @@ -197,36 +199,85 @@ def _switch_backends(self, row, _value):
backend = self.backend_model[row.get_selected()].name
Settings.get().active_translator = backend
self.__check_instance_or_api_key_support()
self.parent.change_backends(backend)
self.parent.reload_backends()

def _on_backend_loading(self, window, _value):
self.backend.set_sensitive(not window.get_property('backend-loading'))
self.backend_instance_row.set_sensitive(not window.get_property('backend-loading'))
self.api_key_row.set_sensitive(not window.get_property('backend-loading'))

# Show or hide api key entry
if not window.get_property('backend-loading') and window.translator:
if window.translator.supported_features['api-key-supported']:
self.api_key_row.set_visible(True)
self.api_key_label.set_label(Settings.get().api_key or 'None')
else:
self.api_key_row.set_visible(False)

def _on_edit_backend_instance(self, _button):
self.backend_instance_stack.set_visible_child_name('edit')
self.backend_instance.set_text(Settings.get().instance_url)

def _on_save_backend_instance(self, _button):
def on_validation_response(session, result):
valid = False
backend = Settings.get().active_translator
try:
data = Session.get_response(session, result)
valid = TRANSLATORS[backend].validate_instance(data)
except Exception as exc:
logging.error(exc)

if valid:
Settings.get().instance_url = self.new_instance_url
self.backend_instance.get_style_context().remove_class('error')
self.backend_instance_stack.set_visible_child_name('view')
# self.error_popover.popdown()
else:
self.backend_instance.get_style_context().add_class('error')
error_text = _('Not a valid {backend} instance')
error_text = error_text.format(backend=TRANSLATORS[backend].prettyname)
self.error_label.set_label(error_text)
# self.error_popover.popup()
self.api_key_row.set_visible(False)
self.api_key_label.set_label('None')

self.backend.set_sensitive(True)
self.backend_instance_row.set_sensitive(True)
self.api_key_row.set_sensitive(True)
self.backend_instance_save.set_child(self.instance_save_image)
self.backend_instance_label.set_label(Settings.get().instance_url)
self.instance_save_spinner.stop()

old_value = Settings.get().instance_url
new_value = self.backend_instance.get_text()

url = re.compile(r'https?://(www\.)?')
new_value = url.sub('', new_value).strip().strip('/')
self.new_instance_url = url.sub('', new_value).strip().strip('/')

if new_value != old_value:
# Validate
threading.Thread(
target=self.__validate_new_backend_instance,
args=[new_value],
daemon=True
).start()
# Validate
if self.new_instance_url != old_value:
# Progress feedback
self.backend.set_sensitive(False)
self.backend_instance_row.set_sensitive(False)
self.api_key_row.set_sensitive(False)
self.backend_instance_save.set_child(self.instance_save_spinner)
self.instance_save_spinner.start()

backend = Settings.get().active_translator
validation_url = TRANSLATORS[backend].format_instance_url(
rafaelmardojai marked this conversation as resolved.
Show resolved Hide resolved
self.new_instance_url,
TRANSLATORS[backend].validation_path
)
validation_message = Soup.Message.new('GET', validation_url)

Session.get().send_and_read_async(validation_message, 0, None, on_validation_response)
else:
self.backend_instance_stack.set_visible_child_name('view')

def _on_reset_backend_instance(self, _button):
Settings.get().reset_instance_url()
Settings.get().reset_api_key()
self.backend_instance_label.set_label(Settings.get().instance_url)
self.backend_instance_stack.set_visible_child_name('view')
self.backend_instance.get_style_context().remove_class('error')
Expand All @@ -237,16 +288,52 @@ def _on_edit_api_key(self, _button):
self.api_key.set_text(Settings.get().api_key)

def _on_save_api_key(self, _button):
def on_response(session, result):
valid = False
try:
data = Session.get_response(session, result)
self.parent.translator.get_translation(data)
valid = True
except Exception as exc:
logging.warning(exc)

if valid:
Settings.get().api_key = self.new_api_key
self.api_key.get_style_context().remove_class('error')
self.api_key_stack.set_visible_child_name('view')
else:
self.api_key.get_style_context().add_class('error')
error_text = _('Not a valid {backend} API key')
error_text = error_text.format(backend=TRANSLATORS[backend].prettyname)
self.error_label.set_label(error_text)

self.backend.set_sensitive(True)
self.backend_instance_row.set_sensitive(True)
self.api_key_row.set_sensitive(True)
self.api_key_save.set_child(self.api_key_save_image)
self.api_key_label.set_label(Settings.get().api_key or 'None')
self.instance_save_spinner.stop()

old_value = Settings.get().api_key
new_value = self.api_key.get_text()
self.new_api_key = self.api_key.get_text()

if new_value != old_value:
# Validate
threading.Thread(
target=self.__validate_new_api_key,
args=[new_value],
daemon=True
).start()
if self.new_api_key != old_value:
# Progress feedback
self.backend.set_sensitive(False)
self.backend_instance_row.set_sensitive(False)
self.api_key_row.set_sensitive(False)
self.api_key_save.set_child(self.api_key_save_spinner)
self.api_key_save_spinner.start()

backend = Settings.get().active_translator
validation_url = TRANSLATORS[backend].format_instance_url(
Settings.get().instance_url,
TRANSLATORS[backend].api_test_path
)
(data, headers) = TRANSLATORS[backend].format_api_key_test(self.new_api_key)
message = Session.create_post_message(validation_url, data, headers)

Session.get().send_and_read_async(message, 0, None, on_response)
else:
self.api_key_stack.set_visible_child_name('view')

Expand All @@ -271,78 +358,6 @@ def __check_instance_or_api_key_support(self):
else:
self.api_key_row.set_visible(False)

def __validate_new_backend_instance(self, url):
def spinner_start():
self.backend.set_sensitive(False)
self.backend_instance_row.set_sensitive(False)
self.api_key_row.set_sensitive(False)
self.backend_instance_save.set_child(self.instance_save_spinner)
self.instance_save_spinner.start()

def spinner_end():
self.backend.set_sensitive(True)
self.backend_instance_row.set_sensitive(True)
self.api_key_row.set_sensitive(True)
self.backend_instance_save.set_child(self.instance_save_image)
self.backend_instance_label.set_label(Settings.get().instance_url)
self.instance_save_spinner.stop()

GLib.idle_add(spinner_start)
backend = Settings.get().active_translator
result = TRANSLATORS[backend].validate_instance_url(url)
if result['validation-success']:
Settings.get().instance_url = url
GLib.idle_add(self.backend_instance.get_style_context().remove_class, 'error')
GLib.idle_add(self.backend_instance_stack.set_visible_child_name, 'view')
# GLib.idle_add(self.error_popover.popdown)
if result['api-key-supported']:
Settings.get().reset_api_key()
self.api_key_row.set_visible(True)
self.api_key_label.set_label(Settings.get().api_key or 'None')
else:
self.api_key_row.set_visible(False)
else:
GLib.idle_add(self.backend_instance.get_style_context().add_class, 'error')
error_text = _('Not a valid {backend} instance')
error_text = error_text.format(backend=TRANSLATORS[backend].prettyname)
GLib.idle_add(self.error_label.set_label, error_text)
# GLib.idle_add(self.error_popover.popup)
self.api_key_row.set_visible(False)
self.api_key_label.set_label('None')

GLib.idle_add(spinner_end)

def __validate_new_api_key(self, api_key):
def spinner_start():
self.backend.set_sensitive(False)
self.backend_instance_row.set_sensitive(False)
self.api_key_row.set_sensitive(False)
self.api_key_save.set_child(self.api_key_save_spinner)
self.api_key_save_spinner.start()

def spinner_end():
self.backend.set_sensitive(True)
self.backend_instance_row.set_sensitive(True)
self.api_key_row.set_sensitive(True)
self.api_key_save.set_child(self.api_key_save_image)
self.api_key_label.set_label(Settings.get().api_key or 'None')
self.instance_save_spinner.stop()

GLib.idle_add(spinner_start)
backend = Settings.get().active_translator
result = TRANSLATORS[backend].validate_api_key(api_key, Settings.get().instance_url)
if result:
Settings.get().api_key = api_key
GLib.idle_add(self.api_key.get_style_context().remove_class, 'error')
GLib.idle_add(self.api_key_stack.set_visible_child_name, 'view')
else:
GLib.idle_add(self.api_key.get_style_context().add_class, 'error')
error_text = _('Not a valid {backend} API key')
error_text = error_text.format(backend=TRANSLATORS[backend].prettyname)
GLib.idle_add(self.error_label.set_label, error_text)

GLib.idle_add(spinner_end)


class BackendObject(GObject.Object):
__gtype_name__ = 'BackendObject'
Expand Down
Loading