Commit 5ed83e04 authored by Bilal Elmoussaoui's avatar Bilal Elmoussaoui

ui improvements and fix #5

parent cc3d46e9
...@@ -12,13 +12,17 @@ import signal ...@@ -12,13 +12,17 @@ import signal
from gettext import gettext as _ from gettext import gettext as _
from os import environ as env from os import environ as env
class Application(Gtk.Application): class Application(Gtk.Application):
win = None win = None
alive = True alive = True
locked = False locked = False
menu = Gio.Menu() menu = Gio.Menu()
auth = Authenticator() auth = Authenticator()
use_GMenu = None use_GMenu = True
settings_window = None
settings_action = None
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
for key in kwargs: for key in kwargs:
...@@ -61,25 +65,28 @@ class Application(Gtk.Application): ...@@ -61,25 +65,28 @@ class Application(Gtk.Application):
logging.debug("Adding gnome shell menu") logging.debug("Adding gnome shell menu")
def generate_menu(self): def generate_menu(self):
pass_enabled = self.cfg.read("state", "login") # Settings section
if pass_enabled: settings_content = Gio.Menu.new()
if self.locked: settings_content.append_item(Gio.MenuItem.new(_("Settings"), "app.settings"))
self.menu.append(_("Unlock the Application"), "app.lock") settings_section = Gio.MenuItem.new_section(None, settings_content)
else: self.menu.append_item(settings_section)
self.menu.append(_("Lock the Application"), "app.lock")
# Help section
help_content = Gio.Menu.new()
if Gtk.get_major_version() >= 3 and Gtk.get_minor_version() >= 20:
help_content.append_item(Gio.MenuItem.new(_("Shortcuts"), "app.shortcuts"))
if not self.locked: help_content.append_item(Gio.MenuItem.new(_("About"), "app.about"))
self.menu.append(_("Settings"), "app.settings") help_content.append_item(Gio.MenuItem.new(_("Quit"), "app.quit"))
help_section = Gio.MenuItem.new_section(None, help_content)
self.menu.append_item(help_section)
if Gtk.get_major_version() >= 3 and Gtk.get_minor_version() >= 20:
self.menu.append(_("Shortcuts"), "app.shortcuts")
self.menu.append(_("About"), "app.about")
self.menu.append(_("Quit"), "app.quit")
self.set_app_menu(self.menu) self.set_app_menu(self.menu)
action = Gio.SimpleAction.new("settings", None) self.settings_action = Gio.SimpleAction.new("settings", None)
action.connect("activate", self.on_settings) self.settings_action.connect("activate", self.on_settings)
self.add_action(action) self.settings_action.set_enabled(not self.locked)
self.add_action(self.settings_action)
if Gtk.get_major_version() >= 3 and Gtk.get_minor_version() >= 20: if Gtk.get_major_version() >= 3 and Gtk.get_minor_version() >= 20:
action = Gio.SimpleAction.new("shortcuts", None) action = Gio.SimpleAction.new("shortcuts", None)
...@@ -90,10 +97,6 @@ class Application(Gtk.Application): ...@@ -90,10 +97,6 @@ class Application(Gtk.Application):
action.connect("activate", self.on_about) action.connect("activate", self.on_about)
self.add_action(action) self.add_action(action)
action = Gio.SimpleAction.new("lock", None)
action.connect("activate", self.on_toggle_lock)
self.add_action(action)
action = Gio.SimpleAction.new("quit", None) action = Gio.SimpleAction.new("quit", None)
action.connect("activate", self.on_quit) action.connect("activate", self.on_quit)
self.add_action(action) self.add_action(action)
...@@ -103,29 +106,9 @@ class Application(Gtk.Application): ...@@ -103,29 +106,9 @@ class Application(Gtk.Application):
self.win.show_all() self.win.show_all()
self.add_window(self.win) self.add_window(self.win)
def toggle_settings_menu(self):
if self.locked:
self.menu.remove(1)
else:
self.menu.insert(1, _("Settings"), "app.settings")
def refresh_menu(self): def refresh_menu(self):
if self.use_GMenu: if self.use_GMenu:
self.menu.remove_all() self.settings_action.set_enabled(not self.settings_action.get_enabled())
shortcuts_enabled = Gtk.get_major_version() >= 3 and Gtk.get_minor_version() >= 20
pass_enabled = self.cfg.read("state", "login")
can_be_locked = not self.app.locked and pass_enabled
if can_be_locked:
self.menu.append(_("Lock the Application"), "app.lock")
if shortcuts_enabled:
self.menu.append(_("Shortcuts"), "app.shortcuts")
if not self.locked:
self.menu.insert(1, _("Settings"), "app.settings")
self.menu.append(_("About"), "app.about")
self.menu.append(_("Quit"), "app.quit")
def on_toggle_lock(self, *args): def on_toggle_lock(self, *args):
if not self.locked: if not self.locked:
...@@ -144,7 +127,10 @@ class Application(Gtk.Application): ...@@ -144,7 +127,10 @@ class Application(Gtk.Application):
""" """
Shows settings window Shows settings window
""" """
SettingsWindow(self.win) if not self.settings_window:
self.settings_window = SettingsWindow(self.win)
else:
self.settings_window.show()
def on_quit(self, *args): def on_quit(self, *args):
""" """
......
...@@ -18,6 +18,8 @@ class AddAuthenticator(Gtk.Window): ...@@ -18,6 +18,8 @@ class AddAuthenticator(Gtk.Window):
secret_code = Gtk.Entry() secret_code = Gtk.Entry()
name_entry = Gtk.Entry() name_entry = Gtk.Entry()
logo_finder_window = None
def __init__(self, window): def __init__(self, window):
self.parent = window self.parent = window
self.generate_window() self.generate_window()
...@@ -42,7 +44,7 @@ class AddAuthenticator(Gtk.Window): ...@@ -42,7 +44,7 @@ class AddAuthenticator(Gtk.Window):
Keyboard Listener handler Keyboard Listener handler
""" """
if Gdk.keyval_name(key_event.keyval) == "Escape": if Gdk.keyval_name(key_event.keyval) == "Escape":
self.destroy() self.close_window()
def update_logo(self, image): def update_logo(self, image):
""" """
...@@ -179,7 +181,10 @@ class AddAuthenticator(Gtk.Window): ...@@ -179,7 +181,10 @@ class AddAuthenticator(Gtk.Window):
Shows icon finder window Shows icon finder window
select icon by icon name select icon by icon name
""" """
IconFinderWindow(self) if not self.logo_finder_window:
self.logo_finder_window = IconFinderWindow(self)
else:
self.logo_finder_window.show()
def add_filters(self, dialog): def add_filters(self, dialog):
""" """
......
...@@ -152,4 +152,5 @@ class PasswordWindow(Gtk.Window): ...@@ -152,4 +152,5 @@ class PasswordWindow(Gtk.Window):
""" """
Close the window Close the window
""" """
self.destroy() self.hide()
return True
...@@ -28,6 +28,14 @@ class IconFinderWindow(Gtk.Window): ...@@ -28,6 +28,14 @@ class IconFinderWindow(Gtk.Window):
self.set_position(Gtk.WindowPosition.CENTER) self.set_position(Gtk.WindowPosition.CENTER)
self.set_resizable(False) self.set_resizable(False)
self.set_transient_for(self.parent) self.set_transient_for(self.parent)
self.connect("key_press_event", self.on_key_press)
def on_key_press(self, key, key_event):
"""
Keyboard Listener handler
"""
if Gdk.keyval_name(key_event.keyval) == "Escape":
self.close_window()
def generate_components(self): def generate_components(self):
""" """
...@@ -100,4 +108,5 @@ class IconFinderWindow(Gtk.Window): ...@@ -100,4 +108,5 @@ class IconFinderWindow(Gtk.Window):
""" """
Close the window Close the window
""" """
self.destroy() self.hide()
return True
from gi import require_version from gi import require_version
require_version("Gtk", "3.0") require_version("Gtk", "3.0")
from gi.repository import Gtk from gi.repository import Gtk, Gdk
from TwoFactorAuth.models.settings import SettingsReader from TwoFactorAuth.models.settings import SettingsReader
from TwoFactorAuth.widgets.change_password import PasswordWindow from TwoFactorAuth.widgets.change_password import PasswordWindow
from gettext import gettext as _ from gettext import gettext as _
...@@ -9,9 +9,13 @@ from gettext import gettext as _ ...@@ -9,9 +9,13 @@ from gettext import gettext as _
class SettingsWindow(Gtk.Window): class SettingsWindow(Gtk.Window):
notebook = Gtk.Notebook() notebook = Gtk.Notebook()
time_spin_button = Gtk.SpinButton() time_spin_button = Gtk.SpinButton()
auto_lock_time = Gtk.SpinButton()
enable_switch = Gtk.Switch() enable_switch = Gtk.Switch()
auto_lock_switch = Gtk.Switch()
password_button = Gtk.Button() password_button = Gtk.Button()
password_window = None
def __init__(self, parent): def __init__(self, parent):
self.parent = parent self.parent = parent
self.cfg = SettingsReader() self.cfg = SettingsReader()
...@@ -20,14 +24,22 @@ class SettingsWindow(Gtk.Window): ...@@ -20,14 +24,22 @@ class SettingsWindow(Gtk.Window):
self.show_all() self.show_all()
def generate_window(self): def generate_window(self):
Gtk.Window.__init__(self, title=_("Settings"), modal=True, Gtk.Window.__init__(self, title=_("Settings"),
destroy_with_parent=True) destroy_with_parent=True)
self.connect("delete-event", self.close_window) self.connect("delete-event", self.close_window)
self.resize(300, 300) self.resize(400, 300)
self.set_size_request(300, 300) self.set_size_request(400, 300)
self.set_resizable(False) self.set_resizable(False)
self.set_position(Gtk.WindowPosition.CENTER) self.set_position(Gtk.WindowPosition.CENTER)
self.set_transient_for(self.parent) self.set_transient_for(self.parent)
self.connect("key_press_event", self.on_key_press)
def on_key_press(self, key, key_event):
"""
Keyboard Listener handler
"""
if Gdk.keyval_name(key_event.keyval) == "Escape":
self.close_window()
def generate_components(self): def generate_components(self):
""" """
...@@ -91,21 +103,53 @@ class SettingsWindow(Gtk.Window): ...@@ -91,21 +103,53 @@ class SettingsWindow(Gtk.Window):
time_box.pack_start(time_label, False, True, 0) time_box.pack_start(time_label, False, True, 0)
time_box.pack_end(self.time_spin_button, False, True, 0) time_box.pack_end(self.time_spin_button, False, True, 0)
is_auto_lock_active = bool(self.cfg.read("auto-lock", "preferences"))
auto_lock_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
auto_lock_label = Gtk.Label(_("Auto-lock the Application"))
self.auto_lock_switch.set_active(is_auto_lock_active)
self.auto_lock_switch.connect("notify::active", self.on_auto_lock_activated)
auto_lock_box.pack_start(auto_lock_label, False, True, 0)
auto_lock_box.pack_end(self.auto_lock_switch, False, True, 0)
auto_lock_time_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
auto_lock_time_label = Gtk.Label(_("Auto-lock time (m): "))
default_value = self.cfg.read("auto-lock-time", "preferences")
if default_value < 1 or default_value > 10:
default_value = 3
adjustment = Gtk.Adjustment(default_value, 1, 10, 1, 1, 0)
self.auto_lock_time.connect("value-changed", self.on_auto_lock_time_changed)
self.auto_lock_time.set_adjustment(adjustment)
self.auto_lock_time.set_sensitive(is_auto_lock_active)
self.auto_lock_time.set_value(default_value)
auto_lock_time_box.pack_start(auto_lock_time_label, False, True, 0)
auto_lock_time_box.pack_end(self.auto_lock_time, False, True, 0)
main_box.pack_start(time_box, False, True, 6) main_box.pack_start(time_box, False, True, 6)
main_box.pack_start(auto_lock_box, False, True, 6)
main_box.pack_start(auto_lock_time_box, False, True, 6)
return main_box return main_box
def new_password_window(self, *args): def new_password_window(self, *args):
""" """
Show a new password window Show a new password window
""" """
PasswordWindow(self) if not self.password_window:
self.password_window = PasswordWindow(self)
else:
self.password_window.show()
def on_time_changed(self, spin_button): def on_time_changed(self, spin_button):
""" """
Update time tog generate a new secret code Update time tog generate a new secret code
""" """
self.cfg.update("refresh-time", spin_button.get_value_as_int(), self.cfg.update("refresh-time", spin_button.get_value_as_int(), "preferences")
"preferences")
def on_auto_lock_time_changed(self, spin_button):
"""
Update time tog generate a new secret code
"""
self.cfg.update("auto-lock-time", spin_button.get_value_as_int(), "preferences")
def on_switch_activated(self, switch, *args): def on_switch_activated(self, switch, *args):
""" """
...@@ -113,11 +157,19 @@ class SettingsWindow(Gtk.Window): ...@@ -113,11 +157,19 @@ class SettingsWindow(Gtk.Window):
""" """
self.password_button.set_sensitive(switch.get_active()) self.password_button.set_sensitive(switch.get_active())
self.cfg.update("state", switch.get_active(), "login") self.cfg.update("state", switch.get_active(), "login")
self.parent.app.refresh_menu()
self.parent.refresh_menu_popover() self.parent.refresh_window()
def on_auto_lock_activated(self, switch, *args):
"""
Update auto-lock state : enabled/disabled
"""
self.auto_lock_time.set_sensitive(switch.get_active())
self.cfg.update("auto-lock", switch.get_active(), "preferences")
def close_window(self, *args): def close_window(self, *args):
""" """
Close the window Close the window
""" """
self.destroy() self.hide()
\ No newline at end of file return True
\ No newline at end of file
from gi import require_version from gi import require_version
require_version("Gtk", "3.0") require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio, Gdk from gi.repository import Gtk, Gio, Gdk, GObject
from TwoFactorAuth.widgets.add_authenticator import AddAuthenticator from TwoFactorAuth.widgets.add_authenticator import AddAuthenticator
from TwoFactorAuth.widgets.confirmation import ConfirmationMessage from TwoFactorAuth.widgets.confirmation import ConfirmationMessage
from TwoFactorAuth.widgets.listrow import ListBoxRow from TwoFactorAuth.widgets.listrow import ListBoxRow
...@@ -13,6 +13,7 @@ class Window(Gtk.ApplicationWindow): ...@@ -13,6 +13,7 @@ class Window(Gtk.ApplicationWindow):
app = None app = None
selected_app_idx = None selected_app_idx = None
selected_count = 0 selected_count = 0
counter = 0
hb = Gtk.HeaderBar() hb = Gtk.HeaderBar()
main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
...@@ -29,12 +30,11 @@ class Window(Gtk.ApplicationWindow): ...@@ -29,12 +30,11 @@ class Window(Gtk.ApplicationWindow):
remove_button = Gtk.Button() remove_button = Gtk.Button()
cancel_button = Gtk.Button() cancel_button = Gtk.Button()
select_button = Gtk.Button() select_button = Gtk.Button()
lock_button = Gtk.Button()
popover = Gtk.PopoverMenu().new() popover = Gtk.PopoverMenu().new()
pop_unlock = Gtk.ModelButton.new()
settings_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) settings_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
unlock_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) pop_settings = Gtk.ModelButton.new()
password_entry = Gtk.Entry() password_entry = Gtk.Entry()
search_entry = Gtk.Entry() search_entry = Gtk.Entry()
...@@ -47,6 +47,7 @@ class Window(Gtk.ApplicationWindow): ...@@ -47,6 +47,7 @@ class Window(Gtk.ApplicationWindow):
self.generate_no_apps_box() self.generate_no_apps_box()
self.generate_login_form() self.generate_login_form()
self.refresh_window() self.refresh_window()
GObject.timeout_add_seconds(60, self.refresh_counter)
def generate_window(self, *args): def generate_window(self, *args):
""" """
...@@ -99,10 +100,25 @@ class Window(Gtk.ApplicationWindow): ...@@ -99,10 +100,25 @@ class Window(Gtk.ApplicationWindow):
elif keypress == "escape": elif keypress == "escape":
if self.search_box.get_visible(): if self.search_box.get_visible():
self.toggle_search_box() self.toggle_search_box()
if not self.select_button.get_visible():
self.toggle_select()
else: else:
if keypress == "return": if keypress == "return":
self.on_unlock_clicked() self.on_unlock_clicked()
def refresh_counter(self):
"""
Add a value to the counter each 60 seconds
"""
print(self.counter)
if not self.app.locked:
self.counter += 1
if self.app.cfg.read("auto-lock", "preferences"):
if self.counter == self.app.cfg.read("auto-lock-time", "preferences") - 1:
self.counter = 0
self.toggle_app_lock()
return True
def filter_applications(self, entry): def filter_applications(self, entry):
data = entry.get_text().strip() data = entry.get_text().strip()
if len(data) != 0: if len(data) != 0:
...@@ -174,11 +190,7 @@ class Window(Gtk.ApplicationWindow): ...@@ -174,11 +190,7 @@ class Window(Gtk.ApplicationWindow):
if password == self.app.cfg.read("password", "login"): if password == self.app.cfg.read("password", "login"):
self.password_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, None) self.password_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, None)
self.toggle_app_lock() self.toggle_app_lock()
self.app.locked = False
self.app.toggle_settings_menu()
self.password_entry.set_text("") self.password_entry.set_text("")
self.app.refresh_menu()
else: else:
self.password_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "dialog-error-symbolic") self.password_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "dialog-error-symbolic")
...@@ -209,7 +221,7 @@ class Window(Gtk.ApplicationWindow): ...@@ -209,7 +221,7 @@ class Window(Gtk.ApplicationWindow):
""" """
Hide all buttons on the header bar Hide all buttons on the header bar
""" """
self.toggle_hb_buttons(False, False, False, False, False, False) self.toggle_hb_buttons(False, False, False, False, False, False, False)
def generate_header_bar(self): def generate_header_bar(self):
""" """
...@@ -254,9 +266,21 @@ class Window(Gtk.ApplicationWindow): ...@@ -254,9 +266,21 @@ class Window(Gtk.ApplicationWindow):
self.cancel_button.set_label(_("Cancel")) self.cancel_button.set_label(_("Cancel"))
self.cancel_button.connect("clicked", self.toggle_select) self.cancel_button.connect("clicked", self.toggle_select)
self.cancel_button.set_no_show_all(True) self.cancel_button.set_no_show_all(True)
pass_enabled = self.app.cfg.read("state", "login")
can_be_locked = not self.app.locked and pass_enabled
lock_icon = Gio.ThemedIcon(name="changes-prevent-symbolic")
lock_image = Gtk.Image.new_from_gicon(lock_icon, Gtk.IconSize.BUTTON)
self.lock_button.set_tooltip_text(_("Lock the Application"))
self.lock_button.set_image(lock_image)
self.lock_button.connect("clicked", self.app.on_toggle_lock)
self.lock_button.set_no_show_all(not can_be_locked)
self.lock_button.set_visible(can_be_locked)
right_box.add(self.search_button) right_box.add(self.search_button)
right_box.add(self.select_button) right_box.add(self.select_button)
right_box.add(self.cancel_button) right_box.add(self.cancel_button)
right_box.add(self.lock_button)
if not self.app.use_GMenu: if not self.app.use_GMenu:
self.generate_popover(right_box) self.generate_popover(right_box)
...@@ -281,32 +305,16 @@ class Window(Gtk.ApplicationWindow): ...@@ -281,32 +305,16 @@ class Window(Gtk.ApplicationWindow):
self.popover.add(popover_box) self.popover.add(popover_box)
shortcuts_enabled = Gtk.get_major_version() >= 3 and Gtk.get_minor_version() >= 20 shortcuts_enabled = Gtk.get_major_version() >= 3 and Gtk.get_minor_version() >= 20
pass_enabled = self.app.cfg.read("state", "login")
unlock_section_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.pop_unlock.connect("clicked", self.app.on_toggle_lock)
self.pop_unlock.get_style_context().add_class("flat")
self.pop_unlock.set_label(_("Lock the Application"))
unlock_section_box.pack_start(self.pop_unlock, False, False, 0)
unlock_section_box.pack_start(Gtk.Separator(), False, False, 0)
can_be_locked = not self.app.locked and pass_enabled self.pop_settings.set_label(_("Settings"))
self.unlock_box.set_no_show_all(not can_be_locked) self.pop_settings.get_style_context().add_class("flat")
self.unlock_box.set_visible(can_be_locked) self.pop_settings.connect("clicked", self.app.on_settings)
self.unlock_box.pack_start(unlock_section_box, True, True, 0) self.pop_settings.set_sensitive(not self.app.locked)
popover_box.pack_start(self.unlock_box, True, True, 0)
settings = Gtk.ModelButton.new()
settings.set_label(_("Settings"))
settings.get_style_context().add_class("flat")
settings.connect("clicked", self.app.on_settings)
settings_section_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) settings_section_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
settings_section_box.pack_start(settings, False, False, 0) settings_section_box.pack_start(self.pop_settings, False, False, 0)
settings_section_box.pack_start(Gtk.Separator(), False, False, 0) settings_section_box.pack_start(Gtk.Separator(), False, False, 0)
self.settings_box.set_visible(not self.app.locked)
self.settings_box.set_no_show_all(self.app.locked)
self.settings_box.pack_start(settings_section_box, True, True, 0) self.settings_box.pack_start(settings_section_box, True, True, 0)
popover_box.pack_start(self.settings_box, True, True, 0) popover_box.pack_start(self.settings_box, True, True, 0)
...@@ -332,17 +340,6 @@ class Window(Gtk.ApplicationWindow): ...@@ -332,17 +340,6 @@ class Window(Gtk.ApplicationWindow):
box.add(self.settings_button) box.add(self.settings_button)
def refresh_menu_popover(self):
if not self.app.use_GMenu:
pass_enabled = self.app.cfg.read("state", "login")
can_be_locked = not self.app.locked and pass_enabled
self.settings_box.set_visible(not self.app.locked)
self.unlock_box.set_visible(can_be_locked)
self.unlock_box.set_no_show_all(not can_be_locked)
self.settings_box.set_no_show_all(self.app.locked)
self.unlock_box.show_all()
self.settings_box.show_all()
def toggle_popover(self, *args): def toggle_popover(self, *args):
if self.popover: if self.popover:
if self.popover.get_visible(): if self.popover.get_visible():
...@@ -385,6 +382,9 @@ class Window(Gtk.ApplicationWindow): ...@@ -385,6 +382,9 @@ class Window(Gtk.ApplicationWindow):
self.remove_button.set_visible(not is_visible) self.remove_button.set_visible(not is_visible)
if not self.app.use_GMenu: if not self.app.use_GMenu:
self.settings_button.set_visible(is_visible) self.settings_button.set_visible(is_visible)
pass_enabled = self.app.cfg.read("state", "login")
self.lock_button.set_visible( is_visible and pass_enabled)