Commit 75f15498 authored by Bilal Elmoussaoui's avatar Bilal Elmoussaoui

LoginWidget: remove uneeded widget, use Gtk.Template

reduce the complexity of the code by adding a GObject Property to the main window
this allows us to keep the state tracking pretty simple
parent fc369c3a
Pipeline #58278 passed with stages
in 5 minutes and 49 seconds
......@@ -5,7 +5,7 @@ trim_trailing_whitespace = true
insert_final_newline = true
charset = utf-8
[*.py]
[*.{py,py.in}]
indent_size = 4
[*.build]
......
......@@ -6,7 +6,7 @@
<file alias="qrscanner-symbolic.svg">icons/hicolor/symbolic/actions/qrscanner-symbolic.svg</file>
<!-- Accounts logo fallback -->
<file alias="authenticator-fallback">icons/hicolor/scalable/apps/com.github.bilelmoussaoui.Authenticator.svg</file>
<file alias="authenticator-symbolic.svg">icons/hicolor/symbolic/apps/com.github.bilelmoussaoui.Authenticator-symbolic.svg</file>
<!-- UI Files -->
<file compressed="true" preprocess="xml-stripblanks" alias="shortcuts.ui">ui/shortcuts.ui</file>
......
......@@ -157,6 +157,65 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="LoginWidget">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="border_width">36</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="resource">/com/github/bilelmoussaoui/Authenticator/authenticator-symbolic.svg</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">10</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="halign">center</property>
<property name="visibility">False</property>
<property name="text" translatable="yes">1656656</property>
<property name="input_purpose">password</property>
</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="GtkButton" id="unlock_btn">
<property name="label" translatable="yes">Unlock</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<signal name="clicked" handler="unlock_btn_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">locked_state</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
......
Authenticator/application.py.in
Authenticator/models/account.py
Authenticator/widgets/accounts/add.py
Authenticator/widgets/accounts/edit.py
Authenticator/widgets/accounts/list.py
Authenticator/widgets/accounts/row.py
Authenticator/widgets/actions_bar.py
Authenticator/widgets/headerbar.py
Authenticator/widgets/search_bar.py
Authenticator/widgets/settings.py
Authenticator/widgets/utils.py
Authenticator/widgets/window.py.in
data/com.github.bilelmoussaoui.Authenticator.appdata.xml.in.in
data/com.github.bilelmoussaoui.Authenticator.desktop.in.in
data/com.github.bilelmoussaoui.Authenticator.gschema.xml.in
data/ui/about_dialog.ui.in
data/ui/shortcuts.ui
authenticator.py.in
src/authenticator.py.in
src/Authenticator/application.py.in
src/Authenticator/models/account.py
src/Authenticator/widgets/accounts/add.py
src/Authenticator/widgets/accounts/edit.py
src/Authenticator/widgets/accounts/list.py
src/Authenticator/widgets/accounts/row.py
src/Authenticator/widgets/settings.py
src/Authenticator/widgets/utils.py
src/Authenticator/widgets/window.py
......@@ -22,8 +22,8 @@ from gi import require_version
require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gio, Gdk, GObject
from .widgets import Window, AboutDialog, import_json, export_json
from .models import Settings, Clipboard, Logger
from .widgets import Window, WindowState, AboutDialog, import_json, export_json
from .models import Database, Settings, Clipboard, Logger
class Application(Gtk.Application):
......@@ -45,10 +45,13 @@ class Application(Gtk.Application):
def __is_locked_changed(self, *_):
if self.is_locked:
Window.get_default().emit("locked")
Window.get_default().state = WindowState.LOCKED
else:
Window.get_default().emit("unlocked")
count = Database.get_default().count
if count == 0:
Window.get_default().state = WindowState.EMPTY
else:
Window.get_default().state = WindowState.NORMAL
@staticmethod
def get_default():
if Application.instance is None:
......
......@@ -18,7 +18,6 @@
"""
from .about import AboutDialog
from .accounts import AccountsList, AccountRow
from .login import LoginWidget
from .window import Window
from .window import Window, WindowState
from .settings import SettingsWindow
from .utils import import_json, export_json
......@@ -30,9 +30,6 @@ from ...utils import load_pixbuf_from_provider
class AccountsWidget(Gtk.Box, GObject.GObject):
__gsignals__ = {
'changed': (GObject.SignalFlags.RUN_LAST, None, ())
}
instance = None
def __init__(self):
......@@ -79,7 +76,6 @@ class AccountsWidget(Gtk.Box, GObject.GObject):
self.accounts_container.pack_start(provider_widget, False, False, 0)
accounts_list.add_row(account)
self._reorder()
self.emit("changed")
@property
def accounts_lists(self):
......@@ -89,7 +85,6 @@ class AccountsWidget(Gtk.Box, GObject.GObject):
for account_list in self._providers.values():
self.accounts_container.remove(account_list.get_parent())
self._providers = {}
self.emit("changed")
def set_state(self, state):
for account_list in self._providers.values():
......
"""
Copyright © 2017 Bilal Elmoussaoui <bil.elmoussaoui@gmail.com>
This file is part of Authenticator.
Authenticator 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.
Authenticator 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 Authenticator. If not, see <http://www.gnu.org/licenses/>.
"""
from gettext import gettext as _
from gi import require_version
require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio
class LoginWidget(Gtk.Box):
instance = None
def __init__(self):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
self.login_btn = Gtk.Button()
self._password_entry = Gtk.Entry()
self._build_widgets()
@staticmethod
def get_default():
if LoginWidget.instance is None:
LoginWidget.instance = LoginWidget()
return LoginWidget.instance
def _build_widgets(self):
self.set_border_width(36)
self.set_halign(Gtk.Align.CENTER)
self.set_valign(Gtk.Align.FILL)
info_container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
info_container.set_valign(Gtk.Align.START)
gicon = Gio.ThemedIcon(name="dialog-password-symbolic")
image = Gtk.Image.new_from_gicon(gicon, Gtk.IconSize.DIALOG)
label = Gtk.Label()
label.set_text(_("Authenticator is locked"))
label.get_style_context().add_class("loginwidget-mainlabel")
sub_label = Gtk.Label()
sub_label.set_text(_("Enter password to unlock"))
sub_label.get_style_context().add_class("loginwidget-sublabel")
info_container.pack_start(image, False, False, 6)
info_container.pack_start(label, False, False, 3)
info_container.pack_start(sub_label, False, False, 3)
password_container = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self._password_entry.set_placeholder_text(_("Type your password here"))
self._password_entry.set_visibility(False)
self._password_entry.grab_focus_without_selecting()
self.login_btn.set_label(_("Unlock"))
password_container.pack_start(self._password_entry, False, False, 3)
password_container.pack_start(self.login_btn, False, False, 3)
password_container.set_valign(Gtk.Align.CENTER)
self.pack_start(info_container, False, False, 3)
self.pack_start(password_container, True, False, 3)
def set_has_error(self, has_errors):
if has_errors:
self._password_entry.get_style_context().add_class("error")
else:
self._password_entry.get_style_context().remove_class("error")
@property
def password(self):
return self._password_entry.get_text()
@password.setter
def password(self, new_password):
self._password_entry.set_text(new_password)
......@@ -18,12 +18,9 @@
"""
from gettext import gettext as _
from gi import require_version
require_version("Gtk", "3.0")
from gi.repository import Gtk, GObject, Gio, GLib
from ..models import Logger, Settings, Database, AccountsManager
from ..models import Logger, Settings, AccountsManager
from .accounts import AccountsWidget, AddAccountWindow
from . import LoginWidget
class WindowState:
NORMAL = 0
......@@ -35,9 +32,7 @@ class WindowState:
class Window(Gtk.ApplicationWindow, GObject.GObject):
"""Main Window object."""
__gsignals__ = {
'changed': (GObject.SignalFlags.RUN_LAST, None, (bool,)),
'locked': (GObject.SignalFlags.RUN_LAST, None, ()),
'unlocked': (GObject.SignalFlags.RUN_LAST, None, ())
'changed': (GObject.SignalFlags.RUN_LAST, None, (bool,))
}
__gtype_name__ = 'Window'
......@@ -45,7 +40,7 @@ class Window(Gtk.ApplicationWindow, GObject.GObject):
# Default Window instance
instance = None
is_empty = GObject.Property(type=bool, default=False)
state = GObject.Property(type=int, default=0)
headerbar = Gtk.Template.Child()
......@@ -63,12 +58,14 @@ class Window(Gtk.ApplicationWindow, GObject.GObject):
accounts_viewport = Gtk.Template.Child()
unlock_btn = Gtk.Template.Child()
password_entry = Gtk.Template.Child()
def __init__(self):
super(Window, self).__init__()
self.init_template('Window')
self.connect("locked", self.__on_locked)
self.connect("unlocked", self.__on_unlocked)
self.connect("notify::state", self.__state_changed)
self.key_press_signal = None
self.restore_state()
......@@ -102,19 +99,6 @@ class Window(Gtk.ApplicationWindow, GObject.GObject):
popover.set_visible(not popover.get_visible())
self.primary_menu_btn.connect('clicked', primary_menu_btn_handler, popover)
def update_view(self, *_):
count = Database.get_default().count
self.set_property("is-empty", count == 0)
print("hey")
if not self.is_empty:
self.main_stack.set_visible_child_name("normal_state")
child_name = "normal_state"
self.props.state = WindowState.NORMAL
else:
self.main_stack.set_visible_child_name("empty_state")
child_name = "empty_state"
self.props.state = WindowState.EMPTY
def toggle_search(self, *_):
"""
Switch the state of the search mode
......@@ -124,7 +108,7 @@ class Window(Gtk.ApplicationWindow, GObject.GObject):
- There are at least one account in the database
return: None
"""
if not (self.get_application().is_locked or self.is_empty):
if self.props.state == WindowState.NORMAL:
toggled = not self.search_bar.get_property("search_mode_enabled")
self.search_bar.set_property("search_mode_enabled", toggled)
......@@ -156,55 +140,31 @@ class Window(Gtk.ApplicationWindow, GObject.GObject):
def __init_widgets(self):
"""Build main window widgets."""
# Register Actions
self.__add_action("add-account", self.add_account)
self.__add_action("toggle-searchbar", self.toggle_search)
# Set up accounts Widget
accounts_widget = AccountsWidget.get_default()
accounts_widget.connect("changed", self.update_view)
self.accounts_viewport.add(accounts_widget)
# Login Widget
login_widget = LoginWidget.get_default()
login_widget.login_btn.connect("clicked", self.__on_unlock)
self.main_stack.add_named(login_widget, "login")
self.update_view()
def _on_account_delete(self, *_):
self.update_view()
self.notify("state")
def __on_delete_clicked(self, *__):
self.notification_label.set_text(_("An account or more were removed."))
self.notification.set_reveal_child(True)
GLib.timeout_add_seconds(5,
lambda _: self.notification.set_reveal_child(False), None)
def __on_locked(self, *_):
if self.key_press_signal:
self.disconnect(self.key_press_signal)
self.props.state = WindowState.LOCKED
self.main_stack.set_visible_child_name("login")
def __on_unlocked(self, *_):
self.update_view()
def __on_unlock(self, *_):
@Gtk.Template.Callback('unlock_btn_clicked')
def __unlock_btn_clicked(self, *_):
from ..models import Keyring
login_widget = LoginWidget.get_default()
typed_password = login_widget.password
typed_password = self.password_entry.get_text()
if typed_password == Keyring.get_password():
self.get_application().set_property("is-locked", False)
login_widget.set_has_error(False)
login_widget.password = ""
# Reset password entry
self.password_entry.get_style_context().remove_class("error")
self.password_entry.set_text("")
# Connect on type search bar
self.key_press_signal = self.connect("key-press-event", lambda x,
y: self.search_bar.handle_event(y))
self.update_view()
else:
login_widget.set_has_error(True)
self.password_entry.get_style_context().add_class("error")
def __add_action(self, key, callback, prop_bind=None, bind_flag=GObject.BindingFlags.INVERT_BOOLEAN):
action = Gio.SimpleAction.new(key, None)
......@@ -213,6 +173,28 @@ class Window(Gtk.ApplicationWindow, GObject.GObject):
self.bind_property(prop_bind, action, "enabled", bind_flag)
self.add_action(action)
def __state_changed(self, *_):
if self.props.state == WindowState.LOCKED:
visible_child = "locked_state"
self.add_btn.set_visible(False)
self.add_btn.set_no_show_all(True)
self.search_btn.set_visible(False)
self.search_btn.set_no_show_all(True)
if self.key_press_signal:
self.disconnect(self.key_press_signal)
else:
if self.props.state == WindowState.EMPTY:
visible_child = "empty_state"
self.search_btn.set_visible(False)
self.search_btn.set_no_show_all(True)
else:
visible_child = "normal_state"
self.search_btn.set_visible(True)
self.search_btn.set_no_show_all(False)
self.add_btn.set_visible(True)
self.add_btn.set_no_show_all(False)
self.main_stack.set_visible_child_name(visible_child)
@Gtk.Template.Callback('search_changed')
def __search_changed(self, entry):
"""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment