Settings: switch to using Gtk.Template and ditch uneeded options

This commit is contained in:
Bilal Elmoussaoui 2019-02-11 17:22:34 +01:00
parent 343d57462b
commit 3fb0d87c43
11 changed files with 638 additions and 320 deletions

View file

@ -16,6 +16,7 @@
<file compressed="true" preprocess="xml-stripblanks" alias="account_edit.ui">ui/account_edit.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="account_row.ui">ui/account_row.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="window.ui">window.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="settings.ui">settings.ui</file>
<!-- Default pre-shipped icons -->
<file alias="amazon.svg">icons/hicolor/48x48/apps/amazon.svg</file>

View file

@ -1,23 +1,28 @@
about_dialog_conf = configuration_data()
about_dialog_conf.set('APP_ID', application_id)
about_dialog_conf.set('VERSION', meson.project_version())
ui_config = configuration_data()
ui_config.set('APP_ID', application_id)
ui_config.set('VERSION', meson.project_version())
ui_preconfigured_files = files(
'ui/about_dialog.ui.in',
'ui/settings.ui.in',
'ui/window.ui.in',
)
ui_dependencies = []
foreach ui_file: ui_preconfigured_files
ui_dependencies += configure_file(
input: ui_file,
output: '@BASENAME@',
configuration: ui_config
)
endforeach
gnome.compile_resources(
application_id,
meson.project_name() + '.gresource.xml',
gresource_bundle: true,
install_dir: join_paths(get_option('datadir'), meson.project_name()),
install: true,
dependencies: [configure_file(
input: 'ui/about_dialog.ui.in',
output: 'about_dialog.ui',
configuration: about_dialog_conf
),
configure_file(
input: 'ui/window.ui.in',
output: 'window.ui',
configuration: about_dialog_conf
)
]
dependencies: ui_dependencies
)
# Install gschema

View file

@ -1,9 +1,13 @@
.account-row,
.settings-box{
padding: 6px;
.settings-row{
background-color: mix(@theme_base_color,@theme_bg_color,0.3);
padding: 2px 8px;
margin:0;
border: 1px solid mix(@theme_base_color,@theme_fg_color,0.3);
background-color: mix(@theme_base_color,@theme_bg_color,0.3);
margin: 6px;
border-bottom: 0px;
}
.account-row:last-child, .settings-row:last-child {
border-bottom: 1px solid mix(@theme_base_color,@theme_fg_color,0.3);
}
/* AccountsList */
@ -16,9 +20,6 @@
}
/* AccountRow */
.account-row {
padding:0;
}
.account-row .account-name-label{
font-size: 13px;
padding: 3px 6px;
@ -27,6 +28,21 @@
font-size: 12px;
}
/* Settings */
.settings-category-title{
font-size:13px;
font-weight:600;
padding: 6px 3px;
}
.settings-box-main-label{
font-size:12px;
}
.settings-box-secondary-label{
font-size:12px;
color: mix(@theme_base_color,@theme_fg_color,0.6);
}
.application-name {
font-size: 14px;
@ -39,31 +55,7 @@
font-size: 16px;
}
.settings-box-main-label{
font-size: 14px;
padding: 3px 6px;
}
.settings-box-secondary-label {
font-size:12px;
font-style:italic;
color: mix(@theme_base_color,@theme_fg_color,0.6);
padding: 3px 6px;
}
.settings-main-container{
margin-left: 36px;
margin-right: 36px;
}
.loginwidget-sublabel{
font-size: 12px;
color: mix(@theme_base_color,@theme_fg_color,0.6);
}
.loginwidget-mainlabel{
font-size: 18px;
}
/* Common */
.progress-bar trough progress {
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
@ -72,3 +64,6 @@
.progress-bar trough {
border-radius: 0px
}
.app-notification{
font-size:11px;
}

View file

@ -22,7 +22,6 @@
<object class="GtkRevealer" id="notification">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">none</property>
<child>
<object class="GtkOverlay">
<property name="visible">True</property>

View file

@ -13,11 +13,10 @@
<property name="icon_name">document-edit-symbolic</property>
</object>
<template class="AccountRow" parent="GtkListBoxRow">
<property name="width_request">100</property>
<property name="height_request">80</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="valign">start</property>
<property name="valign">center</property>
<property name="selectable">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>

482
data/ui/settings.ui.in Normal file
View file

@ -0,0 +1,482 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.0 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkImage" id="previous_img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-previous-symbolic</property>
</object>
<template class="SettingsWindow" parent="GtkWindow">
<property name="can_focus">False</property>
<property name="type">popup</property>
<property name="window_position">center-on-parent</property>
<property name="default_width">350</property>
<property name="default_height">500</property>
<property name="gravity">center</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkRevealer" id="notification">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkOverlay">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="notification_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<style>
<class name="app-notification"/>
</style>
</object>
<packing>
<property name="index">-1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkStack" id="main_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">36</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Behaviour</property>
<style>
<class name="settings-category-title"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkListBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selection_mode">none</property>
<child>
<object class="GtkListBoxRow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Dark theme</property>
<style>
<class name="settings-box-main-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Use a dark theme, if possible</property>
<style>
<class name="settings-box-secondary-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="dark_theme_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="halign">end</property>
<property name="valign">center</property>
<signal name="state-set" handler="dark_theme_switch_state_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="settings-box"/>
</style>
</object>
</child>
<style>
<class name="settings-row"/>
</style>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Lock the application</property>
<style>
<class name="settings-box-main-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Lock the application with a password</property>
<style>
<class name="settings-box-secondary-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="lock_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="halign">end</property>
<property name="valign">center</property>
<signal name="state-set" handler="lock_switch_state_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="settings-box"/>
</style>
</object>
</child>
<style>
<class name="settings-row"/>
</style>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="name">settings_view</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="hexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">@APP_ID@-symbolic</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_bottom">20</property>
<property name="label" translatable="yes">Keep your accounts safer </property>
<property name="ellipsize">end</property>
<style>
<class name="label-help"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Password</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="password_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="valign">center</property>
<property name="visibility">False</property>
<property name="input_purpose">password</property>
<signal name="changed" handler="password_entry_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Repeat Password</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="repeat_password_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="valign">center</property>
<property name="visibility">False</property>
<property name="input_purpose">password</property>
<signal name="changed" handler="password_entry_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="name">password_view</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="show_close_button">True</property>
<child type="title">
<object class="GtkStack" id="headerbar_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Settings</property>
<style>
<class name="title"/>
</style>
</object>
<packing>
<property name="name">headerbar_settings</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child type="center">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Authenticator Password</property>
<style>
<class name="title"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="back_btn">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">previous_img</property>
<signal name="clicked" handler="back_btn_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="save_btn">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="save_btn_clicked" swapped="no"/>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="name">headerbar_password</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View file

@ -170,7 +170,7 @@
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="hexpand">True</property>
<property name="resource">/com/github/bilelmoussaoui/Authenticator/authenticator-symbolic.svg</property>
<property name="icon_name">@APP_ID@-symbolic</property>
<property name="icon_size">6</property>
</object>
<packing>

View file

@ -23,7 +23,7 @@ from gi import require_version
require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gio, Gdk, GObject
from .widgets import Window, WindowState, AboutDialog, import_json, export_json
from .models import Database, Settings, Clipboard, Logger
from .models import Database, Settings, Clipboard, Logger, Keyring
class Application(Gtk.Application):
@ -40,7 +40,7 @@ class Application(Gtk.Application):
GLib.set_prgname("Authenticator")
self.connect("notify::is-locked", self.__is_locked_changed)
self.alive = True
Settings.get_default().bind("is-locked", self, "is_locked", Gio.SettingsBindFlags.GET)
self._menu = Gio.Menu()
def __is_locked_changed(self, *_):
@ -63,7 +63,7 @@ class Application(Gtk.Application):
Gtk.Application.do_startup(self)
self.__generate_menu()
self.__setup_actions()
self.set_property("is-locked", Settings.get_default().can_be_locked)
self.props.is_locked = Keyring.get_default().has_password()
Application.__setup_css()
# Set the default night mode
@ -126,7 +126,7 @@ class Application(Gtk.Application):
self.__add_action("settings", self.__on_settings, "is_locked")
self.__add_action("import_json", self.__on_import_json, "is_locked")
self.__add_action("export_json", self.__on_export_json, "is_locked")
if Settings.get_default().can_be_locked:
if Keyring.get_default().has_password():
self.__add_action("lock", self.__on_lock, "is_locked")
# Keyboard shortcuts. This includes actions defined in window.py.in

View file

@ -137,3 +137,8 @@ class Keyring:
@staticmethod
def has_password():
return Keyring.get_password() is not None
@staticmethod
def clear_password():
schema = Keyring.get_default().password_schema
Secret.password_clear_sync(schema, {}, None)

View file

@ -29,7 +29,7 @@ class Settings(Gio.Settings):
instance = None
# Settings schema
SCHEMA = "@APP_ID@"
def __init__(self):
Gio.Settings.__init__(self)

View file

@ -19,293 +19,125 @@
from gettext import gettext as _
from gi import require_version
require_version("Gtk", "3.0")
from gi.repository import Gtk, GObject
from gi.repository import Gio, GLib, Gtk, GObject
from .window import Window
from ..models import Settings, Keyring
class ClickableSettingsBox(Gtk.EventBox):
def __init__(self, label, sub_label=None):
Gtk.EventBox.__init__(self)
# cursor = Gdk.Cursor(Gdk.CursorType.WATCH)
# self.get_window().set_cursor(cursor)
self._build_widgets(label, sub_label)
def _build_widgets(self, label, sub_label=None):
container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
container.get_style_context().add_class("settings-box")
main_lbl = Gtk.Label()
main_lbl.set_halign(Gtk.Align.START)
main_lbl.get_style_context().add_class("settings-box-main-label")
main_lbl.set_text(label)
container.pack_start(main_lbl, True, True, 3)
self.secondary_lbl = Gtk.Label()
self.secondary_lbl.set_halign(Gtk.Align.START)
self.secondary_lbl.get_style_context().add_class("settings-box-secondary-label")
if sub_label:
self.secondary_lbl.set_text(sub_label)
else:
self.secondary_lbl.set_text("")
container.pack_start(self.secondary_lbl, True, True, 3)
self.add(container)
class SwitchSettingsBox(Gtk.Box, GObject.GObject):
__gsignals__ = {
'changed': (GObject.SignalFlags.RUN_LAST, None, (bool,))
}
def __init__(self, label, sub_label, schema):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
GObject.GObject.__init__(self)
self.switch = Gtk.Switch()
self._schema = schema
self._build_widgets(label, sub_label)
def _build_widgets(self, label, sub_label):
self.get_style_context().add_class("settings-box")
self.switch.set_state(Settings.get_default().get_boolean(self._schema))
self.switch.connect("state-set", self.__on_toggled)
label_container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
main_lbl = Gtk.Label()
main_lbl.set_halign(Gtk.Align.START)
main_lbl.get_style_context().add_class("settings-box-main-label")
main_lbl.set_text(label)
label_container.pack_start(main_lbl, False, False, 3)
secondary_lbl = Gtk.Label()
secondary_lbl.set_halign(Gtk.Align.START)
secondary_lbl.get_style_context().add_class("settings-box-secondary-label")
secondary_lbl.set_text(sub_label)
label_container.pack_start(secondary_lbl, False, False, 3)
self.pack_start(label_container, False, False, 0)
switch_container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
switch_container.pack_start(self.switch, False, False, 0)
switch_container.set_valign(Gtk.Align.CENTER)
self.pack_end(switch_container, False, False, 0)
def __on_toggled(self, *_):
Settings.get_default().set_boolean(self._schema, not self.switch.get_state())
self.emit("changed", not self.switch.get_state())
class SettingsBoxWithEntry(Gtk.Box):
def __init__(self, label, is_password=False):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)
self.get_style_context().add_class("settings-box")
self.entry = Gtk.Entry()
if is_password:
self.entry.set_visibility(False)
self._build_widgets(label)
def _build_widgets(self, label):
entry_label = Gtk.Label()
entry_label.set_text(label)
entry_label.get_style_context().add_class("settings-box-main-label")
entry_label.set_halign(Gtk.Align.START)
self.pack_start(entry_label, True, True, 6)
self.pack_end(self.entry, False, False, 6)
class PasswordWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.set_modal(True)
self.set_size_request(500, 400)
self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
self.resize(500, 400)
self.set_resizable(False)
self.set_border_width(36)
self.old_password = None
self._apply_btn = Gtk.Button()
self._build_widgets()
def _build_widgets(self):
header_bar = Gtk.HeaderBar()
header_bar.set_title(_("Authentication Password"))
header_bar.set_show_close_button(True)
self.set_titlebar(header_bar)
self._apply_btn.set_label(_("Save"))
self._apply_btn.connect("clicked", self.__on_apply_button_clicked)
self._apply_btn.set_sensitive(False)
self._apply_btn.get_style_context().add_class("suggested-action")
header_bar.pack_end(self._apply_btn)
container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
if Keyring.has_password():
self.old_password = SettingsBoxWithEntry(_("Old Password"), True)
self.old_password.entry.connect("changed", self._validate)
container.pack_start(self.old_password, False, False, 6)
self.password = SettingsBoxWithEntry(_("Password"), True)
self.password.entry.connect("changed", self._validate)
self.repeat_password = SettingsBoxWithEntry(_("Repeat Password"), True)
self.repeat_password.entry.connect("changed", self._validate)
container.pack_start(self.password, False, False, 6)
container.pack_start(self.repeat_password, False, False, 6)
self.add(container)
def _validate(self, *_):
password = self.password.entry.get_text()
repeat_password = self.repeat_password.entry.get_text()
if not password:
self.password.entry.get_style_context().add_class("error")
valid_password = False
else:
self.password.entry.get_style_context().remove_class("error")
valid_password = True
if not repeat_password or password != repeat_password:
self.repeat_password.entry.get_style_context().add_class("error")
valid_repeat_password = False
else:
self.repeat_password.entry.get_style_context().remove_class("error")
valid_repeat_password = True
to_validate = [valid_password, valid_repeat_password]
if self.old_password:
old_password = self.old_password.entry.get_text()
if not old_password or old_password != Keyring.get_password():
self.old_password.entry.get_style_context().add_class("error")
valid_old_password = False
else:
self.old_password.entry.get_style_context().remove_class("error")
valid_old_password = True
to_validate.append(valid_old_password)
self._apply_btn.set_sensitive(all(to_validate))
def __on_apply_button_clicked(self, *_):
if self._apply_btn.get_sensitive():
password = self.password.entry.get_text()
Keyring.set_password(password)
self.destroy()
class SettingsView:
MAIN = 0
PASSWORD = 1
@Gtk.Template(resource_path='/com/github/bilelmoussaoui/Authenticator/settings.ui')
class SettingsWindow(Gtk.Window):
__gtype_name__ = 'SettingsWindow'
lock_switch = Gtk.Template.Child()
dark_theme_switch = Gtk.Template.Child()
headerbar = Gtk.Template.Child()
headerbar_stack = Gtk.Template.Child()
main_stack = Gtk.Template.Child()
save_btn = Gtk.Template.Child()
password_entry = Gtk.Template.Child()
repeat_password_entry = Gtk.Template.Child()
notification = Gtk.Template.Child()
notification_label = Gtk.Template.Child()
view = GObject.Property(type=int)
def __init__(self):
Gtk.Window.__init__(self)
self.set_transient_for(Window.get_default())
self.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
self.set_size_request(600, 600)
self.set_title(_("Settings"))
self.resize(600, 600)
super(SettingsWindow, self).__init__()
self.init_template('SettingsWindow')
self.stack_switcher = Gtk.StackSwitcher()
self.stack = Gtk.Stack()
self.connect("notify::view", self.__update_view)
self._build_widgets()
self.__init_widgets()
def _build_widgets(self):
header_bar = Gtk.HeaderBar()
header_bar.set_show_close_button(True)
self.set_titlebar(header_bar)
header_bar.set_custom_title(self.stack_switcher)
self.stack_switcher.set_stack(self.stack)
self.stack.get_style_context().add_class("settings-main-container")
def __init_widgets(self):
settings = Settings.get_default()
settings.bind("night-mode", self.dark_theme_switch, "state", Gio.SettingsBindFlags.DEFAULT)
appearance_container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
dark_theme = SwitchSettingsBox(_("Dark theme"), _("Use a dark theme, if possible"), "night-mode")
dark_theme.connect("changed", self.__on_dark_theme_changed)
appearance_container.pack_start(dark_theme, False, False, 0)
self.stack.add_titled(appearance_container, "appearance", _("Appearance"))
self.lock_switch.set_active(Keyring.get_default().has_password())
behaviour_container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
@Gtk.Template.Callback('lock_switch_state_changed')
def __on_app_set_password(self, __, state):
if state and not Keyring.get_default().has_password():
self.props.view = SettingsView.PASSWORD
else:
Keyring.get_default().clear_password()
self.__send_notification(_("Authentication password was unset. Please restart the application"))
clear_database = ClickableSettingsBox(_("Clear the database"), _("Erase existing accounts"))
clear_database.connect("button-press-event", self.__on_clear_database_clicked)
@Gtk.Template.Callback('save_btn_clicked')
def __save_password(self, *__):
if self.save_btn.get_sensitive():
password = self.password_entry.get_text()
Keyring.set_password(password)
self.props.view = SettingsView.MAIN
self.__send_notification(_("Authentication password is now enabled. Please restart the application."))
app_can_be_locked = SwitchSettingsBox(_("Lock the application"),
_("Possibility to lock the application with a password"), "can-be-locked")
app_can_be_locked.connect("changed", self.__on_app_can_be_locked_changed)
app_password = ClickableSettingsBox(_("Authentication password"),
_("Set up application authentication password"))
app_password.connect("button-press-event", self.__on_app_set_password)
behaviour_container.pack_start(clear_database, False, False, 0)
behaviour_container.pack_start(app_can_be_locked, False, False, 0)
behaviour_container.pack_start(app_password, False, False, 0)
self.stack.add_titled(behaviour_container, "behaviour", _("Behaviour"))
self.add(self.stack)
def __on_app_can_be_locked_changed(self, __, state):
"""notification = Gd.Notification()
notification.set_timeout(5)
notification_lbl = Gtk.Label()
notification_lbl.set_text(_("The application needs to be restarted first."))
notification.add(notification_lbl)
notification_parent = self.stack.get_child_by_name("behaviour")
notification_parent.add(notification)
notification_parent.reorder_child(notification, 0)
"""
self.show_all()
if state and not Keyring.has_password():
self.__on_app_set_password()
def __on_app_set_password(self, *_):
password_window = PasswordWindow()
password_window.set_transient_for(self)
password_window.show_all()
@Gtk.Template.Callback('back_btn_clicked')
def __back_btn_clicked(self, *_):
self.props.view = SettingsView.MAIN
if not Keyring.get_default().has_password():
self.lock_switch.set_active(False)
@Gtk.Template.Callback('dark_theme_switch_state_changed')
@staticmethod
def __on_dark_theme_changed(_, state):
gtk_settings = Gtk.Settings.get_default()
gtk_settings.set_property("gtk-application-prefer-dark-theme",
state)
def __on_clear_database_clicked(self, *__):
"""
notification = Gd.Notification()
notification.set_timeout(5)
notification.connect("dismissed", self.__clear_database)
container = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
@Gtk.Template.Callback('password_entry_changed')
def __validate_password(self, *_):
password = self.password_entry.get_text()
repeat_password = self.repeat_password_entry.get_text()
if not password:
self.password_entry.get_style_context().add_class("error")
valid_password = False
else:
self.password_entry.get_style_context().remove_class("error")
valid_password = True
notification_lbl = Gtk.Label()
notification_lbl.set_text(_("The existing accounts will be erased in 5 seconds"))
container.pack_start(notification_lbl, False, False, 3)
if not repeat_password or password != repeat_password:
self.repeat_password_entry.get_style_context().add_class("error")
valid_repeat_password = False
else:
self.repeat_password_entry.get_style_context().remove_class("error")
valid_repeat_password = True
undo_btn = Gtk.Button()
undo_btn.set_label(_("Undo"))
undo_btn.connect("clicked", lambda widget: notification.hide())
container.pack_end(undo_btn, False, False, 3)
to_validate = [valid_password, valid_repeat_password]
notification.add(container)
notification_parent = self.stack.get_child_by_name("behaviour")
notification_parent.add(notification)
notification_parent.reorder_child(notification, 0)
"""
self.show_all()
self.save_btn.set_sensitive(all(to_validate))
@staticmethod
def __clear_database(*_):
from ..models import Database, Keyring, AccountsManager
from ..widgets.accounts import AccountsWidget
Database.get_default().clear()
Keyring.get_default().clear()
AccountsManager.get_default().clear()
AccountsWidget.get_default().clear()
def __update_view(self, *_):
if self.props.view == SettingsView.PASSWORD:
self.main_stack.set_visible_child_name("password_view")
self.headerbar_stack.set_visible_child_name("headerbar_password")
self.headerbar.set_show_close_button(False)
self.notification.set_reveal_child(False)
self.notification_label.set_text("")
else:
self.main_stack.set_visible_child_name("settings_view")
self.headerbar_stack.set_visible_child_name("headerbar_settings")
self.headerbar.set_show_close_button(True)
# Reset Password View
# To avoid user saving a password he doesn't remember
self.password_entry.set_text("")
self.repeat_password_entry.set_text("")
self.password_entry.get_style_context().remove_class("error")
self.repeat_password_entry.get_style_context().remove_class("error")
self.save_btn.set_sensitive(False)
def __send_notification(self, message):
self.notification_label.set_text(message)
self.notification.set_reveal_child(True)
GLib.timeout_add_seconds(5,
lambda _: self.notification.set_reveal_child(False), None)