Basic loading of blueprints and schema
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,2 +1,3 @@
 | 
			
		||||
/target
 | 
			
		||||
/Cargo.lock
 | 
			
		||||
.dir-locals.el
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								simplelogin-gui/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								simplelogin-gui/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
/res/gschemas.compiled
 | 
			
		||||
@ -6,3 +6,6 @@ edition = "2021"
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
gtk4 = { version = "0.7.3", features = ["blueprint"] }
 | 
			
		||||
simplelogin = { version = "0.1.0", path = "../simplelogin" }
 | 
			
		||||
tokio = { version = "1.33.0", features = ["full"] }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								simplelogin-gui/build.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								simplelogin-gui/build.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
use std::{env, io, fs, path::Path, process::Command};
 | 
			
		||||
 | 
			
		||||
const SCHEMA_NAME: &'static str = "im.zander.SimpleLogin.gschema.xml";
 | 
			
		||||
 | 
			
		||||
fn main() -> io::Result<()> {
 | 
			
		||||
    println!("cargo:rerun-if-changed=data/{}", SCHEMA_NAME);
 | 
			
		||||
    #[cfg(debug_assertions)] {
 | 
			
		||||
        let out_dir = env::var("OUT_DIR").unwrap();
 | 
			
		||||
        let source_path = Path::new("data/").join(SCHEMA_NAME);
 | 
			
		||||
        let compile_dir = Path::new(&out_dir).join("schemas");
 | 
			
		||||
        let compile_path = compile_dir.join(SCHEMA_NAME);
 | 
			
		||||
        eprintln!("Creating \"{}\"...", compile_dir.display());
 | 
			
		||||
        fs::create_dir_all(&compile_dir)?;
 | 
			
		||||
        eprintln!(
 | 
			
		||||
            "Copping \"{}\" to \"{}\"...",
 | 
			
		||||
            source_path.display(),
 | 
			
		||||
            compile_path.display()
 | 
			
		||||
        );
 | 
			
		||||
        fs::copy(source_path, &compile_path)?;
 | 
			
		||||
        eprintln!("Compiling schemas...");
 | 
			
		||||
        let status = Command::new("glib-compile-schemas")
 | 
			
		||||
            .args(["--strict", compile_dir.to_str().unwrap()])
 | 
			
		||||
            .status()?;
 | 
			
		||||
        if !status.success() {
 | 
			
		||||
            panic!("failed to compile schemas");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								simplelogin-gui/data/im.zander.SimpleLogin.gschema.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								simplelogin-gui/data/im.zander.SimpleLogin.gschema.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<schemalist>
 | 
			
		||||
  <schema id="im.zander.SimpleLogin" path="/im/zander/SimpleLogin/">
 | 
			
		||||
    <key name="api-key" type="s">
 | 
			
		||||
      <default>""</default>
 | 
			
		||||
      <summary>Api key</summary>
 | 
			
		||||
      <description>The api key for the current user</description>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="window-size" type="(ii)">
 | 
			
		||||
      <default>(-1,-1)</default>
 | 
			
		||||
    </key>
 | 
			
		||||
  </schema>
 | 
			
		||||
</schemalist>
 | 
			
		||||
							
								
								
									
										240
									
								
								simplelogin-gui/data/login_window.blp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								simplelogin-gui/data/login_window.blp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,240 @@
 | 
			
		||||
using Gtk 4.0;
 | 
			
		||||
 | 
			
		||||
Popover device_entry_popover {
 | 
			
		||||
  child:   Label {
 | 
			
		||||
    accessible-role: tooltip;
 | 
			
		||||
    label: "This is the human readable name that will show up in the API key section of the SimpleLogin website.";
 | 
			
		||||
    max-width-chars: 30;
 | 
			
		||||
    wrap: true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template $LoginWindow : ApplicationWindow {
 | 
			
		||||
  title: "SimpleLogin";
 | 
			
		||||
 | 
			
		||||
  Box {
 | 
			
		||||
    orientation: vertical;
 | 
			
		||||
 | 
			
		||||
    Overlay forms_overlay {
 | 
			
		||||
      child: forms_wrapper;
 | 
			
		||||
      valign: end;
 | 
			
		||||
      vexpand: true;
 | 
			
		||||
 | 
			
		||||
      Box forms_wrapper {
 | 
			
		||||
        valign: end;
 | 
			
		||||
        vexpand: true;
 | 
			
		||||
 | 
			
		||||
        Grid {
 | 
			
		||||
          halign: end;
 | 
			
		||||
          hexpand: true;
 | 
			
		||||
          margin-bottom: 10;
 | 
			
		||||
          margin-end: 10;
 | 
			
		||||
          margin-start: 10;
 | 
			
		||||
          margin-top: 10;
 | 
			
		||||
          valign: center;
 | 
			
		||||
 | 
			
		||||
          Label {
 | 
			
		||||
            hexpand: true;
 | 
			
		||||
            label: "Login:";
 | 
			
		||||
            margin-bottom: 5;
 | 
			
		||||
            vexpand: true;
 | 
			
		||||
 | 
			
		||||
            styles [
 | 
			
		||||
              "login-title-label",
 | 
			
		||||
            ]
 | 
			
		||||
 | 
			
		||||
            layout {
 | 
			
		||||
              column: "0";
 | 
			
		||||
              column-span: "2";
 | 
			
		||||
              row: "0";
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          Label error_label {
 | 
			
		||||
            label: "ERROR";
 | 
			
		||||
            margin-top: 5;
 | 
			
		||||
 | 
			
		||||
            styles [
 | 
			
		||||
              "error-message-label",
 | 
			
		||||
            ]
 | 
			
		||||
 | 
			
		||||
            layout {
 | 
			
		||||
              column: "0";
 | 
			
		||||
              column-span: "2";
 | 
			
		||||
              row: "4";
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          Entry device_entry {
 | 
			
		||||
            margin-start: 6;
 | 
			
		||||
            placeholder-text: "My Awesome Computer";
 | 
			
		||||
            secondary-icon-name: "dialog-question-symbolic";
 | 
			
		||||
            truncate-multiline: true;
 | 
			
		||||
            width-chars: 18;
 | 
			
		||||
 | 
			
		||||
            layout {
 | 
			
		||||
              column: "1";
 | 
			
		||||
              row: "3";
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          Label {
 | 
			
		||||
            label: "Device:";
 | 
			
		||||
            xalign: 0.0;
 | 
			
		||||
 | 
			
		||||
            layout {
 | 
			
		||||
              column: "0";
 | 
			
		||||
              row: "3";
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          Label {
 | 
			
		||||
            label: "Email:";
 | 
			
		||||
            xalign: 0.0;
 | 
			
		||||
 | 
			
		||||
            layout {
 | 
			
		||||
              column: "0";
 | 
			
		||||
              row: "1";
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          Label {
 | 
			
		||||
            label: "Password:";
 | 
			
		||||
            xalign: 0.0;
 | 
			
		||||
 | 
			
		||||
            layout {
 | 
			
		||||
              column: "0";
 | 
			
		||||
              row: "2";
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          Entry email_entry {
 | 
			
		||||
            hexpand: true;
 | 
			
		||||
            input-purpose: email;
 | 
			
		||||
            margin-start: 6;
 | 
			
		||||
            receives-default: true;
 | 
			
		||||
            truncate-multiline: true;
 | 
			
		||||
 | 
			
		||||
            styles [
 | 
			
		||||
            ]
 | 
			
		||||
 | 
			
		||||
            layout {
 | 
			
		||||
              column: "1";
 | 
			
		||||
              row: "1";
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          PasswordEntry password_entry {
 | 
			
		||||
            hexpand: true;
 | 
			
		||||
            margin-start: 6;
 | 
			
		||||
            show-peek-icon: true;
 | 
			
		||||
 | 
			
		||||
            layout {
 | 
			
		||||
              column: "1";
 | 
			
		||||
              row: "2";
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          Button login_button {
 | 
			
		||||
            halign: center;
 | 
			
		||||
            label: "Login";
 | 
			
		||||
            margin-top: 5;
 | 
			
		||||
            sensitive: false;
 | 
			
		||||
            valign: center;
 | 
			
		||||
 | 
			
		||||
            layout {
 | 
			
		||||
              column: "0";
 | 
			
		||||
              column-span: "2";
 | 
			
		||||
              row: "5";
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          styles [
 | 
			
		||||
            "login-form-warpper",
 | 
			
		||||
          ]
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Label {
 | 
			
		||||
          halign: center;
 | 
			
		||||
          justify: center;
 | 
			
		||||
          label: "- or -";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Box {
 | 
			
		||||
          halign: start;
 | 
			
		||||
          hexpand: true;
 | 
			
		||||
          margin-bottom: 10;
 | 
			
		||||
          margin-end: 10;
 | 
			
		||||
          margin-start: 10;
 | 
			
		||||
          margin-top: 10;
 | 
			
		||||
          orientation: vertical;
 | 
			
		||||
          valign: center;
 | 
			
		||||
 | 
			
		||||
          Label {
 | 
			
		||||
            hexpand: true;
 | 
			
		||||
            label: "Set API Key:";
 | 
			
		||||
            margin-bottom: 5;
 | 
			
		||||
 | 
			
		||||
            styles [
 | 
			
		||||
              "login-title-label",
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          PasswordEntry api_key_entry {
 | 
			
		||||
            hexpand: true;
 | 
			
		||||
            margin-end: 3;
 | 
			
		||||
            margin-start: 8;
 | 
			
		||||
            show-peek-icon: true;
 | 
			
		||||
            width-chars: 27;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          Button api_key_button {
 | 
			
		||||
            halign: center;
 | 
			
		||||
            label: "Accept";
 | 
			
		||||
            margin-top: 5;
 | 
			
		||||
            sensitive: false;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Label {
 | 
			
		||||
      label: "Don\'t have an account? You can register <a href=\"https://app.simplelogin.io/auth/register\">here</a>.";
 | 
			
		||||
      margin-bottom: 10;
 | 
			
		||||
      use-markup: true;
 | 
			
		||||
      valign: start;
 | 
			
		||||
      vexpand: true;
 | 
			
		||||
      yalign: 0.0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Box loading_overlay {
 | 
			
		||||
  orientation: vertical;
 | 
			
		||||
 | 
			
		||||
  Spinner {
 | 
			
		||||
    spinning: true;
 | 
			
		||||
    valign: end;
 | 
			
		||||
    vexpand: true;
 | 
			
		||||
 | 
			
		||||
    styles [
 | 
			
		||||
      "loading-label",
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Label {
 | 
			
		||||
    label: "Loading...";
 | 
			
		||||
    valign: start;
 | 
			
		||||
    vexpand: true;
 | 
			
		||||
 | 
			
		||||
    styles [
 | 
			
		||||
      "loading-label",
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  styles [
 | 
			
		||||
    "loading-label",
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										121
									
								
								simplelogin-gui/data/totp_window.blp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								simplelogin-gui/data/totp_window.blp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
			
		||||
using Gtk 4.0;
 | 
			
		||||
 | 
			
		||||
template $TotpWindow : Window {
 | 
			
		||||
  modal: true;
 | 
			
		||||
  title: "TOTP Entry";
 | 
			
		||||
 | 
			
		||||
  Overlay overlay {
 | 
			
		||||
    child: form_wrapper;
 | 
			
		||||
    halign: center;
 | 
			
		||||
    hexpand: true;
 | 
			
		||||
    valign: center;
 | 
			
		||||
    vexpand: true;
 | 
			
		||||
 | 
			
		||||
    Grid form_wrapper {
 | 
			
		||||
      column-spacing: 5;
 | 
			
		||||
      halign: center;
 | 
			
		||||
      hexpand: true;
 | 
			
		||||
      margin-bottom: 10;
 | 
			
		||||
      margin-end: 10;
 | 
			
		||||
      margin-start: 10;
 | 
			
		||||
      margin-top: 10;
 | 
			
		||||
      row-spacing: 5;
 | 
			
		||||
      valign: center;
 | 
			
		||||
      vexpand: true;
 | 
			
		||||
 | 
			
		||||
      Box {
 | 
			
		||||
        halign: center;
 | 
			
		||||
        hexpand: true;
 | 
			
		||||
 | 
			
		||||
        Image {
 | 
			
		||||
          halign: center;
 | 
			
		||||
          icon-name: "dialog-password-symbolic";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Label {
 | 
			
		||||
          label: "TOTP";
 | 
			
		||||
 | 
			
		||||
          styles [
 | 
			
		||||
            "login-title-label",
 | 
			
		||||
          ]
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        layout {
 | 
			
		||||
          column: "0";
 | 
			
		||||
          column-span: "2";
 | 
			
		||||
          row: "0";
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      Button accept_button {
 | 
			
		||||
        label: "Accept";
 | 
			
		||||
 | 
			
		||||
        layout {
 | 
			
		||||
          column: "1";
 | 
			
		||||
          row: "3";
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      Button cancel_button {
 | 
			
		||||
        label: "Cancel";
 | 
			
		||||
 | 
			
		||||
        layout {
 | 
			
		||||
          column: "0";
 | 
			
		||||
          row: "3";
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      Entry code_entry {
 | 
			
		||||
        placeholder-text: "TOTP Code";
 | 
			
		||||
 | 
			
		||||
        layout {
 | 
			
		||||
          column: "0";
 | 
			
		||||
          column-span: "2";
 | 
			
		||||
          row: "1";
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      Label error_label {
 | 
			
		||||
        label: "ERROR";
 | 
			
		||||
 | 
			
		||||
        styles [
 | 
			
		||||
          "error-message-label",
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        layout {
 | 
			
		||||
          column: "0";
 | 
			
		||||
          column-span: "2";
 | 
			
		||||
          row: "2";
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Box loading_overlay {
 | 
			
		||||
  orientation: vertical;
 | 
			
		||||
 | 
			
		||||
  Spinner {
 | 
			
		||||
    spinning: true;
 | 
			
		||||
    valign: end;
 | 
			
		||||
    vexpand: true;
 | 
			
		||||
 | 
			
		||||
    styles [
 | 
			
		||||
      "loading-label",
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Label {
 | 
			
		||||
    label: "Loading...";
 | 
			
		||||
    valign: start;
 | 
			
		||||
    vexpand: true;
 | 
			
		||||
 | 
			
		||||
    styles [
 | 
			
		||||
      "loading-label",
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  styles [
 | 
			
		||||
    "loading-label",
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								simplelogin-gui/res.old/global.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								simplelogin-gui/res.old/global.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
.login-title-label {
 | 
			
		||||
	font-size: x-large;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.error-message-label {
 | 
			
		||||
	color: red;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.loading-label {
 | 
			
		||||
	font-size: xx-large;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bold {
 | 
			
		||||
	font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										188
									
								
								simplelogin-gui/res.old/main-panel.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								simplelogin-gui/res.old/main-panel.ui
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,188 @@
 | 
			
		||||
<?xml version='1.0' encoding='UTF-8'?>
 | 
			
		||||
<!-- Created with Cambalache 0.16.0 -->
 | 
			
		||||
<interface>
 | 
			
		||||
  <!-- interface-name main-window.ui -->
 | 
			
		||||
  <requires lib="gtk" version="4.12"/>
 | 
			
		||||
  <template class="SLMainPanel" parent="GtkBox">
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkOverlay" id="overlay">
 | 
			
		||||
        <child>
 | 
			
		||||
          <object class="GtkBox" id="content_wrapper">
 | 
			
		||||
            <property name="orientation">vertical</property>
 | 
			
		||||
            <property name="vexpand">True</property>
 | 
			
		||||
            <child>
 | 
			
		||||
              <object class="GtkBox">
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkSearchEntry" id="search_box">
 | 
			
		||||
                    <property name="hexpand">True</property>
 | 
			
		||||
                    <property name="placeholder-text">Filter by email, description, etc.</property>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkDropDown" id="view_dropdown">
 | 
			
		||||
                    <property name="hexpand">True</property>
 | 
			
		||||
                    <property name="model">
 | 
			
		||||
                      <object class="GtkStringList">
 | 
			
		||||
                        <items>
 | 
			
		||||
                          <item>All aliases</item>
 | 
			
		||||
                          <item>Pinned only</item>
 | 
			
		||||
                          <item>Enabled only</item>
 | 
			
		||||
                          <item>Disabled only</item>
 | 
			
		||||
                        </items>
 | 
			
		||||
                      </object>
 | 
			
		||||
                    </property>
 | 
			
		||||
                    <property name="selected">0</property>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkButton" id="search_button">
 | 
			
		||||
                    <property name="label">Search</property>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
              </object>
 | 
			
		||||
            </child>
 | 
			
		||||
            <child>
 | 
			
		||||
              <object class="GtkBox">
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkButton" id="new_button">
 | 
			
		||||
                    <property name="label">New</property>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkButton" id="edit_button">
 | 
			
		||||
                    <property name="label">Edit</property>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkButton" id="delete_button">
 | 
			
		||||
                    <property name="label">Delete</property>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkButton" id="prev_page_button">
 | 
			
		||||
                    <property name="halign">end</property>
 | 
			
		||||
                    <property name="hexpand">True</property>
 | 
			
		||||
                    <property name="icon-name">go-previous-symbolic</property>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkEntry" id="page_label">
 | 
			
		||||
                    <property name="has-frame">False</property>
 | 
			
		||||
                    <property name="input-hints">no-emoji | no-spellcheck</property>
 | 
			
		||||
                    <property name="input-purpose">digits</property>
 | 
			
		||||
                    <property name="max-width-chars">0</property>
 | 
			
		||||
                    <property name="text">1</property>
 | 
			
		||||
                    <property name="truncate-multiline">True</property>
 | 
			
		||||
                    <property name="width-chars">5</property>
 | 
			
		||||
                    <property name="xalign">0.5</property>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkButton" id="next_page_button">
 | 
			
		||||
                    <property name="icon-name">go-next-symbolic</property>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
              </object>
 | 
			
		||||
            </child>
 | 
			
		||||
            <child>
 | 
			
		||||
              <object class="GtkOverlay" id="scroll_overlay">
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkScrolledWindow">
 | 
			
		||||
                    <property name="vexpand">True</property>
 | 
			
		||||
                    <child>
 | 
			
		||||
                      <object class="GtkListView" id="alias_list_view">
 | 
			
		||||
                        <property name="factory">
 | 
			
		||||
                          <object class="GtkSignalListItemFactory" id="alias_item_factory"/>
 | 
			
		||||
                        </property>
 | 
			
		||||
                        <property name="model">
 | 
			
		||||
                          <object class="GtkMultiSelection" id="alias_selection_model"/>
 | 
			
		||||
                        </property>
 | 
			
		||||
                      </object>
 | 
			
		||||
                    </child>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
              </object>
 | 
			
		||||
            </child>
 | 
			
		||||
          </object>
 | 
			
		||||
        </child>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
  </template>
 | 
			
		||||
  <object class="GtkBox" id="loading_overlay">
 | 
			
		||||
    <property name="orientation">vertical</property>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkSpinner">
 | 
			
		||||
        <property name="spinning">True</property>
 | 
			
		||||
        <property name="valign">end</property>
 | 
			
		||||
        <property name="vexpand">True</property>
 | 
			
		||||
        <style>
 | 
			
		||||
          <class name="loading-label"/>
 | 
			
		||||
        </style>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkLabel">
 | 
			
		||||
        <property name="label">Loading...</property>
 | 
			
		||||
        <property name="valign">start</property>
 | 
			
		||||
        <property name="vexpand">True</property>
 | 
			
		||||
        <style>
 | 
			
		||||
          <class name="loading-label"/>
 | 
			
		||||
        </style>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
    <style>
 | 
			
		||||
      <class name="loading-label"/>
 | 
			
		||||
    </style>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object class="GtkLabel" id="no_content_label">
 | 
			
		||||
    <property name="hexpand">True</property>
 | 
			
		||||
    <property name="label">No more results</property>
 | 
			
		||||
    <property name="vexpand">True</property>
 | 
			
		||||
    <style>
 | 
			
		||||
      <class name="loading-label"/>
 | 
			
		||||
    </style>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object class="GtkBox" id="error_overlay">
 | 
			
		||||
    <property name="hexpand">True</property>
 | 
			
		||||
    <property name="orientation">vertical</property>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkBox">
 | 
			
		||||
        <property name="halign">center</property>
 | 
			
		||||
        <property name="valign">end</property>
 | 
			
		||||
        <child>
 | 
			
		||||
          <object class="GtkButton" id="error_refresh_button">
 | 
			
		||||
            <property name="halign">center</property>
 | 
			
		||||
            <property name="icon-name">view-refresh-symbolic</property>
 | 
			
		||||
            <property name="valign">end</property>
 | 
			
		||||
            <property name="vexpand">True</property>
 | 
			
		||||
            <style>
 | 
			
		||||
              <class name="loading-label"/>
 | 
			
		||||
            </style>
 | 
			
		||||
          </object>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
          <object class="GtkButton" id="error_close_button">
 | 
			
		||||
            <property name="halign">center</property>
 | 
			
		||||
            <property name="icon-name">window-close-symbolic</property>
 | 
			
		||||
            <property name="valign">end</property>
 | 
			
		||||
            <style>
 | 
			
		||||
              <class name="loading-label"/>
 | 
			
		||||
            </style>
 | 
			
		||||
          </object>
 | 
			
		||||
        </child>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkLabel" id="error_label">
 | 
			
		||||
        <property name="label">ERROR</property>
 | 
			
		||||
        <property name="valign">start</property>
 | 
			
		||||
        <property name="vexpand">True</property>
 | 
			
		||||
        <style>
 | 
			
		||||
          <class name="error-message-label"/>
 | 
			
		||||
          <class name="loading-label"/>
 | 
			
		||||
        </style>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
  </object>
 | 
			
		||||
  <!-- Custom fragments -->
 | 
			
		||||
</interface>
 | 
			
		||||
							
								
								
									
										263
									
								
								simplelogin-gui/res.old/settings-panel.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								simplelogin-gui/res.old/settings-panel.ui
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,263 @@
 | 
			
		||||
<?xml version='1.0' encoding='UTF-8'?>
 | 
			
		||||
<!-- Created with Cambalache 0.16.0 -->
 | 
			
		||||
<interface>
 | 
			
		||||
  <requires lib="gtk" version="4.12"/>
 | 
			
		||||
  <template class="SLSettingsPanel" parent="GtkBox">
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkOverlay" id="overlay">
 | 
			
		||||
        <property name="child">content_wrapper</property>
 | 
			
		||||
        <property name="hexpand">True</property>
 | 
			
		||||
        <child>
 | 
			
		||||
          <object class="GtkBox" id="content_wrapper">
 | 
			
		||||
            <property name="hexpand">True</property>
 | 
			
		||||
            <property name="vexpand">True</property>
 | 
			
		||||
            <child>
 | 
			
		||||
              <object class="GtkGrid" id="content">
 | 
			
		||||
                <property name="hexpand">True</property>
 | 
			
		||||
                <property name="row-homogeneous">True</property>
 | 
			
		||||
                <property name="valign">start</property>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkButton" id="profile_image_button">
 | 
			
		||||
                    <property name="has-frame">False</property>
 | 
			
		||||
                    <child>
 | 
			
		||||
                      <object class="GtkImage" id="profile_image">
 | 
			
		||||
                        <property name="halign">center</property>
 | 
			
		||||
                        <property name="icon-name">user-info-symbolic</property>
 | 
			
		||||
                        <property name="icon-size">large</property>
 | 
			
		||||
                        <property name="margin-end">5</property>
 | 
			
		||||
                        <property name="valign">center</property>
 | 
			
		||||
                        <property name="vexpand">True</property>
 | 
			
		||||
                      </object>
 | 
			
		||||
                    </child>
 | 
			
		||||
                    <!-- Custom fragments -->
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">0</property>
 | 
			
		||||
                      <property name="column-span">1</property>
 | 
			
		||||
                      <property name="row">0</property>
 | 
			
		||||
                      <property name="row-span">2</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkBox">
 | 
			
		||||
                    <child>
 | 
			
		||||
                      <object class="GtkButton" id="remove_picture_button">
 | 
			
		||||
                        <property name="icon-name">window-close-symbolic</property>
 | 
			
		||||
                      </object>
 | 
			
		||||
                    </child>
 | 
			
		||||
                    <child>
 | 
			
		||||
                      <object class="GtkEntry" id="name_label">
 | 
			
		||||
                        <property name="editable">False</property>
 | 
			
		||||
                        <property name="has-frame">False</property>
 | 
			
		||||
                        <property name="hexpand">True</property>
 | 
			
		||||
                        <property name="input-hints">no-emoji | no-spellcheck</property>
 | 
			
		||||
                        <property name="text">Testy McTesterface</property>
 | 
			
		||||
                        <style>
 | 
			
		||||
                          <class name="login-title-label"/>
 | 
			
		||||
                        </style>
 | 
			
		||||
                      </object>
 | 
			
		||||
                    </child>
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">1</property>
 | 
			
		||||
                      <property name="column-span">1</property>
 | 
			
		||||
                      <property name="row">0</property>
 | 
			
		||||
                      <property name="row-span">1</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkBox">
 | 
			
		||||
                    <child>
 | 
			
		||||
                      <object class="GtkButton" id="edit_button">
 | 
			
		||||
                        <property name="halign">start</property>
 | 
			
		||||
                        <property name="label">Edit</property>
 | 
			
		||||
                        <property name="valign">center</property>
 | 
			
		||||
                      </object>
 | 
			
		||||
                    </child>
 | 
			
		||||
                    <child>
 | 
			
		||||
                      <object class="GtkButton" id="cancel_edit_button">
 | 
			
		||||
                        <property name="label">Cancel</property>
 | 
			
		||||
                      </object>
 | 
			
		||||
                    </child>
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">2</property>
 | 
			
		||||
                      <property name="column-span">1</property>
 | 
			
		||||
                      <property name="row">0</property>
 | 
			
		||||
                      <property name="row-span">1</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkLabel" id="stats_label">
 | 
			
		||||
                    <property name="halign">center</property>
 | 
			
		||||
                    <property name="hexpand">True</property>
 | 
			
		||||
                    <property name="label">Stats go here</property>
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">0</property>
 | 
			
		||||
                      <property name="column-span">3</property>
 | 
			
		||||
                      <property name="row">2</property>
 | 
			
		||||
                      <property name="row-span">1</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkLabel" id="email_label">
 | 
			
		||||
                    <property name="hexpand">True</property>
 | 
			
		||||
                    <property name="label">mctesterface@test.tld</property>
 | 
			
		||||
                    <property name="xalign">0.0</property>
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">1</property>
 | 
			
		||||
                      <property name="row">1</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkButton" id="logout_button">
 | 
			
		||||
                    <property name="halign">start</property>
 | 
			
		||||
                    <property name="label">Logout</property>
 | 
			
		||||
                    <property name="valign">center</property>
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">2</property>
 | 
			
		||||
                      <property name="row">1</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkLabel">
 | 
			
		||||
                    <property name="label">Account Status:</property>
 | 
			
		||||
                    <property name="margin-end">5</property>
 | 
			
		||||
                    <property name="xalign">1.0</property>
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">0</property>
 | 
			
		||||
                      <property name="column-span">1</property>
 | 
			
		||||
                      <property name="row">3</property>
 | 
			
		||||
                      <property name="row-span">1</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkLabel">
 | 
			
		||||
                    <property name="label">Api Key:</property>
 | 
			
		||||
                    <property name="margin-end">5</property>
 | 
			
		||||
                    <property name="xalign">1.0</property>
 | 
			
		||||
                    <attributes/>
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">0</property>
 | 
			
		||||
                      <property name="row">4</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkPasswordEntry" id="api_key_field">
 | 
			
		||||
                    <property name="editable">False</property>
 | 
			
		||||
                    <property name="enable-undo">False</property>
 | 
			
		||||
                    <property name="hexpand">True</property>
 | 
			
		||||
                    <property name="show-peek-icon">True</property>
 | 
			
		||||
                    <property name="valign">center</property>
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">1</property>
 | 
			
		||||
                      <property name="row">4</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkLabel" id="status_label">
 | 
			
		||||
                    <property name="hexpand">True</property>
 | 
			
		||||
                    <property name="label">Premium</property>
 | 
			
		||||
                    <property name="xalign">0.0</property>
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">1</property>
 | 
			
		||||
                      <property name="column-span">1</property>
 | 
			
		||||
                      <property name="row">3</property>
 | 
			
		||||
                      <property name="row-span">1</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkButton" id="api_key_clear_button">
 | 
			
		||||
                    <property name="halign">start</property>
 | 
			
		||||
                    <property name="label">Clear</property>
 | 
			
		||||
                    <property name="valign">center</property>
 | 
			
		||||
                    <layout>
 | 
			
		||||
                      <property name="column">2</property>
 | 
			
		||||
                      <property name="row">4</property>
 | 
			
		||||
                    </layout>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
              </object>
 | 
			
		||||
            </child>
 | 
			
		||||
          </object>
 | 
			
		||||
        </child>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
  </template>
 | 
			
		||||
  <object class="GtkBox" id="loading_overlay">
 | 
			
		||||
    <property name="hexpand">True</property>
 | 
			
		||||
    <property name="orientation">vertical</property>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkSpinner">
 | 
			
		||||
        <property name="spinning">True</property>
 | 
			
		||||
        <property name="valign">end</property>
 | 
			
		||||
        <property name="vexpand">True</property>
 | 
			
		||||
        <style>
 | 
			
		||||
          <class name="loading-label"/>
 | 
			
		||||
        </style>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkLabel">
 | 
			
		||||
        <property name="label">Loading...</property>
 | 
			
		||||
        <property name="valign">start</property>
 | 
			
		||||
        <property name="vexpand">True</property>
 | 
			
		||||
        <style>
 | 
			
		||||
          <class name="loading-label"/>
 | 
			
		||||
        </style>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
    <style>
 | 
			
		||||
      <class name="loading-label"/>
 | 
			
		||||
    </style>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object class="GtkBox" id="error_overlay">
 | 
			
		||||
    <property name="hexpand">True</property>
 | 
			
		||||
    <property name="orientation">vertical</property>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkBox">
 | 
			
		||||
        <property name="halign">center</property>
 | 
			
		||||
        <property name="valign">end</property>
 | 
			
		||||
        <child>
 | 
			
		||||
          <object class="GtkButton" id="error_refresh_button">
 | 
			
		||||
            <property name="halign">center</property>
 | 
			
		||||
            <property name="icon-name">view-refresh-symbolic</property>
 | 
			
		||||
            <property name="valign">end</property>
 | 
			
		||||
            <property name="vexpand">True</property>
 | 
			
		||||
            <style>
 | 
			
		||||
              <class name="loading-label"/>
 | 
			
		||||
            </style>
 | 
			
		||||
          </object>
 | 
			
		||||
        </child>
 | 
			
		||||
        <child>
 | 
			
		||||
          <object class="GtkButton" id="error_close_button">
 | 
			
		||||
            <property name="halign">center</property>
 | 
			
		||||
            <property name="icon-name">window-close-symbolic</property>
 | 
			
		||||
            <property name="valign">end</property>
 | 
			
		||||
            <style>
 | 
			
		||||
              <class name="loading-label"/>
 | 
			
		||||
            </style>
 | 
			
		||||
          </object>
 | 
			
		||||
        </child>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkLabel" id="error_label">
 | 
			
		||||
        <property name="label">ERROR</property>
 | 
			
		||||
        <property name="valign">start</property>
 | 
			
		||||
        <property name="vexpand">True</property>
 | 
			
		||||
        <style>
 | 
			
		||||
          <class name="error-message-label"/>
 | 
			
		||||
          <class name="loading-label"/>
 | 
			
		||||
        </style>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
  </object>
 | 
			
		||||
</interface>
 | 
			
		||||
							
								
								
									
										531
									
								
								simplelogin-gui/res.old/simplelogin.cmb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										531
									
								
								simplelogin-gui/res.old/simplelogin.cmb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,531 @@
 | 
			
		||||
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
 | 
			
		||||
<!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd">
 | 
			
		||||
<cambalache-project version="0.13.1" target_tk="gtk-4.0">
 | 
			
		||||
  <ui>
 | 
			
		||||
	(1,1,"main-window.ui","main-panel.ui",None,None,None,None,None,None,""),
 | 
			
		||||
	(3,18,None,"settings-panel.ui",None,None,None,None,None,None,None),
 | 
			
		||||
	(4,13,None,"login-window.ui",None,None,None,None,None,None,None),
 | 
			
		||||
	(5,1,None,"totp-dialog.ui",None,None,None,None,None,None,None)
 | 
			
		||||
  </ui>
 | 
			
		||||
  <css>
 | 
			
		||||
	(1,"global.css",None,1)
 | 
			
		||||
  </css>
 | 
			
		||||
  <css_ui>
 | 
			
		||||
	(1,1),
 | 
			
		||||
	(1,3),
 | 
			
		||||
	(1,4),
 | 
			
		||||
	(1,5)
 | 
			
		||||
  </css_ui>
 | 
			
		||||
  <object>
 | 
			
		||||
	(1,1,"GtkBox","SLMainPanel",None,None,None,None,None,None),
 | 
			
		||||
	(1,2,"GtkOverlay","overlay",1,None,None,None,None,None),
 | 
			
		||||
	(1,3,"GtkBox","content_wrapper",2,None,None,None,None,None),
 | 
			
		||||
	(1,4,"GtkBox",None,3,None,None,None,None,None),
 | 
			
		||||
	(1,5,"GtkSearchEntry","search_box",4,None,None,None,None,None),
 | 
			
		||||
	(1,8,"GtkDropDown","view_dropdown",4,None,None,None,1,None),
 | 
			
		||||
	(1,9,"GtkStringList",None,8,None,None,None,None,None),
 | 
			
		||||
	(1,10,"GtkButton","search_button",4,None,None,None,2,None),
 | 
			
		||||
	(1,11,"GtkBox",None,3,None,None,None,1,None),
 | 
			
		||||
	(1,12,"GtkButton","new_button",11,None,None,None,None,None),
 | 
			
		||||
	(1,13,"GtkButton","edit_button",11,None,None,None,1,None),
 | 
			
		||||
	(1,14,"GtkButton","delete_button",11,None,None,None,2,None),
 | 
			
		||||
	(1,22,"GtkBox","loading_overlay",None,None,None,None,None,None),
 | 
			
		||||
	(1,23,"GtkSpinner",None,22,None,None,None,None,None),
 | 
			
		||||
	(1,24,"GtkLabel",None,22,None,None,None,1,None),
 | 
			
		||||
	(1,28,"GtkButton","prev_page_button",11,None,None,None,3,None),
 | 
			
		||||
	(1,29,"GtkButton","next_page_button",11,None,None,None,5,None),
 | 
			
		||||
	(1,30,"GtkEntry","page_label",11,None,None,None,4,None),
 | 
			
		||||
	(1,31,"GtkOverlay","scroll_overlay",3,None,None,None,2,None),
 | 
			
		||||
	(1,32,"GtkScrolledWindow",None,31,None,None,None,None,None),
 | 
			
		||||
	(1,33,"GtkListView","alias_list_view",32,None,None,None,None,None),
 | 
			
		||||
	(1,34,"GtkSignalListItemFactory","alias_item_factory",33,None,None,None,None,None),
 | 
			
		||||
	(1,35,"GtkMultiSelection","alias_selection_model",33,None,None,None,None,None),
 | 
			
		||||
	(1,36,"GtkLabel","no_content_label",None,None,None,None,None,None),
 | 
			
		||||
	(1,37,"GtkBox","error_overlay",None,None,None,None,None,None),
 | 
			
		||||
	(1,38,"GtkBox",None,37,None,None,None,None,None),
 | 
			
		||||
	(1,39,"GtkButton","error_refresh_button",38,None,None,None,None,None),
 | 
			
		||||
	(1,40,"GtkButton","error_close_button",38,None,None,None,1,None),
 | 
			
		||||
	(1,41,"GtkLabel","error_label",37,None,None,None,1,None),
 | 
			
		||||
	(3,18,"GtkBox","SLSettingsPanel",None,None,None,None,None,None),
 | 
			
		||||
	(3,19,"GtkOverlay","overlay",18,None,None,None,None,None),
 | 
			
		||||
	(3,30,"GtkBox","loading_overlay",None,None,None,None,None,None),
 | 
			
		||||
	(3,31,"GtkSpinner",None,30,None,None,None,None,None),
 | 
			
		||||
	(3,32,"GtkLabel",None,30,None,None,None,1,None),
 | 
			
		||||
	(3,33,"GtkBox","error_overlay",None,None,None,None,None,None),
 | 
			
		||||
	(3,35,"GtkLabel","error_label",33,None,None,None,1,None),
 | 
			
		||||
	(3,45,"GtkBox",None,33,None,None,None,None,None),
 | 
			
		||||
	(3,46,"GtkButton","error_refresh_button",45,None,None,None,None,None),
 | 
			
		||||
	(3,47,"GtkButton","error_close_button",45,None,None,None,1,None),
 | 
			
		||||
	(3,48,"GtkBox","content_wrapper",19,None,None,None,-1,None),
 | 
			
		||||
	(3,49,"GtkGrid","content",48,None,None,None,None,None),
 | 
			
		||||
	(3,51,"GtkLabel","stats_label",49,None,None,None,1,None),
 | 
			
		||||
	(3,52,"GtkLabel","email_label",49,None,None,None,2,None),
 | 
			
		||||
	(3,53,"GtkButton","logout_button",49,None,None,None,3,None),
 | 
			
		||||
	(3,55,"GtkLabel",None,49,None,None,None,5,None),
 | 
			
		||||
	(3,57,"GtkLabel",None,49,None,None,None,7,None),
 | 
			
		||||
	(3,58,"GtkPasswordEntry","api_key_field",49,None,None,None,8,None),
 | 
			
		||||
	(3,59,"GtkLabel","status_label",49,None,None,None,9,None),
 | 
			
		||||
	(3,60,"GtkButton","api_key_clear_button",49,None,None,None,10,None),
 | 
			
		||||
	(3,63,"GtkButton","profile_image_button",49,None,None,None,None,""),
 | 
			
		||||
	(3,64,"GtkImage","profile_image",63,None,None,None,None,None),
 | 
			
		||||
	(3,65,"GtkBox",None,49,None,None,None,None,None),
 | 
			
		||||
	(3,66,"GtkButton","remove_picture_button",65,None,None,None,None,None),
 | 
			
		||||
	(3,67,"GtkEntry","name_label",65,None,None,None,1,None),
 | 
			
		||||
	(3,68,"GtkBox",None,49,None,None,None,None,None),
 | 
			
		||||
	(3,69,"GtkButton","edit_button",68,None,None,None,None,None),
 | 
			
		||||
	(3,70,"GtkButton","cancel_edit_button",68,None,None,None,1,None),
 | 
			
		||||
	(4,11,"GtkPopover","device_entry_popover",None,None,None,None,None,None),
 | 
			
		||||
	(4,12,"GtkLabel",None,11,None,None,None,None,None),
 | 
			
		||||
	(4,13,"GtkApplicationWindow","LoginWindow",None,None,None,None,None,None),
 | 
			
		||||
	(4,14,"GtkBox",None,13,None,None,None,-1,None),
 | 
			
		||||
	(4,30,"GtkLabel",None,14,None,None,None,1,None),
 | 
			
		||||
	(4,31,"GtkOverlay","forms_overlay",14,None,None,None,None,None),
 | 
			
		||||
	(4,32,"GtkBox","forms_wrapper",31,None,None,None,None,None),
 | 
			
		||||
	(4,33,"GtkGrid",None,32,None,None,None,None,None),
 | 
			
		||||
	(4,34,"GtkLabel",None,33,None,None,None,None,None),
 | 
			
		||||
	(4,35,"GtkLabel","error_label",33,None,None,None,1,None),
 | 
			
		||||
	(4,36,"GtkEntry","device_entry",33,None,None,None,2,None),
 | 
			
		||||
	(4,37,"GtkLabel",None,33,None,None,None,3,None),
 | 
			
		||||
	(4,38,"GtkLabel",None,33,None,None,None,4,None),
 | 
			
		||||
	(4,39,"GtkLabel",None,33,None,None,None,5,None),
 | 
			
		||||
	(4,40,"GtkEntry","email_entry",33,None,None,None,6,None),
 | 
			
		||||
	(4,41,"GtkPasswordEntry","password_entry",33,None,None,None,7,None),
 | 
			
		||||
	(4,42,"GtkButton","login_button",33,None,None,None,8,None),
 | 
			
		||||
	(4,43,"GtkLabel",None,32,None,None,None,1,None),
 | 
			
		||||
	(4,44,"GtkBox",None,32,None,None,None,2,None),
 | 
			
		||||
	(4,45,"GtkLabel",None,44,None,None,None,None,None),
 | 
			
		||||
	(4,46,"GtkPasswordEntry","api_key_entry",44,None,None,None,1,None),
 | 
			
		||||
	(4,47,"GtkButton","api_key_button",44,None,None,None,2,None),
 | 
			
		||||
	(4,48,"GtkBox","loading_overlay",None,None,None,None,None,None),
 | 
			
		||||
	(4,49,"GtkSpinner",None,48,None,None,None,None,None),
 | 
			
		||||
	(4,50,"GtkLabel",None,48,None,None,None,1,None),
 | 
			
		||||
	(5,1,"GtkWindow","SLTotpDialog",None,None,None,None,None,None),
 | 
			
		||||
	(5,2,"GtkOverlay","overlay",1,None,None,None,-1,None),
 | 
			
		||||
	(5,11,"GtkBox","loading_overlay",None,None,None,None,None,None),
 | 
			
		||||
	(5,12,"GtkSpinner",None,11,None,None,None,None,None),
 | 
			
		||||
	(5,13,"GtkLabel",None,11,None,None,None,1,None),
 | 
			
		||||
	(5,14,"GtkGrid","form_wrapper",2,None,None,None,None,None),
 | 
			
		||||
	(5,15,"GtkBox",None,14,None,None,None,None,None),
 | 
			
		||||
	(5,16,"GtkImage",None,15,None,None,None,None,None),
 | 
			
		||||
	(5,17,"GtkLabel",None,15,None,None,None,1,None),
 | 
			
		||||
	(5,19,"GtkButton","accept_button",14,None,None,None,2,None),
 | 
			
		||||
	(5,20,"GtkButton","cancel_button",14,None,None,None,3,None),
 | 
			
		||||
	(5,21,"GtkEntry","code_entry",14,None,None,None,4,None),
 | 
			
		||||
	(5,23,"GtkLabel","error_label",14,None,None,None,4,None)
 | 
			
		||||
  </object>
 | 
			
		||||
  <object_property>
 | 
			
		||||
	(1,3,"GtkOrientable","orientation","vertical",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,3,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,5,"GtkSearchEntry","placeholder-text","Filter by email, description, etc.",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,5,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,8,"GtkDropDown","model",None,None,None,None,None,9,None,None,None,None),
 | 
			
		||||
	(1,8,"GtkDropDown","selected","0",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,8,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,10,"GtkButton","label","Search",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,12,"GtkButton","label","New",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,13,"GtkButton","label","Edit",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,14,"GtkButton","label","Delete",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,22,"GtkOrientable","orientation","vertical",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,23,"GtkSpinner","spinning","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,23,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,23,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,24,"GtkLabel","label","Loading...",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,24,"GtkWidget","valign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,24,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,28,"GtkButton","icon-name","go-previous-symbolic",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,28,"GtkWidget","halign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,28,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,29,"GtkButton","icon-name","go-next-symbolic",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,30,"GtkEditable","max-width-chars","0",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,30,"GtkEditable","text","1",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,30,"GtkEditable","width-chars","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,30,"GtkEditable","xalign","0.5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,30,"GtkEntry","has-frame","False",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,30,"GtkEntry","input-hints","no-emoji | no-spellcheck",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,30,"GtkEntry","input-purpose","digits",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,30,"GtkEntry","truncate-multiline","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,32,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,33,"GtkListView","factory",None,None,None,None,None,34,None,None,None,None),
 | 
			
		||||
	(1,33,"GtkListView","model",None,None,None,None,None,35,None,None,None,None),
 | 
			
		||||
	(1,36,"GtkLabel","label","No more results",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,36,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,36,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,37,"GtkOrientable","orientation","vertical",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,37,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,38,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,38,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,39,"GtkButton","icon-name","view-refresh-symbolic",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,39,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,39,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,39,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,40,"GtkButton","icon-name","window-close-symbolic",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,40,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,40,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,41,"GtkLabel","label","ERROR",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,41,"GtkWidget","valign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(1,41,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,19,"GtkOverlay","child","48",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,19,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,30,"GtkOrientable","orientation","vertical",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,30,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,31,"GtkSpinner","spinning","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,31,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,31,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,32,"GtkLabel","label","Loading...",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,32,"GtkWidget","valign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,32,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,33,"GtkOrientable","orientation","vertical",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,33,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,35,"GtkLabel","label","ERROR",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,35,"GtkWidget","valign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,35,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,45,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,45,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,46,"GtkButton","icon-name","view-refresh-symbolic",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,46,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,46,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,46,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,47,"GtkButton","icon-name","window-close-symbolic",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,47,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,47,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,48,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,48,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,49,"GtkGrid","row-homogeneous","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,49,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,49,"GtkWidget","valign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,51,"GtkLabel","label","Stats go here",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,51,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,51,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,52,"GtkLabel","label","mctesterface@test.tld",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,52,"GtkLabel","xalign","0.0",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,52,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,53,"GtkButton","label","Logout",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,53,"GtkWidget","halign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,53,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,55,"GtkLabel","label","Account Status:",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,55,"GtkLabel","xalign","1.0",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,55,"GtkWidget","margin-end","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,57,"GtkLabel","label","Api Key:",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,57,"GtkLabel","xalign","1.0",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,57,"GtkWidget","margin-end","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,58,"GtkEditable","editable","False",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,58,"GtkEditable","enable-undo","False",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,58,"GtkPasswordEntry","show-peek-icon","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,58,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,58,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,59,"GtkLabel","label","Premium",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,59,"GtkLabel","xalign","0.0",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,59,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,60,"GtkButton","label","Clear",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,60,"GtkWidget","halign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,60,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,63,"GtkButton","has-frame","False",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,64,"GtkImage","icon-name","user-info-symbolic",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,64,"GtkImage","icon-size","large",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,64,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,64,"GtkWidget","margin-end","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,64,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,64,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,66,"GtkButton","icon-name","window-close-symbolic",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,67,"GtkEditable","editable","False",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,67,"GtkEditable","text","Testy McTesterface",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,67,"GtkEntry","has-frame","False",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,67,"GtkEntry","input-hints","no-emoji | no-spellcheck",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,67,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,69,"GtkButton","label","Edit",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,69,"GtkWidget","halign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,69,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(3,70,"GtkButton","label","Cancel",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,11,"GtkPopover","child",None,None,None,None,None,12,None,None,None,None),
 | 
			
		||||
	(4,12,"GtkAccessible","accessible-role","tooltip",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,12,"GtkLabel","label","This is the human readable name that will show up in the API key section of the SimpleLogin website.",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,12,"GtkLabel","max-width-chars","30",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,12,"GtkLabel","wrap","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,13,"GtkWindow","title","SimpleLogin",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,14,"GtkOrientable","orientation","vertical",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,30,"GtkLabel","label","Don't have an account? You can register <a href=\"https://app.simplelogin.io/auth/register\">here</a>.",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,30,"GtkLabel","use-markup","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,30,"GtkLabel","yalign","0.0",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,30,"GtkWidget","margin-bottom","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,30,"GtkWidget","valign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,30,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,31,"GtkOverlay","child","32",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,31,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,31,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,32,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,32,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,33,"GtkWidget","halign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,33,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,33,"GtkWidget","margin-bottom","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,33,"GtkWidget","margin-end","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,33,"GtkWidget","margin-start","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,33,"GtkWidget","margin-top","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,33,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,34,"GtkLabel","label","Login:",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,34,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,34,"GtkWidget","margin-bottom","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,34,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,35,"GtkLabel","label","ERROR",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,35,"GtkWidget","margin-top","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,36,"GtkEditable","width-chars","18",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,36,"GtkEntry","placeholder-text","My Awesome Computer",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,36,"GtkEntry","secondary-icon-name","dialog-question-symbolic",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,36,"GtkEntry","truncate-multiline","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,36,"GtkWidget","margin-start","6",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,37,"GtkLabel","label","Device:",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,37,"GtkLabel","xalign","0.0",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,38,"GtkLabel","label","Email:",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,38,"GtkLabel","xalign","0.0",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,39,"GtkLabel","label","Password:",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,39,"GtkLabel","xalign","0.0",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,40,"GtkEntry","input-purpose","email",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,40,"GtkEntry","truncate-multiline","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,40,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,40,"GtkWidget","margin-start","6",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,40,"GtkWidget","receives-default","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,41,"GtkPasswordEntry","show-peek-icon","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,41,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,41,"GtkWidget","margin-start","6",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,42,"GtkButton","label","Login",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,42,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,42,"GtkWidget","margin-top","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,42,"GtkWidget","sensitive","False",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,42,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,43,"GtkLabel","justify","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,43,"GtkLabel","label","- or -",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,43,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,44,"GtkOrientable","orientation","vertical",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,44,"GtkWidget","halign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,44,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,44,"GtkWidget","margin-bottom","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,44,"GtkWidget","margin-end","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,44,"GtkWidget","margin-start","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,44,"GtkWidget","margin-top","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,44,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,45,"GtkLabel","label","Set API Key:",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,45,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,45,"GtkWidget","margin-bottom","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,46,"GtkEditable","width-chars","27",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,46,"GtkPasswordEntry","show-peek-icon","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,46,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,46,"GtkWidget","margin-end","3",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,46,"GtkWidget","margin-start","8",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,47,"GtkButton","label","Accept",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,47,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,47,"GtkWidget","margin-top","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,47,"GtkWidget","sensitive","False",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,48,"GtkOrientable","orientation","vertical",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,49,"GtkSpinner","spinning","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,49,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,49,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,50,"GtkLabel","label","Loading...",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,50,"GtkWidget","valign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(4,50,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,1,"GtkWindow","modal","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,1,"GtkWindow","title","TOTP Entry",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,2,"GtkOverlay","child","14",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,2,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,2,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,2,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,2,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,11,"GtkOrientable","orientation","vertical",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,12,"GtkSpinner","spinning","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,12,"GtkWidget","valign","end",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,12,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,13,"GtkLabel","label","Loading...",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,13,"GtkWidget","valign","start",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,13,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,14,"GtkGrid","column-spacing","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,14,"GtkGrid","row-spacing","5",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,14,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,14,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,14,"GtkWidget","margin-bottom","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,14,"GtkWidget","margin-end","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,14,"GtkWidget","margin-start","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,14,"GtkWidget","margin-top","10",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,14,"GtkWidget","valign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,14,"GtkWidget","vexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,15,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,15,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,16,"GtkImage","icon-name","dialog-password-symbolic",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,16,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,17,"GtkLabel","label","TOTP",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,19,"GtkButton","label","Accept",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,20,"GtkButton","label","Cancel",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,21,"GtkEntry","placeholder-text","TOTP Code",None,None,None,None,None,None,None,None,None),
 | 
			
		||||
	(5,23,"GtkLabel","label","ERROR",None,None,None,None,None,None,None,None,None)
 | 
			
		||||
  </object_property>
 | 
			
		||||
  <object_layout_property>
 | 
			
		||||
	(3,49,51,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(3,49,51,"GtkGridLayoutChild","column-span","3",None,None,None,None),
 | 
			
		||||
	(3,49,51,"GtkGridLayoutChild","row","2",None,None,None,None),
 | 
			
		||||
	(3,49,51,"GtkGridLayoutChild","row-span","1",None,None,None,None),
 | 
			
		||||
	(3,49,52,"GtkGridLayoutChild","column","1",None,None,None,None),
 | 
			
		||||
	(3,49,52,"GtkGridLayoutChild","row","1",None,None,None,None),
 | 
			
		||||
	(3,49,53,"GtkGridLayoutChild","column","2",None,None,None,None),
 | 
			
		||||
	(3,49,53,"GtkGridLayoutChild","row","1",None,None,None,None),
 | 
			
		||||
	(3,49,55,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(3,49,55,"GtkGridLayoutChild","column-span","1",None,None,None,None),
 | 
			
		||||
	(3,49,55,"GtkGridLayoutChild","row","3",None,None,None,None),
 | 
			
		||||
	(3,49,55,"GtkGridLayoutChild","row-span","1",None,None,None,None),
 | 
			
		||||
	(3,49,57,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(3,49,57,"GtkGridLayoutChild","row","4",None,None,None,None),
 | 
			
		||||
	(3,49,58,"GtkGridLayoutChild","column","1",None,None,None,None),
 | 
			
		||||
	(3,49,58,"GtkGridLayoutChild","row","4",None,None,None,None),
 | 
			
		||||
	(3,49,59,"GtkGridLayoutChild","column","1",None,None,None,None),
 | 
			
		||||
	(3,49,59,"GtkGridLayoutChild","column-span","1",None,None,None,None),
 | 
			
		||||
	(3,49,59,"GtkGridLayoutChild","row","3",None,None,None,None),
 | 
			
		||||
	(3,49,59,"GtkGridLayoutChild","row-span","1",None,None,None,None),
 | 
			
		||||
	(3,49,60,"GtkGridLayoutChild","column","2",None,None,None,None),
 | 
			
		||||
	(3,49,60,"GtkGridLayoutChild","row","4",None,None,None,None),
 | 
			
		||||
	(3,49,63,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(3,49,63,"GtkGridLayoutChild","column-span","1",None,None,None,None),
 | 
			
		||||
	(3,49,63,"GtkGridLayoutChild","row-span","2",None,None,None,None),
 | 
			
		||||
	(3,49,65,"GtkGridLayoutChild","column","1",None,None,None,None),
 | 
			
		||||
	(3,49,65,"GtkGridLayoutChild","column-span","1",None,None,None,None),
 | 
			
		||||
	(3,49,65,"GtkGridLayoutChild","row","0",None,None,None,None),
 | 
			
		||||
	(3,49,65,"GtkGridLayoutChild","row-span","1",None,None,None,None),
 | 
			
		||||
	(3,49,68,"GtkGridLayoutChild","column","2",None,None,None,None),
 | 
			
		||||
	(3,49,68,"GtkGridLayoutChild","column-span","1",None,None,None,None),
 | 
			
		||||
	(3,49,68,"GtkGridLayoutChild","row","0",None,None,None,None),
 | 
			
		||||
	(3,49,68,"GtkGridLayoutChild","row-span","1",None,None,None,None),
 | 
			
		||||
	(4,33,34,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(4,33,34,"GtkGridLayoutChild","column-span","2",None,None,None,None),
 | 
			
		||||
	(4,33,34,"GtkGridLayoutChild","row","0",None,None,None,None),
 | 
			
		||||
	(4,33,35,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(4,33,35,"GtkGridLayoutChild","column-span","2",None,None,None,None),
 | 
			
		||||
	(4,33,35,"GtkGridLayoutChild","row","4",None,None,None,None),
 | 
			
		||||
	(4,33,36,"GtkGridLayoutChild","column","1",None,None,None,None),
 | 
			
		||||
	(4,33,36,"GtkGridLayoutChild","row","3",None,None,None,None),
 | 
			
		||||
	(4,33,37,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(4,33,37,"GtkGridLayoutChild","row","3",None,None,None,None),
 | 
			
		||||
	(4,33,38,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(4,33,38,"GtkGridLayoutChild","row","1",None,None,None,None),
 | 
			
		||||
	(4,33,39,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(4,33,39,"GtkGridLayoutChild","row","2",None,None,None,None),
 | 
			
		||||
	(4,33,40,"GtkGridLayoutChild","column","1",None,None,None,None),
 | 
			
		||||
	(4,33,40,"GtkGridLayoutChild","row","1",None,None,None,None),
 | 
			
		||||
	(4,33,41,"GtkGridLayoutChild","column","1",None,None,None,None),
 | 
			
		||||
	(4,33,41,"GtkGridLayoutChild","row","2",None,None,None,None),
 | 
			
		||||
	(4,33,42,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(4,33,42,"GtkGridLayoutChild","column-span","2",None,None,None,None),
 | 
			
		||||
	(4,33,42,"GtkGridLayoutChild","row","5",None,None,None,None),
 | 
			
		||||
	(5,14,15,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(5,14,15,"GtkGridLayoutChild","column-span","2",None,None,None,None),
 | 
			
		||||
	(5,14,15,"GtkGridLayoutChild","row","0",None,None,None,None),
 | 
			
		||||
	(5,14,19,"GtkGridLayoutChild","column","1",None,None,None,None),
 | 
			
		||||
	(5,14,19,"GtkGridLayoutChild","row","3",None,None,None,None),
 | 
			
		||||
	(5,14,20,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(5,14,20,"GtkGridLayoutChild","row","3",None,None,None,None),
 | 
			
		||||
	(5,14,21,"GtkGridLayoutChild","column","0",None,None,None,None),
 | 
			
		||||
	(5,14,21,"GtkGridLayoutChild","column-span","2",None,None,None,None),
 | 
			
		||||
	(5,14,21,"GtkGridLayoutChild","row","1",None,None,None,None),
 | 
			
		||||
	(5,14,23,"GtkGridLayoutChild","column-span","2",None,None,None,None),
 | 
			
		||||
	(5,14,23,"GtkGridLayoutChild","row","2",None,None,None,None)
 | 
			
		||||
  </object_layout_property>
 | 
			
		||||
  <object_data>
 | 
			
		||||
	(4,34,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(4,34,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(4,35,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(4,35,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(4,40,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(4,33,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(4,33,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(4,45,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(4,45,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(1,9,"GtkStringList",2,5,"Disabled only",1,None,None,None,None),
 | 
			
		||||
	(1,9,"GtkStringList",2,4,"Enabled only",1,None,None,None,None),
 | 
			
		||||
	(1,9,"GtkStringList",2,3,"Pinned only",1,None,None,None,None),
 | 
			
		||||
	(1,9,"GtkStringList",2,2,"All aliases",1,None,None,None,None),
 | 
			
		||||
	(1,9,"GtkStringList",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(1,22,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(1,22,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(1,24,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(1,24,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(1,23,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(1,23,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(4,49,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(4,49,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(4,50,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(4,50,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(4,48,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(4,48,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(5,17,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(5,17,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(5,23,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(5,23,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(5,13,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(5,13,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(5,12,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(5,12,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(5,11,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(5,11,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(1,36,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(1,36,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(3,31,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(3,31,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(3,32,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(3,32,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(3,30,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(3,30,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(3,57,"GtkLabel",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(1,39,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(1,39,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(1,40,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(1,40,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(1,41,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(1,41,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(1,41,"GtkWidget",2,3,None,1,None,None,None,None),
 | 
			
		||||
	(3,67,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(3,67,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(3,47,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(3,47,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(3,46,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(3,46,"GtkWidget",1,1,None,None,None,None,None,None),
 | 
			
		||||
	(3,35,"GtkWidget",2,3,None,1,None,None,None,None),
 | 
			
		||||
	(3,35,"GtkWidget",2,2,None,1,None,None,None,None),
 | 
			
		||||
	(3,35,"GtkWidget",1,1,None,None,None,None,None,None)
 | 
			
		||||
  </object_data>
 | 
			
		||||
  <object_data_arg>
 | 
			
		||||
	(4,34,"GtkWidget",2,2,"name","login-title-label"),
 | 
			
		||||
	(4,35,"GtkWidget",2,2,"name","error-message-label"),
 | 
			
		||||
	(4,33,"GtkWidget",2,2,"name","login-form-warpper"),
 | 
			
		||||
	(4,45,"GtkWidget",2,2,"name","login-title-label"),
 | 
			
		||||
	(1,9,"GtkStringList",2,5,"translatable",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,5,"context",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,5,"comments",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,4,"translatable",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,4,"context",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,4,"comments",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,3,"translatable",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,3,"context",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,3,"comments",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,2,"translatable",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,2,"context",None),
 | 
			
		||||
	(1,9,"GtkStringList",2,2,"comments",None),
 | 
			
		||||
	(1,24,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(1,22,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(1,23,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(4,49,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(4,50,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(4,48,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(5,17,"GtkWidget",2,2,"name","login-title-label"),
 | 
			
		||||
	(5,23,"GtkWidget",2,2,"name","error-message-label"),
 | 
			
		||||
	(5,13,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(5,12,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(5,11,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(1,36,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(3,31,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(3,32,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(3,30,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(1,39,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(1,40,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(1,41,"GtkWidget",2,2,"name","error-message-label"),
 | 
			
		||||
	(1,41,"GtkWidget",2,3,"name","loading-label"),
 | 
			
		||||
	(3,67,"GtkWidget",2,2,"name","login-title-label"),
 | 
			
		||||
	(3,47,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(3,46,"GtkWidget",2,2,"name","loading-label"),
 | 
			
		||||
	(3,35,"GtkWidget",2,3,"name","loading-label"),
 | 
			
		||||
	(3,35,"GtkWidget",2,2,"name","error-message-label")
 | 
			
		||||
  </object_data_arg>
 | 
			
		||||
</cambalache-project>
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
[wrap-git]
 | 
			
		||||
directory = blueprint-compiler
 | 
			
		||||
url = https://gitlab.gnome.org/jwestman/blueprint-compiler.git
 | 
			
		||||
revision = v0.10.0
 | 
			
		||||
depth = 1
 | 
			
		||||
 | 
			
		||||
[provide]
 | 
			
		||||
program_names = blueprint-compiler
 | 
			
		||||
							
								
								
									
										124
									
								
								simplelogin-gui/res.old/totp-dialog.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								simplelogin-gui/res.old/totp-dialog.ui
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,124 @@
 | 
			
		||||
<?xml version='1.0' encoding='UTF-8'?>
 | 
			
		||||
<!-- Created with Cambalache 0.16.0 -->
 | 
			
		||||
<interface>
 | 
			
		||||
  <requires lib="gtk" version="4.12"/>
 | 
			
		||||
  <template class="SLTotpDialog" parent="GtkWindow">
 | 
			
		||||
    <property name="modal">True</property>
 | 
			
		||||
    <property name="title">TOTP Entry</property>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkOverlay" id="overlay">
 | 
			
		||||
        <property name="child">form_wrapper</property>
 | 
			
		||||
        <property name="halign">center</property>
 | 
			
		||||
        <property name="hexpand">True</property>
 | 
			
		||||
        <property name="valign">center</property>
 | 
			
		||||
        <property name="vexpand">True</property>
 | 
			
		||||
        <child>
 | 
			
		||||
          <object class="GtkGrid" id="form_wrapper">
 | 
			
		||||
            <property name="column-spacing">5</property>
 | 
			
		||||
            <property name="halign">center</property>
 | 
			
		||||
            <property name="hexpand">True</property>
 | 
			
		||||
            <property name="margin-bottom">10</property>
 | 
			
		||||
            <property name="margin-end">10</property>
 | 
			
		||||
            <property name="margin-start">10</property>
 | 
			
		||||
            <property name="margin-top">10</property>
 | 
			
		||||
            <property name="row-spacing">5</property>
 | 
			
		||||
            <property name="valign">center</property>
 | 
			
		||||
            <property name="vexpand">True</property>
 | 
			
		||||
            <child>
 | 
			
		||||
              <object class="GtkBox">
 | 
			
		||||
                <property name="halign">center</property>
 | 
			
		||||
                <property name="hexpand">True</property>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkImage">
 | 
			
		||||
                    <property name="halign">center</property>
 | 
			
		||||
                    <property name="icon-name">dialog-password-symbolic</property>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <child>
 | 
			
		||||
                  <object class="GtkLabel">
 | 
			
		||||
                    <property name="label">TOTP</property>
 | 
			
		||||
                    <style>
 | 
			
		||||
                      <class name="login-title-label"/>
 | 
			
		||||
                    </style>
 | 
			
		||||
                  </object>
 | 
			
		||||
                </child>
 | 
			
		||||
                <layout>
 | 
			
		||||
                  <property name="column">0</property>
 | 
			
		||||
                  <property name="column-span">2</property>
 | 
			
		||||
                  <property name="row">0</property>
 | 
			
		||||
                </layout>
 | 
			
		||||
              </object>
 | 
			
		||||
            </child>
 | 
			
		||||
            <child>
 | 
			
		||||
              <object class="GtkButton" id="accept_button">
 | 
			
		||||
                <property name="label">Accept</property>
 | 
			
		||||
                <layout>
 | 
			
		||||
                  <property name="column">1</property>
 | 
			
		||||
                  <property name="row">3</property>
 | 
			
		||||
                </layout>
 | 
			
		||||
              </object>
 | 
			
		||||
            </child>
 | 
			
		||||
            <child>
 | 
			
		||||
              <object class="GtkButton" id="cancel_button">
 | 
			
		||||
                <property name="label">Cancel</property>
 | 
			
		||||
                <layout>
 | 
			
		||||
                  <property name="column">0</property>
 | 
			
		||||
                  <property name="row">3</property>
 | 
			
		||||
                </layout>
 | 
			
		||||
              </object>
 | 
			
		||||
            </child>
 | 
			
		||||
            <child>
 | 
			
		||||
              <object class="GtkEntry" id="code_entry">
 | 
			
		||||
                <property name="placeholder-text">TOTP Code</property>
 | 
			
		||||
                <layout>
 | 
			
		||||
                  <property name="column">0</property>
 | 
			
		||||
                  <property name="column-span">2</property>
 | 
			
		||||
                  <property name="row">1</property>
 | 
			
		||||
                </layout>
 | 
			
		||||
              </object>
 | 
			
		||||
            </child>
 | 
			
		||||
            <child>
 | 
			
		||||
              <object class="GtkLabel" id="error_label">
 | 
			
		||||
                <property name="label">ERROR</property>
 | 
			
		||||
                <style>
 | 
			
		||||
                  <class name="error-message-label"/>
 | 
			
		||||
                </style>
 | 
			
		||||
                <layout>
 | 
			
		||||
                  <property name="column">0</property>
 | 
			
		||||
                  <property name="column-span">2</property>
 | 
			
		||||
                  <property name="row">2</property>
 | 
			
		||||
                </layout>
 | 
			
		||||
              </object>
 | 
			
		||||
            </child>
 | 
			
		||||
          </object>
 | 
			
		||||
        </child>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
  </template>
 | 
			
		||||
  <object class="GtkBox" id="loading_overlay">
 | 
			
		||||
    <property name="orientation">vertical</property>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkSpinner">
 | 
			
		||||
        <property name="spinning">True</property>
 | 
			
		||||
        <property name="valign">end</property>
 | 
			
		||||
        <property name="vexpand">True</property>
 | 
			
		||||
        <style>
 | 
			
		||||
          <class name="loading-label"/>
 | 
			
		||||
        </style>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
    <child>
 | 
			
		||||
      <object class="GtkLabel">
 | 
			
		||||
        <property name="label">Loading...</property>
 | 
			
		||||
        <property name="valign">start</property>
 | 
			
		||||
        <property name="vexpand">True</property>
 | 
			
		||||
        <style>
 | 
			
		||||
          <class name="loading-label"/>
 | 
			
		||||
        </style>
 | 
			
		||||
      </object>
 | 
			
		||||
    </child>
 | 
			
		||||
    <style>
 | 
			
		||||
      <class name="loading-label"/>
 | 
			
		||||
    </style>
 | 
			
		||||
  </object>
 | 
			
		||||
</interface>
 | 
			
		||||
							
								
								
									
										50
									
								
								simplelogin-gui/src/application.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								simplelogin-gui/src/application.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
			
		||||
use crate::login_window::LoginWindow;
 | 
			
		||||
 | 
			
		||||
use gtk4 as gtk;
 | 
			
		||||
use gtk::{glib, gio, prelude::*, subclass::prelude::*};
 | 
			
		||||
 | 
			
		||||
mod imp {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    
 | 
			
		||||
    #[derive(Debug)]
 | 
			
		||||
    pub struct Application {
 | 
			
		||||
        pub settings: gio::Settings,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Default for Application {
 | 
			
		||||
        fn default() -> Self {
 | 
			
		||||
            Self {
 | 
			
		||||
                settings: gio::Settings::new(crate::APP_ID)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[glib::object_subclass]
 | 
			
		||||
    impl ObjectSubclass for Application {
 | 
			
		||||
        const NAME: &'static str = "Application";
 | 
			
		||||
        type Type = super::Application;
 | 
			
		||||
        type ParentType = gtk::Application;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl ApplicationImpl for Application {
 | 
			
		||||
        fn activate(&self) {
 | 
			
		||||
            let login_window = LoginWindow::new(&self.obj());
 | 
			
		||||
            login_window.present();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl ObjectImpl for Application {}
 | 
			
		||||
    impl GtkApplicationImpl for Application {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
glib::wrapper! {
 | 
			
		||||
    pub struct Application(ObjectSubclass<imp::Application>)
 | 
			
		||||
        @extends gtk::Application, gio::Application,
 | 
			
		||||
        @implements gio::ActionMap, gio::ActionGroup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Application {
 | 
			
		||||
    pub fn new(app_id: &str) -> Self {
 | 
			
		||||
        glib::Object::builder().property("application-id", app_id).build()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										65
									
								
								simplelogin-gui/src/login_window.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								simplelogin-gui/src/login_window.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
			
		||||
use gtk4 as gtk;
 | 
			
		||||
use gtk::{glib, gio, subclass::prelude::*};
 | 
			
		||||
 | 
			
		||||
mod imp {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    
 | 
			
		||||
    #[derive(Debug, Default, gtk::CompositeTemplate)]
 | 
			
		||||
    #[template(file = "data/login_window.blp")]
 | 
			
		||||
    pub struct LoginWindow {
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub forms_overlay: TemplateChild<gtk::Overlay>,
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub forms_wrapper: TemplateChild<gtk::Box>,
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub error_label: TemplateChild<gtk::Label>,
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub device_entry: TemplateChild<gtk::Entry>,
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub email_entry: TemplateChild<gtk::Entry>,
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub password_entry: TemplateChild<gtk::PasswordEntry>,
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub login_button: TemplateChild<gtk::Button>,
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub api_key_entry: TemplateChild<gtk::PasswordEntry>,
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub api_key_button: TemplateChild<gtk::Button>,
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub device_entry_popover: TemplateChild<gtk::Popover>,
 | 
			
		||||
        #[template_child]
 | 
			
		||||
        pub loading_overlay: TemplateChild<gtk::Box>,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[glib::object_subclass]
 | 
			
		||||
    impl ObjectSubclass for LoginWindow {
 | 
			
		||||
        const NAME: &'static str = "LoginWindow";
 | 
			
		||||
        type Type = super::LoginWindow;
 | 
			
		||||
        type ParentType = gtk::ApplicationWindow;
 | 
			
		||||
 | 
			
		||||
        fn class_init(class: &mut Self::Class) {
 | 
			
		||||
            class.bind_template();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
 | 
			
		||||
            obj.init_template();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl ObjectImpl for LoginWindow {}
 | 
			
		||||
    impl WidgetImpl for LoginWindow {}
 | 
			
		||||
    impl WindowImpl for LoginWindow {}
 | 
			
		||||
    impl ApplicationWindowImpl for LoginWindow {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
glib::wrapper! {
 | 
			
		||||
    pub struct LoginWindow(ObjectSubclass<imp::LoginWindow>)
 | 
			
		||||
        @extends gtk::Widget, gtk::Window, gtk::ApplicationWindow,
 | 
			
		||||
        @implements gio::ActionMap, gio::ActionGroup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl LoginWindow {
 | 
			
		||||
    pub fn new(app: &crate::application::Application) -> Self {
 | 
			
		||||
        glib::Object::builder().property("application", app).build()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,3 +1,20 @@
 | 
			
		||||
fn main() {
 | 
			
		||||
    println!("Hello, world!");
 | 
			
		||||
mod login_window;
 | 
			
		||||
mod totp_window;
 | 
			
		||||
mod application;
 | 
			
		||||
 | 
			
		||||
use gtk4 as gtk;
 | 
			
		||||
use gtk::prelude::*;
 | 
			
		||||
use gtk::glib::{self, g_message};
 | 
			
		||||
 | 
			
		||||
const APP_ID: &str = "im.zander.SimpleLogin";
 | 
			
		||||
 | 
			
		||||
fn main() -> glib::ExitCode {
 | 
			
		||||
    if cfg!(debug_assertions) {
 | 
			
		||||
        // allow us to use a test schema for debug runs
 | 
			
		||||
        let schema_dir = concat!(env!("OUT_DIR"), "/schemas/");
 | 
			
		||||
        g_message!("SimpleLogin", "Using schema dir: \"{}\"", schema_dir);
 | 
			
		||||
        std::env::set_var("GSETTINGS_SCHEMA_DIR", schema_dir);
 | 
			
		||||
    }
 | 
			
		||||
    let app = application::Application::new(APP_ID);
 | 
			
		||||
    app.run()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										43
									
								
								simplelogin-gui/src/totp_window.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								simplelogin-gui/src/totp_window.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
use gtk4 as gtk;
 | 
			
		||||
use gtk::{glib, gio, prelude::*, subclass::prelude::*};
 | 
			
		||||
 | 
			
		||||
mod imp {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    
 | 
			
		||||
    #[derive(Debug, Default, gtk::CompositeTemplate)]
 | 
			
		||||
    #[template(file = "data/totp_window.blp")]
 | 
			
		||||
    pub struct TotpWindow {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[glib::object_subclass]
 | 
			
		||||
    impl ObjectSubclass for TotpWindow {
 | 
			
		||||
        const NAME: &'static str = "TotpWindow";
 | 
			
		||||
        type Type = super::TotpWindow;
 | 
			
		||||
        type ParentType = gtk::Window;
 | 
			
		||||
 | 
			
		||||
        fn class_init(class: &mut Self::Class) {
 | 
			
		||||
            class.bind_template();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
 | 
			
		||||
            obj.init_template();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl ObjectImpl for TotpWindow {}
 | 
			
		||||
    impl WidgetImpl for TotpWindow {}
 | 
			
		||||
    impl WindowImpl for TotpWindow {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
glib::wrapper! {
 | 
			
		||||
    pub struct TotpWindow(ObjectSubclass<imp::TotpWindow>)
 | 
			
		||||
        @extends gtk::Widget, gtk::Window,
 | 
			
		||||
        @implements gio::ActionMap, gio::ActionGroup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TotpWindow {
 | 
			
		||||
    pub fn new<P: IsA<gtk::Application>>(app: &P) -> Self {
 | 
			
		||||
        glib::Object::builder().property("application", app).build()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,9 @@
 | 
			
		||||
#![allow(dead_code)]
 | 
			
		||||
use core::fmt;
 | 
			
		||||
 | 
			
		||||
use serde::{Serialize, Deserialize};
 | 
			
		||||
    
 | 
			
		||||
struct Context {
 | 
			
		||||
pub struct Context {
 | 
			
		||||
    client: reqwest::Client,
 | 
			
		||||
    api_key: Option<String>,
 | 
			
		||||
    url: String,
 | 
			
		||||
@ -32,12 +34,60 @@ struct LoginResponse {
 | 
			
		||||
    api_key: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub enum Error {
 | 
			
		||||
    FIDO(String),
 | 
			
		||||
    Json(String),
 | 
			
		||||
    Auth(String),
 | 
			
		||||
    Http(String),
 | 
			
		||||
    Internal(String)
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
struct MfaRequest<'a> {
 | 
			
		||||
    mfa_token: &'a str,
 | 
			
		||||
    mfa_key: &'a str,
 | 
			
		||||
    device: &'a str
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
struct MfaResponse {
 | 
			
		||||
    name: String,
 | 
			
		||||
    api_key: String,
 | 
			
		||||
    email: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub enum ErrorKind {
 | 
			
		||||
    State,
 | 
			
		||||
    Json,
 | 
			
		||||
    Http,
 | 
			
		||||
    Auth,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Error {
 | 
			
		||||
    kind: ErrorKind,
 | 
			
		||||
    msg: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Error {
 | 
			
		||||
    pub(crate) fn new<T>(
 | 
			
		||||
        kind: ErrorKind, msg: T
 | 
			
		||||
    ) -> Self where T: Into<String> {
 | 
			
		||||
        Self {kind, msg: msg.into()}
 | 
			
		||||
    } 
 | 
			
		||||
 | 
			
		||||
    pub fn is_state(&self) -> bool {
 | 
			
		||||
        matches!(self.kind, ErrorKind::State)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn is_http(&self) -> bool {
 | 
			
		||||
        matches!(self.kind, ErrorKind::Http)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn is_auth(&self) -> bool {
 | 
			
		||||
        matches!(self.kind, ErrorKind::Auth)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn is_json(&self) -> bool {
 | 
			
		||||
        matches!(self.kind, ErrorKind::Json)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for Error {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        write!(f, "{}", self.msg)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const DEFAULT_URL: &str = "https://app.simplelogin.io/";
 | 
			
		||||
@ -63,6 +113,14 @@ impl Context {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn api_key(&self) -> Option<&String> {
 | 
			
		||||
        self.api_key.as_ref()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn set_api_key(&mut self, api_key: Option<&str>) {
 | 
			
		||||
        self.api_key = api_key.map(|s| s.to_owned());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn parse_error_json(error_body: &String) -> String {
 | 
			
		||||
        match serde_json::from_str(error_body) {
 | 
			
		||||
            Ok::<ErrorResponse, _>(obj) => obj.error,
 | 
			
		||||
@ -77,22 +135,43 @@ impl Context {
 | 
			
		||||
            Ok(resp) => {
 | 
			
		||||
                let status = resp.status();
 | 
			
		||||
                let resp_text = resp.text().await
 | 
			
		||||
                    .map_err(|e| Error::Http(e.to_string()))?;
 | 
			
		||||
                    .map_err(|e| Error::new(ErrorKind::Http, e.to_string()))?;
 | 
			
		||||
                return if status.is_success() {
 | 
			
		||||
                    Ok(resp_text)
 | 
			
		||||
                } else if status.is_client_error() {
 | 
			
		||||
                    Err(Error::Auth(Self::parse_error_json(&resp_text)))
 | 
			
		||||
                    Err(Error::new(ErrorKind::Auth, Self::parse_error_json(&resp_text)))
 | 
			
		||||
                } else {
 | 
			
		||||
                    Err(Error::Http("Unknown error! Response code: ".to_owned()
 | 
			
		||||
                        + status.as_str()))
 | 
			
		||||
                    Err(Error::new(ErrorKind::Http, status.to_string()))
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            Err(err) => {
 | 
			
		||||
                Err(Error::Http(err.to_string()))
 | 
			
		||||
                Err(Error::new(ErrorKind::Http, err.to_string()))
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn post_request(
 | 
			
		||||
        &mut self, endpoint: &str, body: &str
 | 
			
		||||
    ) -> Result<String, Error> {
 | 
			
		||||
        Self::perform_request(self.client.post(self.url.to_owned() + endpoint)
 | 
			
		||||
            .header("Content-Type", "application/json")
 | 
			
		||||
            .body(body.to_owned())).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn obj_to_json<T>(
 | 
			
		||||
        obj: &T
 | 
			
		||||
    ) -> Result<String, Error> where T: serde::Serialize {
 | 
			
		||||
        serde_json::to_string(obj)
 | 
			
		||||
            .map_err(|e| Error::new(ErrorKind::Json, e.to_string()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn json_to_obj<'a, T>(
 | 
			
		||||
        json: &'a str
 | 
			
		||||
    ) -> Result<T, Error> where T: serde::Deserialize<'a> {
 | 
			
		||||
        serde_json::from_str(json)
 | 
			
		||||
            .map_err(|e| Error::new(ErrorKind::Json, e.to_string()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn login(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        email: &str,
 | 
			
		||||
@ -100,21 +179,16 @@ impl Context {
 | 
			
		||||
        device: &str
 | 
			
		||||
    ) -> Result<bool, Error> {
 | 
			
		||||
        let req_body = LoginRequest {email, password, device};
 | 
			
		||||
        let response = Self::perform_request(self.client.post(self.url.to_owned())
 | 
			
		||||
            .header("Content-Type", "application/json")
 | 
			
		||||
            .body(serde_json::to_string(&req_body).unwrap()));
 | 
			
		||||
        let body = response.await?;
 | 
			
		||||
        let resp_obj: LoginResponse = serde_json::from_str(body.as_str())
 | 
			
		||||
            .map_err(|_| Error::Json("Could not parse response json"
 | 
			
		||||
                .to_owned()))?;
 | 
			
		||||
        let body = self.post_request("api/auth/login",
 | 
			
		||||
            Self::obj_to_json(&req_body)?.as_str()).await?;
 | 
			
		||||
        let resp_obj: LoginResponse = Self::json_to_obj(body.as_str())?;
 | 
			
		||||
        if resp_obj.mfa_enabled {
 | 
			
		||||
            if resp_obj.mfa_key.is_some() {
 | 
			
		||||
                self.device = Some(device.to_owned());
 | 
			
		||||
                self.mfa_key = resp_obj.mfa_key;
 | 
			
		||||
                Ok(true)
 | 
			
		||||
            } else {
 | 
			
		||||
                Err(Error::Json("Error response did not contain mfa key"
 | 
			
		||||
                    .to_owned()))
 | 
			
		||||
                Err(Error::new(ErrorKind::Json, "Error response did not contain mfa key"))
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if resp_obj.api_key.is_some() {
 | 
			
		||||
@ -123,13 +197,26 @@ impl Context {
 | 
			
		||||
                self.device = None;
 | 
			
		||||
                Ok(true)
 | 
			
		||||
            } else {
 | 
			
		||||
                Err(Error::Json("Response did not contain api key".to_owned()))
 | 
			
		||||
                Err(Error::new(ErrorKind::Json, "Response did not contain api key"))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn mfa(&mut self, mfa_token: &str) -> Result<(), Error> {
 | 
			
		||||
        // TODO implement
 | 
			
		||||
        Ok(())
 | 
			
		||||
        if self.mfa_key.is_some() && self.device.is_some() {
 | 
			
		||||
            let req_json = Self::obj_to_json(&MfaRequest {
 | 
			
		||||
                mfa_token,
 | 
			
		||||
                mfa_key: self.mfa_key.as_ref().unwrap().as_str(),
 | 
			
		||||
                device: self.device.as_ref().unwrap().as_str(),
 | 
			
		||||
            })?;
 | 
			
		||||
            let body = self.post_request("api/auth/mfa", req_json.as_str()).await?; 
 | 
			
		||||
            let resp_obj: MfaResponse = Self::json_to_obj(body.as_str())?;
 | 
			
		||||
            self.api_key = Some(resp_obj.api_key);
 | 
			
		||||
            self.device = None;
 | 
			
		||||
            self.mfa_key = None;
 | 
			
		||||
            Ok(())
 | 
			
		||||
        } else {
 | 
			
		||||
            Err(Error::new(ErrorKind::State, "No login operation in progress"))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user