158 lines
5.2 KiB
Rust

use crate::login_window::LoginWindow;
use crate::tabbed_window::TabbedWindow;
use crate::main_panel::MainPanel;
use crate::settings_panel::SettingsPanel;
use gtk4 as gtk;
use gtk::{glib, gdk, gio, prelude::*, subclass::prelude::*};
use std::cell::RefCell;
use simplelogin as sl;
mod imp {
use super::*;
use glib::closure_local;
#[derive(Debug, glib::Properties)]
#[properties(wrapper_type = super::Application)]
pub struct Application {
#[property(name = "api-key", type = Option<String>,
get = Self::api_key, set = Self::set_api_key, nullable)]
pub settings: RefCell<gio::Settings>,
pub context: RefCell<sl::Context>,
}
impl Application {
fn api_key(&self) -> Option<String> {
self.settings.borrow().value("api-key").get::<Option<String>>()?
}
fn set_api_key(&self, value: Option<String>) {
_ = self.settings.borrow().set("api-key", value);
}
fn activate_no_api_key(&self) {
let login_window = LoginWindow::new(&self.obj());
login_window.connect_closure(
"logged-in", false,
closure_local!(@weak-allow-none self as opt_this
=> move |win: LoginWindow| {
win.close();
if let Some(this) = opt_this {
let obj = this.obj();
let ctx = obj.context().borrow();
let api_key = ctx.api_key();
this.set_api_key(api_key.clone());
this.activate_has_api_key();
}
}));
login_window.present();
}
fn close_window_for_widget<P: glib::IsA<gtk::Widget>>(widget: &P) {
if let Some(win) = get_window_ancestor(widget) {
win.close();
}
}
fn activate_has_api_key(&self) {
let obj = &self.obj();
let main_panel = MainPanel::new(obj);
let settings_panel: gtk::Widget = SettingsPanel::new(obj).upcast();
let window = TabbedWindow::new(obj,
&[("Aliases", &main_panel.upcast()),
("Settings", &settings_panel)]);
settings_panel.connect_closure(
"api-key-cleared", false,
closure_local!(@weak-allow-none self as opt_this
=> move |panel: SettingsPanel| {
Self::close_window_for_widget(&panel);
if let Some(this) = opt_this {
this.set_api_key(None);
this.activate_no_api_key();
}
}));
settings_panel.connect_closure(
"logged-out", false,
closure_local!(@weak-allow-none self as opt_this
=> move |panel: SettingsPanel| {
Self::close_window_for_widget(&panel);
if let Some(this) = opt_this {
this.set_api_key(None);
this.activate_no_api_key();
}
}));
window.present();
}
}
impl Default for Application {
fn default() -> Self {
let settings = RefCell::new(gio::Settings::new(crate::APP_ID));
let api_key: Option<String> =
settings.borrow().value("api-key").get::<Option<String>>().unwrap();
Self {
settings,
context: RefCell::new(sl::Context::new(api_key.as_deref())),
}
}
}
#[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 css = gtk::CssProvider::new();
gtk::style_context_add_provider_for_display(
&gdk::Display::default().unwrap(),
&css, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION
);
css.load_from_string(include_str!("../data/global.css"));
match self.api_key() {
Some(_) => self.activate_has_api_key(),
None => self.activate_no_api_key(),
}
}
}
#[glib::derived_properties]
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()
}
pub fn context(&self) -> &RefCell<sl::Context> {
&self.imp().context
}
}
impl Default for Application {
fn default() -> Self {
Self::new(crate::APP_ID)
}
}
pub fn get_window_ancestor<P: glib::IsA<gtk::Widget>>(
widget: &P
) -> Option<gtk::Window> {
let root_opt = widget.root()?;
match root_opt.downcast::<gtk::Window>() {
Ok(win) => Some(win),
Err(_) => None,
}
}