init a port to gtk4

This commit is contained in:
Bilal Elmoussaoui 2020-10-28 01:52:54 +01:00
parent f03eed607e
commit 338fd0fd37
40 changed files with 1460 additions and 2184 deletions

View file

@ -5,7 +5,7 @@ trim_trailing_whitespace = true
insert_final_newline = true
charset = utf-8
[*.{xml,build,sql}]
[*.{xml,ui,ui.in,build,sql}]
indent_size = 2
[*.{json,py,rs}]

926
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -4,19 +4,8 @@ version = "0.1.0"
edition = "2018"
[dependencies]
gtk = { version = "0.7", features = ["v3_22"] }
libhandy = "0.4"
glib = { version = "0.8", features = ["subclassing"] }
gio = { version = "0.7", features = ["v2_46"] }
gdk = "0.11"
gdk-sys = "0.9"
gobject-sys = "0.9"
glib-sys = "0.9"
cairo-rs = "0.7"
pango = "0.7"
log = "0.4"
gdk-pixbuf = {version = "0.7", features = ["v2_32"] }
gettext-rs= { version = "0.4", features = ["gettext-system"] }
gettext-rs= { version = "0.5", features = ["gettext-system"] }
pretty_env_logger = "0.3"
lazy_static = "1.3"
failure = "0.1"
@ -28,3 +17,26 @@ serde_derive = "1.0"
nanoid = "0.1"
reqwest = "0.9"
url = "2.1"
gtk-macros = "0.2"
[dependencies.gtk]
git = "https://github.com/gtk-rs/gtk4"
package = "gtk4"
[dependencies.glib]
git = "https://github.com/gtk-rs/glib"
[dependencies.gio]
git = "https://github.com/gtk-rs/gio"
[dependencies.gdk]
git = "https://github.com/gtk-rs/gdk4"
package = "gdk4"
[dependencies.libhandy]
git = "https://gitlab.gnome.org/bilelmoussaoui/libhandy4-rs"
package = "libhandy4"
[dependencies.gdk-pixbuf]
git = "https://github.com/gtk-rs/gdk-pixbuf"

View file

@ -6,20 +6,13 @@
"sdk-extensions" : [
"org.freedesktop.Sdk.Extension.rust-stable"
],
"tags" : [
"nightly"
],
"desktop-file-name-prefix" : "(Development) ",
"command": "authenticator",
"finish-args": [
"--share=network",
"--share=ipc",
"--device=dri",
"--socket=fallback-x11",
"--socket=wayland",
"--filesystem=xdg-run/dconf",
"--filesystem=~/.config/dconf:ro",
"--talk-name=ca.desrt.dconf",
"--env=DCONF_USER_CONFIG_DIR=.config/dconf"
"--socket=wayland"
],
"build-options": {
"append-path" : "/usr/lib/sdk/rust-stable/bin",
@ -27,7 +20,6 @@
"--share=network"
],
"env" : {
"RUSTFLAGS" : "--remap-path-prefix =../ --error-format=human",
"CARGO_HOME" : "/run/build/authenticator/cargo",
"RUST_BACKTRACE" : "1",
"RUST_LOG" : "authenticator=debug"
@ -38,7 +30,7 @@
"name": "libhandy",
"buildsystem": "meson",
"config-opts": [
"-Dintrospection=disabled",
"-Dintrospection=enabled",
"-Dgtk_doc=false",
"-Dtests=false",
"-Dexamples=false",
@ -47,9 +39,8 @@
],
"sources": [{
"type": "git",
"url": "https://source.puri.sm/Librem5/libhandy.git",
"tag": "v0.0.11",
"commit": "f5909a897f70143bdd2f89f47a63c1bf848330ce"
"url": "https://gitlab.gnome.org/exalm/libhandy.git",
"branch": "gtk4"
}]
},
{
@ -60,8 +51,8 @@
],
"sources": [
{
"type": "git",
"url" : "https://gitlab.gnome.org/World/authenticator.git"
"type": "dir",
"path" : "../"
}
]
}

View file

@ -1,77 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project maintainer at bilal.elmoussaoui@gnome.org. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

View file

@ -22,7 +22,7 @@
<file compressed="true" preprocess="xml-stripblanks" alias="window.ui">window.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="settings.ui">settings.ui</file>
</gresource>
<gresource prefix="/com/belmoussaoui/Authenticator/icons">
<gresource prefix="/com/belmoussaoui/Authenticator/icons/16x16/actions">
<file alias="qrscanner-symbolic.svg">resources/icons/qrscanner-symbolic.svg</file>
</gresource>

View file

@ -11,16 +11,6 @@
<summary>Default window height</summary>
<description>Default window height</description>
</key>
<key name="window-x" type="i">
<default>-1</default>
<summary>Default window x position</summary>
<description>Default window x position</description>
</key>
<key name="window-y" type="i">
<default>-1</default>
<summary>Default window y position</summary>
<description>Default window y position</description>
</key>
<key name="is-maximized" type="b">
<default>false</default>
<summary>Default window maximized behaviour</summary>

View file

@ -1,56 +0,0 @@
/* Empty View */
.empty-logo{
-gtk-icon-shadow:0 2px 12px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.5);
}
/* Common */
label.head-title{
font-size: 26px;
font-weight: bolder;
color: @theme_fg_color;
}
.insert-image-box{
border: 1px solid mix(@theme_fg_color, @theme_bg_color, 0.7);
}
.account-name{
font-weight: bold;
}
/* Common */
.progress-bar trough progress {
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
}
.progress-bar trough {
border-radius: 0px
}
/* Accounts Widget */
.provider-name{
margin: 6px;
font-weight: bold;
font-size: 18px;
}
/* Accounts List */
.accounts-list {
margin-left:6px;
margin-right:6px;
}
/* Account Row */
.account-row{
padding: 6px;
}
.account-name{
font-size: 16px;
}
.account-pin {
font-size: 14px;
}

View file

@ -1,11 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkAboutDialog" id="about_dialog">
<property name="can_focus">False</property>
<property name="type_hint">dialog</property>
<property name="program_name">Authenticator</property>
<property name="modal">True</property>
<property name="version">@version@</property>
<property name="comments" translatable="yes">A Two-Factor Authentication application</property>
<property name="website">https://gitlab.gnome.org/World/Authenticator</property>
@ -15,35 +12,5 @@
Tobias Bernard</property>
<property name="logo_icon_name">@app-id@</property>
<property name="license_type">gpl-3-0</property>
<child type="titlebar">
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</interface>

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<template class="AccountConfig" parent="GtkOverlay">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<packing>
<property name="index">-1</property>
</packing>
</child>
</template>
</interface>

View file

@ -1,51 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<template class="EditAccountWindow" parent="GtkWindow">
<property name="can_focus">False</property>
<property name="modal">True</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="back_btn">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="close_btn_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="return_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-previous-symbolic</property>
</object>
</child>
<property name="icon-name">go-previous-symbolic</property>
</object>
</child>
<child>
<object class="GtkButton" id="save_btn">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</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="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child>
<placeholder/>
</child>
</template>
</interface>

View file

@ -1,55 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkPopoverMenu" id="more_actions_popover">
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkModelButton" id="edit_btn">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="margin_left">6</property>
<property name="margin_right">6</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="margin-left">6</property>
<property name="margin-right">6</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<property name="text" translatable="yes">Edit</property>
<signal name="clicked" handler="edit_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="GtkModelButton" id="delete_btn">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="margin_left">6</property>
<property name="margin_right">6</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="margin-left">6</property>
<property name="margin-right">6</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<property name="text" translatable="yes">Delete</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="submenu">main</property>
<property name="position">1</property>
</packing>
</child>
</object>
<object class="GtkListBoxRow" id="account_row">
@ -60,20 +36,14 @@
<property name="selectable">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuButton" id="more_actions_btn">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="valign">center</property>
<property name="popover">more_actions_popover</property>
<child>
<object class="GtkImage" id="more_actions_img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">view-more-symbolic</property>
<property name="icon-name">view-more-symbolic</property>
</object>
</child>
<style>
@ -81,49 +51,26 @@
<class name="flat"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">3</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="copy_btn">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Copy PIN to clipboard</property>
<property name="valign">center</property>
<property name="relief">none</property>
<signal name="clicked" handler="copy_btn_clicked" swapped="no"/>
<child>
<object class="GtkStack" id="copy_btn_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<child>
<object class="GtkImage" id="copy_img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-copy-symbolic</property>
<property name="icon-name">edit-copy-symbolic</property>
</object>
<packing>
<property name="name">copy_image</property>
</packing>
</child>
<child>
<object class="GtkImage" id="ok_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">emblem-ok-symbolic</property>
<property name="icon-name">emblem-ok-symbolic</property>
</object>
<packing>
<property name="name">ok_image</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
@ -131,45 +78,22 @@
<class name="flat"/>
</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>
<child>
<object class="GtkLabel" id="pin_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<style>
<class name="account-pin"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">3</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="username_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">3</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>

View file

@ -1,64 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkBox" id="accounts_list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">96</property>
<property name="icon_name">image-missing-symbolic</property>
<property name="icon-name">image-missing-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="provider_name">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Some random provider</property>
<style>
<class name="provider-name"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</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="GtkListBox" id="listbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selection_mode">none</property>
<style>
<class name="frame"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>

View file

@ -1,35 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<requires lib="libhandy" version="0.0"/>
<object class="GtkBox" id="providers_list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="HdyColumn">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="maximum_width">600</property>
<property name="linear_growth_width">600</property>
<child>
<object class="GtkBox" id="providers_container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="orientation">vertical</property>
<child>
@ -42,11 +28,6 @@
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="accounts-widget"/>

View file

@ -1,262 +1,195 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<requires lib="libhandy" version="0.0"/>
<object class="HdyWindow" id="add_dialog">
<property name="modal">True</property>
<property name="default_width">560</property>
<property name="default_height">720</property>
<property name="title">Add a new account</property>
<property name="destroy_with_parent">True</property>
<child>
<object class="HdyLeaflet">
<child>
<object class="HdyLeafletPage">
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="hexpand">True</property>
<child>
<object class="GtkHeaderBar">
<property name="show-title-buttons">False</property>
<child type="start">
<object class="GtkButton" id="back_btn">
<property name="receives_default">True</property>
<property name="action_name">add.back</property>
<property name="icon-name">go-previous-symbolic</property>
</object>
</child>
<child type="end">
<object class="GtkButton" id="add_btn">
<property name="label" translatable="yes">Add</property>
<property name="sensitive">False</property>
<property name="receives_default">True</property>
<property name="action_name">add.save</property>
<style>
<class name="suggested-action"/>
</style>
</object>
</child>
<child type="end">
<object class="GtkButton" id="scan_btn">
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Scan QR Code</property>
<property name="action_name">add.scan-qr</property>
<property name="icon-name">qrscanner-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="HdyClamp">
<property name="valign">center</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="vexpand">True</property>
<property name="maximum-size">400</property>
<property name="tightening-threshold">400</property>
<child>
<object class="GtkBox" id="main_container">
<property name="orientation">vertical</property>
<property name="spacing">42</property>
<child>
<object class="GtkListBox" id="basic_list">
<property name="selection_mode">none</property>
<child>
<object class="HdyActionRow">
<property name="activatable_widget">provider_entry</property>
<property name="title" translatable="yes">Provider</property>
<child>
<object class="GtkEntry" id="provider_entry">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="completion">provider_completion</property>
<property name="enable_emoji_completion">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="HdyActionRow">
<property name="activatable_widget">username_entry</property>
<property name="title" translatable="yes">Account</property>
<child>
<object class="GtkEntry" id="username_entry">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="enable_emoji_completion">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="HdyActionRow" id="token_row">
<property name="activatable_widget">token_entry</property>
<property name="title" translatable="yes">Token</property>
<child>
<object class="GtkEntry" id="token_entry">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="visibility">False</property>
<property name="secondary_icon_name">dialog-information-symbolic</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Enable 2FA for this account</property>
<property name="secondary_icon_tooltip_markup" translatable="yes">Enable 2FA for this account</property>
<property name="input_purpose">pin</property>
</object>
</child>
</object>
</child>
<style>
<class name="content"/>
</style>
</object>
</child>
<child>
<object class="GtkListBox" id="more_list">
<property name="selection_mode">none</property>
<child>
<object class="HdyActionRow">
<property name="activatable_widget">provider_website_entry</property>
<property name="title" translatable="yes">Website</property>
<child>
<object class="GtkEntry" id="provider_website_entry">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="input_purpose">url</property>
<property name="enable_emoji_completion">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="HdyActionRow">
<property name="activatable_widget">period_spinbutton</property>
<property name="title" translatable="yes">Period</property>
<child>
<object class="GtkSpinButton" id="period_spinbutton">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="text" translatable="yes">0</property>
<property name="adjustment">period_adjustment</property>
<property name="numeric">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="HdyComboRow" id="algorithm_comborow">
<property name="title" translatable="yes">Algorithm</property>
</object>
</child>
<style>
<class name="content"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
<object class="GtkEntryCompletion" id="provider_completion">
<property name="minimum_key_length">2</property>
<property name="text_column">1</property>
<property name="inline_selection">True</property>
<child>
<object class="GtkCellRendererText"/>
<object class="GtkCellRendererText" />
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
<object class="GtkWindow" id="add_dialog">
<property name="width_request">360</property>
<property name="height_request">600</property>
<property name="can_focus">False</property>
<property name="modal">True</property>
<property name="default_width">360</property>
<property name="default_height">600</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Add a new account</property>
<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="action_name">add.back</property>
<signal name="clicked" handler="close_btn_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="return_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-previous-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="add_btn">
<property name="label" translatable="yes">Add</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">add.save</property>
<signal name="clicked" handler="add_btn_clicked" swapped="no"/>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="scan_btn">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Scan QR Code</property>
<property name="action_name">add.scan-qr</property>
<signal name="clicked" handler="scan_btn_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="scan_img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">qrscanner-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkOverlay">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="HdyColumn" id="column">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="maximum_width">600</property>
<property name="linear_growth_width">600</property>
<child>
<object class="GtkBox" id="main_container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin_top">42</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">baseline</property>
<property name="margin_top">24</property>
<property name="hexpand">True</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkEntry" id="username_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="placeholder_text" translatable="yes">Account Name</property>
<property name="enable_emoji_completion">True</property>
<signal name="changed" handler="account_edited" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="provider_combobox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="has_entry">True</property>
<property name="entry_text_column">1</property>
<property name="id_column">0</property>
<signal name="changed" handler="provider_changed" swapped="no"/>
<child internal-child="entry">
<object class="GtkEntry" id="provider_entry">
<property name="can_focus">True</property>
<property name="placeholder_text" translatable="yes">Provider</property>
<property name="completion">provider_completion</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="token_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="visibility">False</property>
<property name="secondary_icon_name">dialog-information-symbolic</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Enable 2FA for this account</property>
<property name="secondary_icon_tooltip_markup" translatable="yes">Enable 2FA for this account</property>
<property name="placeholder_text" translatable="yes">2FA Token</property>
<property name="input_purpose">pin</property>
<signal name="changed" handler="account_edited" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="provider_website_entry">
<property name="can_focus">True</property>
<property name="no_show_all">True</property>
<property name="hexpand">True</property>
<property name="placeholder_text" translatable="yes">Provider Website</property>
<property name="input_purpose">url</property>
<property name="enable_emoji_completion">True</property>
<signal name="key-release-event" handler="on_provider_website_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</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>
</child>
</object>
<packing>
<property name="pass_through">True</property>
<property name="index">-1</property>
</packing>
</child>
<child type="overlay">
<object class="GtkRevealer" id="notification">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="notification_msg">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">end</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">window-close-symbolic</property>
</object>
</child>
<style>
<class name="flat"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="app-notification"/>
</style>
</object>
</child>
<style>
<class name="frame"/>
</style>
</object>
</child>
</object>
</child>
<object class="GtkAdjustment" id="period_adjustment">
<property name="upper">60</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkSizeGroup">
<widgets>
<widget name="period_spinbutton"/>
<widget name="provider_entry"/>
<widget name="provider_website_entry"/>
<widget name="username_entry"/>
<widget name="token_entry"/>
</widgets>
</object>
</interface>

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkBox" id="LoginWidget">
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="halign">center</property>
<property name="hexpand">True</property>
<property name="resource">/com/github/bilelmoussaoui/Authenticator/authenticator.svg</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">center</property>
<property name="margin-top">12</property>
<property name="label" translatable="yes">Authenticator is locked</property>
<style>
<class name="head-title"/>
</style>
</object>
</child>
<child>
<object class="GtkBox">
<property name="halign">center</property>
<property name="valign">start</property>
<property name="margin-top">24</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkEntry" id="password_entry">
<property name="halign">center</property>
<property name="visibility">False</property>
<property name="input_purpose">password</property>
</object>
</child>
<child>
<object class="GtkButton" id="unlock_btn">
<property name="label" translatable="yes">Unlock</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<style>
<class name="suggested-action"/>
</style>
</object>
</child>
</object>
</child>
</object>
</interface>

View file

@ -1,238 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="PasswordWidget" parent="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</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="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="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="current_password_box">
<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">start</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Current 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="current_password_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="hexpand">True</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="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">0</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">start</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">New 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="halign">end</property>
<property name="valign">center</property>
<property name="hexpand">True</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="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">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">start</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Confirm New 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="confirm_password_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="hexpand">True</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="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>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">18</property>
<property name="margin-top">18</property>
<child>
<object class="GtkButton" id="change_password_btn">
<property name="label" translatable="yes">Change Password</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">end</property>
<signal name="clicked" handler="update_password_clicked" swapped="no"/>
<style>
<class name="suggested-action"/>
</style>
</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">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="delete_password_btn">
<property name="label" translatable="yes">Delete Password</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">start</property>
<signal name="clicked" handler="reset_password_clicked" swapped="no"/>
<style>
<class name="destructive-action"/>
</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">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">6</property>
<property name="position">1</property>
</packing>
</child>
</template>
</interface>

View file

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="ProviderImage" parent="GtkStack">
<property name="visible">True</property>
<property name="can_focus">True</property>
@ -10,101 +8,59 @@
<property name="valign">center</property>
<child>
<object class="GtkSpinner" id="provider_spinner">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="name">provider_loading</property>
</packing>
</child>
<child>
<object class="GtkEventBox" id="image_eventbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="button-press-event" handler="select_image_clicked" swapped="no"/>
<child>
<object class="GtkOverlay">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="provider_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">128</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="index">-1</property>
</packing>
</child>
<child type="overlay">
<object class="GtkImage" id="insert_image">
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="icon_name">insert-image-symbolic</property>
<property name="icon_size">5</property>
<property name="icon-name">insert-image-symbolic</property>
<style>
<class name="insert-image"/>
</style>
</object>
<packing>
<property name="pass_through">True</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="name">provider_image</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="not_found_box">
<property name="width_request">48</property>
<property name="height_request">48</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkEventBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<signal name="button-press-event" handler="select_image_clicked" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="icon_name">insert-image-symbolic</property>
<property name="icon_size">5</property>
<property name="icon-name">insert-image-symbolic</property>
<style>
<class name="insert-image"/>
</style>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<style>
<class name="insert-image-box"/>
</style>
</object>
<packing>
<property name="name">provider_not_found</property>
<property name="position">2</property>
</packing>
</child>
</template>
</interface>

View file

@ -1,48 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<requires lib="libhandy" version="0.0"/>
<object class="GtkBox" id="providers_list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<object class="HdyClamp">
<child>
<object class="HdyColumn">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="maximum_width">600</property>
<property name="linear_growth_width">600</property>
<object class="GtkBox" id="providers_container">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="providers_container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
<placeholder/>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="accounts-widget"/>

View file

@ -1,110 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkAdjustment" id="auto_lock_adjustment">
<property name="lower">0</property>
<property name="upper">60</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<requires lib="libhandy" version="0.0"/>
<template class="SettingsWindow" parent="HdyPreferencesWindow">
<property name="default_height">400</property>
<property name="default_width">600</property>
<property name="height-request">300</property>
<child>
<object class="HdyPreferencesPage">
<property name="icon_name">emblem-system-symbolic</property>
<property name="icon-name">emblem-system-symbolic</property>
<property name="title">General</property>
<property name="visible">True</property>
<child>
<object class="HdyPreferencesGroup">
<property name="title" translatable="yes">Appearance</property>
<property name="visible">True</property>
<child>
<object class="HdyActionRow">
<property name="title" translatable="yes">Dark Theme</property>
<property name="subtitle" translatable="yes">Whether the application should use a dark theme.</property>
<property name="visible">true</property>
<child type="action">
<object class="GtkSwitch" id="dark_theme_switch">
<property name="can_focus">True</property>
<property name="visible">True</property>
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<object class="HdyPreferencesGroup">
<property name="title" translatable="yes">Appearance</property>
<child>
<object class="HdyActionRow">
<property name="title" translatable="yes">Dark Theme</property>
<property name="subtitle" translatable="yes">Whether the application should use a dark theme.</property>
<child type="action">
<object class="GtkSwitch" id="dark_theme_switch">
<child>
<object class="HdyActionRow">
<property name="title" translatable="yes">Night Light</property>
<property name="subtitle" translatable="yes">Automatically enable dark mode at night.</property>
<property name="visible">true</property>
<child type="action">
<object class="GtkSwitch" id="night_light_switch">
<property name="can_focus">True</property>
<property name="visible">True</property>
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="HdyActionRow">
<property name="title" translatable="yes">Night Light</property>
<property name="subtitle" translatable="yes">Automatically enable dark mode at night.</property>
<child type="action">
<object class="GtkSwitch" id="night_light_switch">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</child>
<child>
<object class="HdyPreferencesPage">
<property name="icon_name">security-low-symbolic</property>
<property name="icon-name">security-low-symbolic</property>
<property name="title">Security</property>
<property name="visible">True</property>
<child>
<object class="HdyPreferencesGroup">
<property name="title" translatable="yes"></property>
<property name="visible">True</property>
<child>
<object class="HdyExpanderRow" id="lock_row">
<property name="title" translatable="yes">Lock the application</property>
<property name="subtitle" translatable="yes">Whether the application should use a dark theme.</property>
<property name="visible">true</property>
</object>
</child>
<child>
<object class="HdyActionRow" id="lock_timeout_row">
<property name="title" translatable="yes">Auto lock timeout</property>
<property name="subtitle" translatable="yes">Automatically enable dark mode at night.</property>
<property name="visible">true</property>
<child type="action">
<object class="GtkSpinButton" id="lock_timeout_spinbtn">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="input_purpose">digits</property>
<property name="valign">center</property>
<property name="halign">center</property>
<property name="adjustment">auto_lock_adjustment</property>
<property name="climb_rate">1</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
</object>
</child>
</object>
</child>
</object>
<object class="HdyPreferencesGroup">
<property name="title" translatable="yes"></property>
<child>
<object class="HdyExpanderRow" id="lock_row">
<property name="title" translatable="yes">Lock the application</property>
<property name="subtitle" translatable="yes">Whether the application should use a dark theme.</property>
</object>
</child>
<child>
<object class="HdyActionRow" id="lock_timeout_row">
<property name="title" translatable="yes">Auto lock timeout</property>
<property name="subtitle" translatable="yes">Automatically enable dark mode at night.</property>
<child type="action">
<object class="GtkSpinButton" id="lock_timeout_spinbtn">
<property name="input_purpose">digits</property>
<property name="valign">center</property>
<property name="halign">center</property>
<property name="adjustment">auto_lock_adjustment</property>
<property name="climb_rate">1</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View file

@ -1,60 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkShortcutsWindow" id="shortcuts">
<property name="modal">True</property>
<object class="GtkShortcutsWindow" id="shortcuts">
<property name="modal">True</property>
<child>
<object class="GtkShortcutsSection">
<property name="section-name">shortcuts</property>
<property name="max-height">10</property>
<child>
<object class="GtkShortcutsSection">
<property name="visible">True</property>
<property name="section-name">shortcuts</property>
<property name="max-height">10</property>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">True</property>
<property name="title" translatable="yes" context="shortcut window">General</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">True</property>
<property name="title" translatable="yes" context="shortcut window">Show Shortcuts</property>
<property name="accelerator">&lt;Primary&gt;question</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">True</property>
<property name="title" translatable="yes" context="shortcut window">Preferences</property>
<property name="accelerator">&lt;Primary&gt;comma</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">True</property>
<property name="title" translatable="yes" context="shortcut window">Quit</property>
<property name="accelerator">&lt;Primary&gt;Q</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="visible">True</property>
<property name="title" translatable="yes" context="shortcut window">Accounts</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">True</property>
<property name="title" translatable="yes" context="shortcut window">Add</property>
<property name="accelerator">&lt;Primary&gt;N</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">True</property>
<property name="title" translatable="yes" context="shortcut window">Search</property>
<property name="accelerator">&lt;Primary&gt;F</property>
</object>
</child>
</object>
</child>
</object>
<object class="GtkShortcutsGroup">
<property name="title" translatable="yes" context="shortcut window">General</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Show Shortcuts</property>
<property name="accelerator">&lt;Primary&gt;question</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Preferences</property>
<property name="accelerator">&lt;Primary&gt;comma</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Quit</property>
<property name="accelerator">&lt;Primary&gt;Q</property>
</object>
</child>
</object>
</child>
</object>
<child>
<object class="GtkShortcutsGroup">
<property name="title" translatable="yes" context="shortcut window">Accounts</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Add</property>
<property name="accelerator">&lt;Primary&gt;N</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="title" translatable="yes" context="shortcut window">Search</property>
<property name="accelerator">&lt;Primary&gt;F</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View file

@ -1,772 +1,165 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkPopoverMenu" id="popover">
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkStack" id="menu_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="vhomogeneous">False</property>
<property name="transition_type">slide-left-right</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkButton" id="zoom_out_btn">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="action_name">reader.zoom-out</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">zoom-out-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="zoom_reset_btn">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="action_name">reader.zoom-reset</property>
<child>
<object class="GtkLabel" id="zoom_level">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label">100%</property>
<property name="width_chars">5</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="zoom_in_btn">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="action_name">reader.zoom-in</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">zoom-in-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="name">reader</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="orientation">vertical</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkBox">
<property name="width_request">146</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">start</property>
<property name="action_name">library.sort-ascending</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">view-sort-ascending-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">start</property>
<property name="action_name">library.sort-descending</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">view-sort-descending-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkRadioButton" id="sort_name_radio">
<property name="label" translatable="yes">Name</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="action_name">library.sort-by</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="sort_date_radio">
<property name="label" translatable="yes">Date</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="action_name">library.sort-by</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">sort_name_radio</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="name">library</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="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="action_name">win.show-help-overlay</property>
<property name="text" translatable="yes">_Keyboard Shortcuts</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="action_name">app.about</property>
<property name="text" translatable="yes">_About Authenticator</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
</object>
<packing>
<property name="submenu">main</property>
<property name="position">1</property>
</packing>
</child>
</object>
<object class="GtkApplicationWindow" id="window">
<menu id="menu">
<item>
<attribute name="label">_Lock the application</attribute>
<attribute name="action">app.preferences</attribute>
</item>
<item>
<attribute name="label">_Preferences</attribute>
<attribute name="action">app.preferences</attribute>
</item>
<item>
<attribute name="label">_Keyboard Shortcuts</attribute>
<attribute name="action">win.show-help-overlay</attribute>
</item>
<item>
<attribute name="label">About Authenticator</attribute>
<attribute name="action">app.about</attribute>
</item>
</menu>
<object class="HdyApplicationWindow" id="window">
<property name="width_request">350</property>
<property name="height_request">500</property>
<property name="can_focus">False</property>
<property name="default_width">360</property>
<property name="default_height">550</property>
<property name="icon_name">@app-id@</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<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>
<property name="transition_type">slide-left-right</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<child>
<object class="GtkButton" id="add_btn">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">win.add-account</property>
<signal name="clicked" handler="add_btn_clicked" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">list-add-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="search_btn">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkImage" id="search_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">system-search-symbolic</property>
</object>
</child>
</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">main_headerbar</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">win.add-account</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">list-add-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="name">empty_headerbar</property>
<property name="position">1</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>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">locked_headerbar</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="popover">popover</property>
<child>
<object class="GtkImage" id="primary_menu_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">open-menu-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
</packing>
</child>
</object>
</child>
<property name="icon-name">@app-id@</property>
<child>
<object class="GtkStack" id="main_stack">
<property name="width_request">350</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">slide-left-right</property>
<object class="HdyLeaflet">
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="border_width">12</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">start</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="pixel_size">192</property>
<property name="icon_name">@app-id@</property>
<property name="icon_size">6</property>
<style>
<class name="empty-logo"/>
</style>
</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="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">start</property>
<property name="margin_top">12</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="label" translatable="yes">There are no accounts yet…</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<style>
<class name="head-title"/>
</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="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">start</property>
<property name="margin_top">24</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="row_spacing">12</property>
<property name="column_spacing">12</property>
<object class="HdyLeafletPage">
<property name="child">
<object class="GtkBox">
<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">Add a new account from the menu</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">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">Scan a QR Code</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkImage" id="add_image_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">list-add-symbolic</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkImage" id="qr_scanner_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">qrscanner-symbolic</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">empty_state</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchBar" id="search_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkStack" id="accounts_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_duration">300</property>
<property name="transition_type">slide-left-right</property>
<child>
<object class="GtkBox" id="providers_container">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
<object class="GtkHeaderBar">
<property name="show-title-buttons">True</property>
<child type="start">
<object class="GtkButton" id="add_btn">
<property name="receives_default">True</property>
<property name="action_name">win.add-account</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
<child type="end">
<object class="GtkMenuButton">
<property name="receives_default">True</property>
<property name="menu-model">menu</property>
<property name="icon-name">open-menu-symbolic</property>
</object>
</child>
<child type="end">
<object class="GtkToggleButton" id="search_btn">
<property name="receives_default">True</property>
<property name="icon-name">system-search-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="name">results</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="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</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="halign">center</property>
<property name="valign">start</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="pixel_size">128</property>
<property name="icon_name">system-search-symbolic</property>
<property name="icon_size">6</property>
<property name="pixel_size">192</property>
<property name="icon-name">@app-id@</property>
<style>
<class name="empty-logo"/>
</style>
</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="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">start</property>
<property name="margin_top">12</property>
<property name="margin-top">12</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="label" translatable="yes">No results found</property>
<property name="label" translatable="yes">There are no accounts yet…</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<style>
<class name="head-title"/>
<class name="title-2"/>
</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="halign">center</property>
<property name="valign">start</property>
<property name="margin-top">16</property>
<property name="spacing">8</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="spacing">8</property>
<child>
<object class="GtkImage" id="add_image_label">
<property name="icon-name">list-add-symbolic</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="label" translatable="yes">Add a new account from the menu</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<style>
<class name="body"/>
<class name="dim-label"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="spacing">8</property>
<child>
<object class="GtkImage" id="qr_scanner_image">
<property name="icon-name">qrscanner-symbolic</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="label" translatable="yes">Scan a QR Code</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">empty_results</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</property>
</object>
<packing>
<property name="name">normal_state</property>
<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="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</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="halign">center</property>
<property name="hexpand">True</property>
<property name="resource">/com/github/bilelmoussaoui/Authenticator/authenticator.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="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_top">12</property>
<property name="label" translatable="yes">Authenticator is locked</property>
<style>
<class name="head-title"/>
</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>
<property name="halign">center</property>
<property name="valign">start</property>
<property name="margin_top">24</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<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="input_purpose">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="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"/>
<style>
<class name="suggested-action"/>
</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">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">locked_state</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<style>
<class name="theme"/>
</style>
</object>
</interface>

View file

@ -7,8 +7,8 @@ project('authenticator', 'rust',
dependency('glib-2.0', version: '>= 2.56')
dependency('gio-2.0', version: '>= 2.56')
dependency('gdk-pixbuf-2.0')
dependency('gtk+-3.0', version: '>= 3.24.7')
dependency('libhandy-0.0', version: '>= 0.0.11')
dependency('gtk4', version: '>= 3.99.2')
#dependency('libhandy-4', version: '>= 1')
cargo = find_program('cargo', required: false)
glib_compile_schemas = find_program('glib-compile-schemas', required: true)

View file

@ -1,3 +0,0 @@
max_width = 200
edition = "2018"

View file

@ -14,7 +14,7 @@ pub enum Action {
pub struct Application {
app: gtk::Application,
window: Rc<RefCell<Window>>,
window: Rc<Window>,
sender: Sender<Action>,
receiver: RefCell<Option<Receiver<Action>>>,
}
@ -23,19 +23,17 @@ impl Application {
pub fn new() -> Rc<Self> {
let app = gtk::Application::new(Some(config::APP_ID), Default::default()).unwrap();
glib::set_application_name(&format!("{}Authenticator", config::NAME_PREFIX));
glib::set_prgname(Some("authenticator"));
let (sender, r) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let receiver = RefCell::new(Some(r));
let window = Window::new(sender.clone());
let builder = gtk::Builder::new_from_resource("/com/belmoussaoui/Authenticator/shortcuts.ui");
let dialog: gtk::ShortcutsWindow = builder.get_object("shortcuts").unwrap();
window.borrow().widget.set_help_overlay(Some(&dialog));
let application = Rc::new(Self { app, window, sender, receiver });
let application = Rc::new(Self {
app,
window,
sender,
receiver,
});
application.setup_gactions();
application.setup_signals();
@ -58,55 +56,56 @@ impl Application {
fn setup_gactions(&self) {
// Quit
let app = self.app.clone();
let simple_action = gio::SimpleAction::new("quit", None);
simple_action.connect_activate(move |_, _| app.quit());
self.app.add_action(&simple_action);
self.app.set_accels_for_action("app.quit", &["<primary>q"]);
action!(
self.app,
"quit",
clone!(@strong self.app as app => move |_, _| app.quit())
);
// About
let window = self.window.borrow().widget.clone();
let simple_action = gio::SimpleAction::new("about", None);
simple_action.connect_activate(move |_, _| {
let builder = gtk::Builder::new_from_resource("/com/belmoussaoui/Authenticator/about_dialog.ui");
let about_dialog: gtk::AboutDialog = builder.get_object("about_dialog").unwrap();
about_dialog.set_transient_for(Some(&window));
action!(
self.app,
"about",
clone!(@weak self.window.widget as window => move |_, _| {
let builder = gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/about_dialog.ui");
get_widget!(builder, gtk::AboutDialog, about_dialog);
about_dialog.set_transient_for(Some(&window));
about_dialog.show();
})
);
about_dialog.connect_response(|dialog, _| dialog.destroy());
about_dialog.show();
});
self.app.add_action(&simple_action);
self.app.set_accels_for_action("win.show-help-overlay", &["<primary>question"]);
self.app.set_accels_for_action("app.quit", &["<primary>q"]);
self.app
.set_accels_for_action("win.show-help-overlay", &["<primary>question"]);
}
fn setup_signals(&self) {
let window = self.window.borrow().widget.clone();
self.app.connect_activate(move |app| {
let gtk_settings = gtk::Settings::get_default().unwrap();
window.set_application(Some(app));
app.add_window(&window);
window.present();
});
self.app
.connect_activate(clone!(@weak self.window.widget as window => move |app| {
window.set_application(Some(app));
app.add_window(&window);
window.present();
}));
}
fn setup_css(&self) {
let theme = gtk::IconTheme::get_default().unwrap();
theme.add_resource_path("/com/belmoussaoui/Authenticator/icons");
self.app
.set_resource_base_path(Some("/com/belmoussaoui/Authenticator"));
let p = gtk::CssProvider::new();
gtk::CssProvider::load_from_resource(&p, "/com/belmoussaoui/Authenticator/style.css");
gtk::StyleContext::add_provider_for_screen(&gdk::Screen::get_default().unwrap(), &p, 500);
if let Some(ref display) = gdk::Display::get_default() {
let p = gtk::CssProvider::new();
gtk::CssProvider::load_from_resource(&p, "/com/belmoussaoui/Authenticator/style.css");
gtk::StyleContext::add_provider_for_display(display, &p, 500);
}
}
fn do_action(&self, action: Action) -> glib::Continue {
match action {
Action::OpenAddAccountDialog => {
let dialog = AddAccountDialog::new(self.sender.clone());
dialog.widget.set_transient_for(Some(&self.window.borrow().widget));
dialog.widget.set_transient_for(Some(&self.window.widget));
dialog.widget.show();
}
Action::ViewAccounts => self.window.borrow().set_view(View::Accounts),
Action::ViewAccounts => self.window.set_view(View::Accounts),
};
glib::Continue(true)

View file

@ -1,8 +1,8 @@
pub static APP_ID: &'static str = @APP_ID@;
pub static PKGDATADIR: &'static str = @PKGDATADIR@;
pub static PROFILE: &'static str = @PROFILE@;
pub static NAME_PREFIX: &'static str = @NAME_PREFIX@;
pub static VERSION: &'static str = @VERSION@;
pub static GETTEXT_PACKAGE: &'static str = @GETTEXT_PACKAGE@;
pub static LOCALEDIR: &'static str = @LOCALEDIR@;
pub static APP_ID: &str = @APP_ID@;
pub static PKGDATADIR: &str = @PKGDATADIR@;
pub static PROFILE: &str = @PROFILE@;
pub static NAME_PREFIX: &str = @NAME_PREFIX@;
pub static VERSION: &str = @VERSION@;
pub static GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@;
pub static LOCALEDIR: &str = @LOCALEDIR@;

View file

@ -1,4 +1,3 @@
extern crate pretty_env_logger;
#[macro_use]
extern crate log;
#[macro_use]
@ -13,10 +12,10 @@ extern crate diesel;
extern crate glib;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate gtk_macros;
extern crate gtk;
use gettextrs::*;
use libhandy::ColumnExt;
mod application;
mod config;
mod models;
@ -32,16 +31,16 @@ fn main() {
pretty_env_logger::init();
gtk::init().expect("Unable to start GTK3");
libhandy::functions::init();
// Prepare i18n
setlocale(LocaleCategory::LcAll, "");
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
textdomain(GETTEXT_PACKAGE);
static_resources::init().expect("Failed to initialize the resource file.");
glib::set_application_name("Authenticator");
glib::set_prgname(Some("authenticator"));
let column = libhandy::Column::new();
column.set_maximum_width(800);
column.set_linear_growth_width(600);
static_resources::init().expect("Failed to initialize the resource file.");
let app = Application::new();
app.run(app.clone());

View file

@ -29,8 +29,13 @@ impl database::Insert<Account> for NewAccount {
let db = database::connection();
let conn = db.get()?;
diesel::insert_into(accounts::table).values(self).execute(&conn)?;
diesel::insert_into(accounts::table)
.values(self)
.execute(&conn)?;
accounts::table.order(accounts::columns::id.desc()).first::<Account>(&conn).map_err(From::from)
accounts::table
.order(accounts::columns::id.desc())
.first::<Account>(&conn)
.map_err(From::from)
}
}

View file

@ -3,7 +3,6 @@ use super::database;
use super::object_wrapper::ObjectWrapper;
use super::provider::Provider;
use gio::prelude::*;
use glib::prelude::*;
use std::cell::RefCell;
#[derive(Clone, PartialEq)]
@ -61,8 +60,9 @@ impl AccountsModel {
let object = ObjectWrapper::new(Box::new(account));
let sort_by = self.sort_by.clone();
let sort_order = self.sort_order.clone();
self.model
.insert_sorted(&object, move |a, b| Self::accounts_cmp(a, b, sort_by.borrow().clone(), sort_order.borrow().clone()));
self.model.insert_sorted(&object, move |a, b| {
Self::accounts_cmp(a, b, sort_by.borrow().clone(), sort_order.borrow().clone())
});
}
pub fn get_count(&self) -> u32 {
@ -85,10 +85,16 @@ impl AccountsModel {
}
None => self.sort_order.borrow().clone(),
};
self.model.sort(move |a, b| Self::accounts_cmp(a, b, sort_by.clone(), sort_order.clone()));
self.model
.sort(move |a, b| Self::accounts_cmp(a, b, sort_by.clone(), sort_order.clone()));
}
fn accounts_cmp(a: &gio::Object, b: &gio::Object, sort_by: SortBy, sort_order: SortOrder) -> std::cmp::Ordering {
fn accounts_cmp(
a: &glib::Object,
b: &glib::Object,
sort_by: SortBy,
sort_order: SortOrder,
) -> std::cmp::Ordering {
let mut account_a: Account = a.downcast_ref::<ObjectWrapper>().unwrap().deserialize();
let mut account_b: Account = b.downcast_ref::<ObjectWrapper>().unwrap().deserialize();

View file

@ -10,7 +10,7 @@ use std::{fs, fs::File};
type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
lazy_static! {
static ref DB_PATH: PathBuf = glib::get_user_data_dir().unwrap().join("authenticator");
static ref DB_PATH: PathBuf = glib::get_user_data_dir().join("authenticator");
static ref POOL: Pool = init_pool().expect("Failed to create a pool");
}
@ -54,7 +54,10 @@ pub fn get_accounts_by_provider(provider_model: Provider) -> Result<Vec<Account>
let db = connection();
let conn = db.get()?;
accounts.filter(provider.eq(provider_model.id)).load::<Account>(&conn).map_err(From::from)
accounts
.filter(provider.eq(provider_model.id))
.load::<Account>(&conn)
.map_err(From::from)
}
pub fn get_accounts() -> Result<Vec<Account>, Error> {

View file

@ -43,19 +43,19 @@ mod imp {
}
fn new() -> Self {
Self { data: RefCell::new(None) }
Self {
data: RefCell::new(None),
}
}
}
impl ObjectImpl for ObjectWrapper {
glib_object_impl!();
fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
let prop = &PROPERTIES[id];
match *prop {
subclass::Property("data", ..) => {
let data = value.get();
let data = value.get().unwrap();
self.data.replace(data);
}
_ => unimplemented!(),
@ -86,17 +86,25 @@ impl ObjectWrapper {
where
O: serde::ser::Serialize,
{
glib::Object::new(Self::static_type(), &[("data", &serde_json::to_string(&object).unwrap())])
.unwrap()
.downcast()
.unwrap()
glib::Object::new(
Self::static_type(),
&[("data", &serde_json::to_string(&object).unwrap())],
)
.unwrap()
.downcast()
.unwrap()
}
pub fn deserialize<O>(&self) -> O
where
O: DeserializeOwned,
{
let data = self.get_property("data").unwrap().get::<String>().unwrap();
let data = self
.get_property("data")
.unwrap()
.get::<String>()
.unwrap()
.unwrap();
serde_json::from_str(&data).unwrap()
}
}

View file

@ -31,8 +31,13 @@ impl database::Insert<Provider> for NewProvider {
let db = database::connection();
let conn = db.get()?;
diesel::insert_into(providers::table).values(self).execute(&conn)?;
diesel::insert_into(providers::table)
.values(self)
.execute(&conn)?;
providers::table.order(providers::columns::id.desc()).first::<Provider>(&conn).map_err(From::from)
providers::table
.order(providers::columns::id.desc())
.first::<Provider>(&conn)
.map_err(From::from)
}
}

View file

@ -1,9 +1,6 @@
use super::accounts::AccountsModel;
use super::database;
use super::provider::Provider;
use gio::prelude::*;
use glib::prelude::*;
use std::cell::RefCell;
use std::collections::HashMap;
pub struct ProvidersModel {
@ -12,7 +9,9 @@ pub struct ProvidersModel {
impl ProvidersModel {
pub fn new() -> Self {
let mut model = Self { model: HashMap::new() };
let mut model = Self {
model: HashMap::new(),
};
model.init();
model
}
@ -23,6 +22,7 @@ impl ProvidersModel {
}
pub fn get_count(&self) -> usize {
println!("{}", self.model.len());
self.model.len()
}

View file

@ -1,7 +1,7 @@
// Source: https://gitlab.gnome.org/World/podcasts/blob/master/podcasts-gtk/src/static_resource.rs
use gio::{resources_register, Error, Resource};
use glib::Bytes;
use gio::{resources_register, Resource};
use glib::{Bytes, Error};
pub(crate) fn init() -> Result<(), Error> {
// load the gresource binary at build time and include/link it into the final
@ -10,7 +10,7 @@ pub(crate) fn init() -> Result<(), Error> {
// Create Resource it will live as long the value lives.
let gbytes = Bytes::from_static(res_bytes.as_ref());
let resource = Resource::new_from_data(&gbytes)?;
let resource = Resource::from_data(&gbytes)?;
// Register the resource so it won't be dropped and will continue to live in
// memory.

View file

@ -1,24 +1,29 @@
use crate::application::Action;
use crate::models::database::{self, *};
use crate::models::{Account, AccountsModel, NewAccount};
use crate::models::{Account, NewAccount};
use gio::prelude::*;
use glib::Sender;
use gtk::prelude::*;
use std::rc::Rc;
pub struct AddAccountDialog {
pub widget: gtk::Window,
pub widget: libhandy::Window,
builder: gtk::Builder,
sender: Sender<Action>,
}
impl AddAccountDialog {
pub fn new(sender: Sender<Action>) -> Rc<Self> {
let builder = gtk::Builder::new_from_resource("/com/belmoussaoui/Authenticator/add_account.ui");
let widget: gtk::Window = builder.get_object("add_dialog").expect("Failed to retrieve AddAccountDialog");
widget.show_all();
let builder = gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/add_account.ui");
let widget: libhandy::Window = builder
.get_object("add_dialog")
.expect("Failed to retrieve AddAccountDialog");
let add_account_dialog = Rc::new(Self { widget, builder, sender });
let add_account_dialog = Rc::new(Self {
widget,
builder,
sender,
});
add_account_dialog.setup_actions(add_account_dialog.clone());
add_account_dialog.setup_signals();
@ -32,37 +37,27 @@ impl AddAccountDialog {
}
fn notify_err(&self, error_msg: &str) {
let notification: gtk::Revealer = self.builder.get_object("notification").expect("Failed to retrieve notification");
let notification_msg: gtk::Label = self.builder.get_object("notification_msg").expect("Failed to retrieve notification_msg");
get_widget!(self.builder, gtk::Revealer, notification);
get_widget!(self.builder, gtk::Label, notification_msg);
notification_msg.set_text(error_msg);
notification.set_reveal_child(true); // Display the notification
}
fn setup_signals(&self) {
let username_entry: gtk::Entry = self.builder.get_object("username_entry").expect("Failed to retrieve username_entry");
let token_entry: gtk::Entry = self.builder.get_object("token_entry").expect("Failed to retrieve token_entry");
get_widget!(self.builder, gtk::Entry, username_entry);
get_widget!(self.builder, gtk::Entry, token_entry);
let action_group = self.widget.get_action_group("add").unwrap().downcast::<gio::SimpleActionGroup>().unwrap();
let save_action = action_group.lookup_action("save").unwrap().downcast::<gio::SimpleAction>().unwrap();
//let action_group = self.widget.get_action_group("add").unwrap().downcast::<gio::SimpleActionGroup>().unwrap();
//let save_action = action_group.lookup_action("save").unwrap().downcast::<gio::SimpleAction>().unwrap();
let weak_username = username_entry.downgrade();
let weak_token = token_entry.downgrade();
let validate_entries = move |entry: &gtk::Entry| {
let mut username = String::new();
let mut token = String::new();
if let Some(username_entry) = weak_username.upgrade() {
username.push_str(&username_entry.get_text().unwrap());
}
if let Some(token_entry) = weak_token.upgrade() {
token.push_str(&token_entry.get_text().unwrap());
}
let validate_entries = clone!(@weak username_entry, @weak token_entry => move |_: &gtk::Entry| {
let username = username_entry.get_text().unwrap();
let token = token_entry.get_text().unwrap();
let is_valid = !(username.is_empty() || token.is_empty());
save_action.set_enabled(is_valid);
};
//save_action.set_enabled(is_valid);
});
username_entry.connect_changed(validate_entries.clone());
token_entry.connect_changed(validate_entries);
@ -82,13 +77,22 @@ impl AddAccountDialog {
actions.add_action(&back);
let save = gio::SimpleAction::new("save", None);
let add_account_dialog = s.clone();
save.connect_activate(move |_, _| {
let builder = &add_account_dialog.builder;
let username_entry: gtk::Entry = builder.get_object("username_entry").expect("Failed to retrieve username_entry");
let token_entry: gtk::Entry = builder.get_object("token_entry").expect("Failed to retrieve token_entry");
let provider_combobox: gtk::ComboBox = builder.get_object("provider_combobox").expect("Failed to retrieve provider_combobox");
save.connect_activate(clone!(@strong self.builder as builder => move |_, _| {
get_widget!(builder, gtk::Entry, username_entry);
get_widget!(builder, gtk::Entry, token_entry);
get_widget!(builder, gtk::Entry, provider_entry);
get_widget!(builder, gtk::Entry, website_entry);
// get_widget!(builder, gtk::Entry, period_entry);
// get_widget!(builder, gtk::Entry, algorithm_model);
/*
let new_account = NewAccount {
username: username_entry.get_text().unwrap().to_string(),
token_id: token_entry.get_text().unwrap().to_string(),
@ -100,7 +104,8 @@ impl AddAccountDialog {
// Close the dialog if everything is fine.
add_account_dialog.widget.destroy();
}
});
*/
}));
save.set_enabled(false);
actions.add_action(&save);
@ -115,19 +120,14 @@ impl AddAccountDialog {
fn setup_widgets(&self) {
// Fill the providers gtk::ListStore
let col_types: [gtk::Type; 2] = [gtk::Type::String, gtk::Type::String];
let providers_store = gtk::ListStore::new(&col_types);
/*get_widget!(self.builder, gtk::ListStore, providers_store);
if let Ok(providers) = database::get_providers() {
for provider in providers.iter() {
let values: [&dyn ToValue; 2] = [&provider.id, &provider.name];
providers_store.set(&providers_store.append(), &[0, 1], &values);
}
}
}*/
let provider_completion: gtk::EntryCompletion = self.builder.get_object("provider_completion").expect("Failed to retrieve provider_completion");
let provider_combobox: gtk::ComboBox = self.builder.get_object("provider_combobox").expect("Failed to retrieve provider_combobox");
provider_combobox.set_model(Some(&providers_store));
provider_completion.set_model(Some(&providers_store));
get_widget!(self.builder, gtk::SpinButton, @period_spinbutton).set_value(30.0);
}
}

View file

@ -1,6 +1,6 @@
use gtk::prelude::*;
use glib::Sender;
use glib::{signal::Inhibit, Sender};
use crate::application::Action;
use crate::models::{Account, AccountsModel, ObjectWrapper, Provider};
@ -19,8 +19,11 @@ pub struct AccountsList<'a> {
*/
impl<'a> AccountsList<'a> {
pub fn new(model: &'a AccountsModel, provider: &'a Provider, sender: Sender<Action>) -> Self {
let builder = gtk::Builder::new_from_resource("/com/belmoussaoui/Authenticator/accounts_list.ui");
let widget: gtk::Box = builder.get_object("accounts_list").expect("Failed to retrieve accounts_list");
let builder =
gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/accounts_list.ui");
let widget: gtk::Box = builder
.get_object("accounts_list")
.expect("Failed to retrieve accounts_list");
let accounts_list = Self {
widget,
builder,
@ -33,29 +36,43 @@ impl<'a> AccountsList<'a> {
}
fn init(&self) {
let provider_name: gtk::Label = self.builder.get_object("provider_name").expect("Failed to retrieve provider_name");
let provider_name: gtk::Label = self
.builder
.get_object("provider_name")
.expect("Failed to retrieve provider_name");
provider_name.set_text(&self.provider.name);
let listbox: gtk::ListBox = self.builder.get_object("listbox").expect("Failed to retrieve listbox");
let listbox: gtk::ListBox = self
.builder
.get_object("listbox")
.expect("Failed to retrieve listbox");
let sender = self.sender.clone();
listbox.bind_model(Some(&self.model.model), move |account| {
let account: Account = account.downcast_ref::<ObjectWrapper>().unwrap().deserialize();
let row = AccountRow::new(account, sender.clone());
let sender = sender.clone();
row.set_on_click_callback(move |_, _| {
// sender.send(Action::LoadChapter(chapter.clone())).unwrap();
gtk::Inhibit(false)
});
row.widget.upcast::<gtk::Widget>()
});
listbox.bind_model(
Some(&self.model.model),
Some(Box::new(move |account: &glib::Object| {
let account: Account = account
.downcast_ref::<ObjectWrapper>()
.unwrap()
.deserialize();
let row = AccountRow::new(account, sender.clone());
let sender = sender.clone();
/*row.set_on_click_callback(move |_, _| {
// sender.send(Action::LoadChapter(chapter.clone())).unwrap();
Inhibit(false)
});*/
row.widget.upcast::<gtk::Widget>()
})),
);
listbox.set_header_func(Some(Box::new(move |row1: &gtk::ListBoxRow, row2: Option<&gtk::ListBoxRow>| {
if let Some(row_before) = row2 {
let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
row1.set_header(Some(&separator));
separator.show();
}
})));
listbox.set_header_func(Some(Box::new(
move |row1: &gtk::ListBoxRow, row2: Option<&gtk::ListBoxRow>| {
if let Some(row_before) = row2 {
let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
row1.set_header(Some(&separator));
separator.show();
}
},
)));
}
}

View file

@ -12,25 +12,27 @@ pub struct AccountRow {
impl AccountRow {
pub fn new(account: Account, sender: Sender<Action>) -> Self {
let builder = gtk::Builder::new_from_resource("/com/belmoussaoui/Authenticator/account_row.ui");
let widget: gtk::ListBoxRow = builder.get_object("account_row").expect("Failed to load library_row object");
let builder = gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/account_row.ui");
let widget: gtk::ListBoxRow = builder
.get_object("account_row")
.expect("Failed to load library_row object");
let account_row = Self { widget, builder, sender, account };
let account_row = Self {
widget,
builder,
sender,
account,
};
account_row.init();
account_row
}
fn init(&self) {
let username_label: gtk::Label = self.builder.get_object("username_label").expect("Failed to retrieve username_label");
let username_label: gtk::Label = self
.builder
.get_object("username_label")
.expect("Failed to retrieve username_label");
username_label.set_text(&self.account.username);
}
pub fn set_on_click_callback<F>(&self, callback: F)
where
for<'r, 's> F: std::ops::Fn(&'r gtk::EventBox, &'s gdk::EventButton) -> gtk::Inhibit + 'static,
{
//let event_box: gtk::EventBox = self.builder.get_object("eventbox").expect("Failed to load eventbox");
// event_box.connect_button_press_event(callback);
}
}

View file

@ -1,4 +1,3 @@
use gio::prelude::*;
use glib::Sender;
use gtk::prelude::*;
use std::cell::RefCell;
@ -16,23 +15,35 @@ pub struct ProvidersList {
impl ProvidersList {
pub fn new(sender: Sender<Action>) -> Self {
let builder = gtk::Builder::new_from_resource("/com/belmoussaoui/Authenticator/providers_list.ui");
let widget: gtk::Box = builder.get_object("providers_list").expect("Failed to retrieve providers_list");
let builder =
gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/providers_list.ui");
let widget: gtk::Box = builder
.get_object("providers_list")
.expect("Failed to retrieve providers_list");
let model = RefCell::new(ProvidersModel::new());
let providers_list = Self { widget, builder, sender, model };
let providers_list = Self {
widget,
builder,
sender,
model,
};
providers_list.init();
providers_list
}
fn init(&self) {
let providers_container: gtk::Box = self.builder.get_object("providers_container").expect("Failed to retrieve providers_container");
let providers_container: gtk::Box = self
.builder
.get_object("providers_container")
.expect("Failed to retrieve providers_container");
for (provider, accounts_model) in &self.model.borrow().model {
if accounts_model.get_count() != 0 {
let accounts_list = AccountsList::new(accounts_model, provider, self.sender.clone());
providers_container.pack_start(&accounts_list.widget, false, false, 0);
let accounts_list =
AccountsList::new(accounts_model, provider, self.sender.clone());
providers_container.append(&accounts_list.widget);
}
}
}

View file

@ -4,7 +4,7 @@ use crate::widgets::providers::ProvidersList;
use crate::window_state;
use gio::prelude::*;
use glib::Sender;
use glib::{signal::Inhibit, Sender, WeakRef};
use gtk::prelude::*;
use std::cell::RefCell;
@ -18,37 +18,37 @@ pub enum View {
}
pub struct Window {
pub widget: gtk::ApplicationWindow,
pub widget: libhandy::ApplicationWindow,
sender: Sender<Action>,
builder: gtk::Builder,
settings: RefCell<gio::Settings>,
}
impl Window {
pub fn new(sender: Sender<Action>) -> Rc<RefCell<Self>> {
pub fn new(sender: Sender<Action>) -> Rc<Self> {
let settings = gio::Settings::new(APP_ID);
let builder = gtk::Builder::new_from_resource("/com/belmoussaoui/Authenticator/window.ui");
let widget: gtk::ApplicationWindow = builder.get_object("window").unwrap();
let builder = gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/window.ui");
get_widget!(builder, libhandy::ApplicationWindow, window);
if PROFILE == "Devel" {
widget.get_style_context().add_class("devel");
window.get_style_context().add_class("devel");
}
let window = Rc::new(RefCell::new(Window {
widget,
let window_widget = Rc::new(Window {
widget: window,
sender,
builder,
settings: RefCell::new(settings),
}));
});
window.borrow().init();
window.borrow().setup_actions(window.clone());
window.borrow().set_view(View::Empty); // Start by default in an empty state
window
window_widget.init();
window_widget.setup_actions();
window_widget.set_view(View::Empty); // Start by default in an empty state
window_widget
}
pub fn set_view(&self, view: View) {
let headerbar_stack: gtk::Stack = self.builder.get_object("headerbar_stack").expect("Failed to retrieve headerbar_stack");
let main_stack: gtk::Stack = self.builder.get_object("main_stack").expect("Failed to retrieve main_stack");
/*get_widget!(self.builder, gtk::Stack, headerbar_stack);
get_widget!(self.builder, gtk::Stack, main_stack);
match view {
View::Empty => {
main_stack.set_visible_child_name("empty_state");
@ -62,7 +62,7 @@ impl Window {
main_stack.set_visible_child_name("normal_state");
headerbar_stack.set_visible_child_name("main_headerbar");
}
}
}*/
}
fn init(&self) {
@ -70,66 +70,31 @@ impl Window {
let settings = self.settings.borrow().clone();
window_state::load(&self.widget, &settings);
// save window state on delete event
self.widget.connect_delete_event(move |window, _| {
self.widget.connect_close_request(move |window| {
window_state::save(&window, &settings);
Inhibit(false)
});
let builder = gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/shortcuts.ui");
get_widget!(builder, gtk::ShortcutsWindow, shortcuts);
self.widget.set_help_overlay(Some(&shortcuts));
let providers_list = ProvidersList::new(self.sender.clone());
let providers_container: gtk::Box = self.builder.get_object("providers_container").expect("Failed to retrieve providers_container");
/*get_widget!(self.builder, gtk::Box, providers_container);
providers_container.pack_start(&providers_list.widget, true, true, 0);
providers_container.append(&providers_list.widget);
if providers_list.model.borrow().get_count() != 0 {
self.sender.send(Action::ViewAccounts).expect("Failed to send ViewAccountsAction");
}
send!(self.sender, Action::ViewAccounts);
}*/
}
/*
fn order(&self, sort_by: Option<SortBy>, sort_order: Option<SortOrder>) {
// self.library.borrow_mut().clone().sort(sort_by.clone(), sort_order.clone());
}
*/
fn setup_actions(&self, s: Rc<RefCell<Self>>) {
let actions = gio::SimpleActionGroup::new();
let add_account = gio::SimpleAction::new("add-account", None);
let sender = self.sender.clone();
add_account.connect_activate(move |_, _| {
sender.send(Action::OpenAddAccountDialog).unwrap();
});
actions.add_action(&add_account);
self.widget.insert_action_group("win", Some(&actions));
let actions = gio::SimpleActionGroup::new();
let sort_descending = gio::SimpleAction::new("sort-descending", None);
let sort_ascending = gio::SimpleAction::new("sort-ascending", None);
let window = s.clone();
let sort_ascending_action = sort_ascending.clone();
sort_descending.connect_activate(move |action, _| {
action.set_enabled(false);
sort_ascending_action.set_enabled(true);
// window.borrow_mut().order(None, Some(SortOrder::Desc));
});
actions.add_action(&sort_descending);
let window = s.clone();
let sort_descending_action = sort_descending.clone();
sort_ascending.connect_activate(move |action, _| {
action.set_enabled(false);
sort_descending_action.set_enabled(true);
// window.borrow().order(None, Some(SortOrder::Asc));
});
actions.add_action(&sort_ascending);
let window = s.clone();
let sort_by = gio::SimpleAction::new("sort-by", Some(glib::VariantTy::new("s").unwrap()));
sort_by.connect_activate(move |_, data| {
// let sort_by = SortBy::from(data.unwrap().get_str().unwrap());
// window.borrow().order(Some(sort_by), None);
});
actions.add_action(&sort_by);
self.widget.insert_action_group("library", Some(&actions));
fn setup_actions(&self) {
action!(
self.widget,
"add-account",
clone!(@strong self.sender as sender => move |_,_| {
send!(sender, Action::OpenAddAccountDialog);
})
);
}
}

View file

@ -1,7 +1,7 @@
use gio::prelude::SettingsExt;
use gtk::prelude::GtkWindowExt;
pub fn load(window: &gtk::ApplicationWindow, settings: &gio::Settings) {
pub fn load(window: &libhandy::ApplicationWindow, settings: &gio::Settings) {
let width = settings.get_int("window-width");
let height = settings.get_int("window-height");
@ -9,26 +9,16 @@ pub fn load(window: &gtk::ApplicationWindow, settings: &gio::Settings) {
window.resize(360, 600);
}
let x = settings.get_int("window-x");
let y = settings.get_int("window-y");
let is_maximized = settings.get_boolean("is-maximized");
if x > -1 && y > -1 {
window.move_(x, y);
} else if is_maximized {
if is_maximized {
window.maximize();
}
}
pub fn save(window: &gtk::ApplicationWindow, settings: &gio::Settings) {
pub fn save(window: &libhandy::ApplicationWindow, settings: &gio::Settings) {
let size = window.get_size();
let position = window.get_position();
settings.set_int("window-width", size.0);
settings.set_int("window-height", size.1);
settings.set_boolean("is-maximized", window.is_maximized());
settings.set_int("window-x", position.0);
settings.set_int("window-y", position.1);
}