A bunch of changes
This commit is contained in:
parent
8754520d10
commit
dbdf66012d
@ -6,6 +6,16 @@
|
|||||||
<summary>Api key</summary>
|
<summary>Api key</summary>
|
||||||
<description>The api key for the current user</description>
|
<description>The api key for the current user</description>
|
||||||
</key>
|
</key>
|
||||||
|
<key name="profile-url" type="ms">
|
||||||
|
<default>nothing</default>
|
||||||
|
<summary>Profile picture url</summary>
|
||||||
|
<description>The url for the users profile picture</description>
|
||||||
|
</key>
|
||||||
|
<key name="profile-data" type="may">
|
||||||
|
<default>nothing</default>
|
||||||
|
<summary>Profile picture data</summary>
|
||||||
|
<description>The data for the users profile picture</description>
|
||||||
|
</key>
|
||||||
<key name="window-size" type="(ii)">
|
<key name="window-size" type="(ii)">
|
||||||
<default>(-1,-1)</default>
|
<default>(-1,-1)</default>
|
||||||
</key>
|
</key>
|
||||||
|
@ -14,17 +14,13 @@ template $SettingsPanel : Box {
|
|||||||
row-homogeneous: true;
|
row-homogeneous: true;
|
||||||
valign: start;
|
valign: start;
|
||||||
|
|
||||||
Button profile_image_button {
|
Image profile_image {
|
||||||
has-frame: false;
|
halign: center;
|
||||||
|
icon-name: "user-info-symbolic";
|
||||||
Image profile_image {
|
icon-size: large;
|
||||||
halign: center;
|
margin-end: 5;
|
||||||
icon-name: "user-info-symbolic";
|
valign: center;
|
||||||
icon-size: large;
|
vexpand: true;
|
||||||
margin-end: 5;
|
|
||||||
valign: center;
|
|
||||||
vexpand: true;
|
|
||||||
}
|
|
||||||
|
|
||||||
layout {
|
layout {
|
||||||
column: "0";
|
column: "0";
|
||||||
@ -34,27 +30,17 @@ template $SettingsPanel : Box {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Box {
|
Entry name_label {
|
||||||
Button remove_picture_button {
|
editable: false;
|
||||||
halign: start;
|
can-focus: false;
|
||||||
valign: center;
|
has-frame: false;
|
||||||
icon-name: "window-close-symbolic";
|
hexpand: true;
|
||||||
visible: false;
|
input-hints: no_emoji | no_spellcheck;
|
||||||
}
|
text: "Testy McTesterface";
|
||||||
|
|
||||||
Entry name_label {
|
|
||||||
editable: false;
|
|
||||||
can-focus: false;
|
|
||||||
has-frame: false;
|
|
||||||
hexpand: true;
|
|
||||||
input-hints: no_emoji | no_spellcheck;
|
|
||||||
text: "Testy McTesterface";
|
|
||||||
|
|
||||||
styles [
|
|
||||||
"login-title-label",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"login-title-label",
|
||||||
|
]
|
||||||
layout {
|
layout {
|
||||||
column: "1";
|
column: "1";
|
||||||
column-span: "1";
|
column-span: "1";
|
||||||
|
@ -17,6 +17,7 @@ mod imp {
|
|||||||
pub struct Application {
|
pub struct Application {
|
||||||
#[property(name = "api-key", type = Option<String>,
|
#[property(name = "api-key", type = Option<String>,
|
||||||
get = Self::api_key, set = Self::set_api_key, nullable)]
|
get = Self::api_key, set = Self::set_api_key, nullable)]
|
||||||
|
#[property(get)]
|
||||||
pub settings: RefCell<gio::Settings>,
|
pub settings: RefCell<gio::Settings>,
|
||||||
pub context: RefCell<sl::Context>,
|
pub context: RefCell<sl::Context>,
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::application;
|
use crate::application;
|
||||||
use gtk4 as gtk;
|
use gtk4 as gtk;
|
||||||
use gtk::{glib, prelude::*, subclass::prelude::*};
|
use gtk::{glib, gio, gdk, prelude::*, subclass::prelude::*};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -8,6 +8,7 @@ mod imp {
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use glib::subclass::Signal;
|
use glib::subclass::Signal;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
use simplelogin::reqwest;
|
||||||
|
|
||||||
#[derive(Debug, Default, glib::Properties, gtk::CompositeTemplate)]
|
#[derive(Debug, Default, glib::Properties, gtk::CompositeTemplate)]
|
||||||
#[template(file = "data/settings_panel.blp")]
|
#[template(file = "data/settings_panel.blp")]
|
||||||
@ -20,12 +21,8 @@ mod imp {
|
|||||||
#[template_child]
|
#[template_child]
|
||||||
pub content: TemplateChild<gtk::Grid>,
|
pub content: TemplateChild<gtk::Grid>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub profile_image_button: TemplateChild<gtk::Button>,
|
|
||||||
#[template_child]
|
|
||||||
pub profile_image: TemplateChild<gtk::Image>,
|
pub profile_image: TemplateChild<gtk::Image>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub remove_picture_button: TemplateChild<gtk::Button>,
|
|
||||||
#[template_child]
|
|
||||||
pub name_label: TemplateChild<gtk::Entry>,
|
pub name_label: TemplateChild<gtk::Entry>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub edit_button: TemplateChild<gtk::Button>,
|
pub edit_button: TemplateChild<gtk::Button>,
|
||||||
@ -149,6 +146,79 @@ mod imp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn did_profile_picture_change(
|
||||||
|
new_url: &Option<String>, settings: &gio::Settings
|
||||||
|
) -> bool {
|
||||||
|
let old_url: Option<String> = settings.value("profile-url")
|
||||||
|
.get::<Option<String>>().unwrap();
|
||||||
|
*new_url != old_url
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_valid_content_type(resp: &reqwest::Response) -> bool {
|
||||||
|
match resp.headers().get("Content-Type") {
|
||||||
|
Some(ct) => match ct.to_str() {
|
||||||
|
Ok("image/png") => true,
|
||||||
|
Ok("image/jpeg") => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn process_profile_picture_response_body(
|
||||||
|
&self, url: &str, resp: reqwest::Response,
|
||||||
|
settings: &gio::Settings
|
||||||
|
) {
|
||||||
|
if let Ok(body) = resp.bytes().await {
|
||||||
|
let tex_res = gdk::Texture::from_bytes(&glib::Bytes::from(body.as_ref()));
|
||||||
|
if let Ok(tex) = tex_res {
|
||||||
|
self.profile_image.get().set_from_paintable(Some(&tex));
|
||||||
|
_ = settings.set("profile-url", Some(url));
|
||||||
|
_ = settings.set("profile-data", Some(body.as_ref()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn download_and_set_profile_picture(
|
||||||
|
&self, url: &str, app: &application::Application
|
||||||
|
) -> bool {
|
||||||
|
let ctx = app.context().borrow();
|
||||||
|
let client = ctx.client();
|
||||||
|
match client.get(url).send().await {
|
||||||
|
Ok(resp) if Self::has_valid_content_type(&resp) => {
|
||||||
|
self.process_profile_picture_response_body(
|
||||||
|
url, resp, &app.settings()).await;
|
||||||
|
false
|
||||||
|
},
|
||||||
|
Ok(_) => false,
|
||||||
|
Err(e) => {
|
||||||
|
self.set_error(Some(&e.to_string()));
|
||||||
|
true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refresh_user_profile_picture(
|
||||||
|
&self, user_info: &simplelogin::UserInfo,
|
||||||
|
) -> bool {
|
||||||
|
let app = self.application.borrow();
|
||||||
|
let settings = &app.settings();
|
||||||
|
if Self::did_profile_picture_change(&user_info.profile_picture_url,
|
||||||
|
&settings) {
|
||||||
|
self.profile_image.get()
|
||||||
|
.set_from_icon_name(Some("user-info-symbolic"));
|
||||||
|
_ = settings.set("profile-url", Option::<&str>::None);
|
||||||
|
_ = settings.set("profile-data", Option::<&[u8]>::None);
|
||||||
|
match &user_info.profile_picture_url {
|
||||||
|
Some(new_url) => self.download_and_set_profile_picture(
|
||||||
|
&new_url, &app).await,
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn refresh_user_info(&self) -> bool {
|
async fn refresh_user_info(&self) -> bool {
|
||||||
let app = self.application.borrow();
|
let app = self.application.borrow();
|
||||||
let mut ctx = app.context().borrow_mut();
|
let mut ctx = app.context().borrow_mut();
|
||||||
@ -170,6 +240,8 @@ mod imp {
|
|||||||
} else {
|
} else {
|
||||||
"Free"
|
"Free"
|
||||||
});
|
});
|
||||||
|
drop(ctx);
|
||||||
|
self.refresh_user_profile_picture(&user_info).await;
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
pub use reqwest;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
@ -63,6 +64,7 @@ struct MfaResponse {
|
|||||||
struct UserInfoRequest<'a> {
|
struct UserInfoRequest<'a> {
|
||||||
api_key: &'a str,
|
api_key: &'a str,
|
||||||
profile_picture: Option<&'a str>,
|
profile_picture: Option<&'a str>,
|
||||||
|
name: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -148,6 +150,10 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn client(&self) -> &reqwest::Client {
|
||||||
|
&self.client
|
||||||
|
}
|
||||||
|
|
||||||
pub fn api_key(&self) -> &Option<String> {
|
pub fn api_key(&self) -> &Option<String> {
|
||||||
&self.api_key
|
&self.api_key
|
||||||
}
|
}
|
||||||
@ -304,12 +310,12 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_user_info(
|
pub async fn update_user_info(
|
||||||
&mut self, profile_picture: Option<&str>
|
&mut self, profile_picture: Option<&str>, name: Option<&str>
|
||||||
) -> Result<UserInfo, Error> {
|
) -> Result<UserInfo, Error> {
|
||||||
match self.api_key.as_ref() {
|
match self.api_key.as_ref() {
|
||||||
Some(api_key) => {
|
Some(api_key) => {
|
||||||
let req_json = Self::obj_to_json(
|
let req_json = Self::obj_to_json(
|
||||||
&UserInfoRequest {api_key, profile_picture})?;
|
&UserInfoRequest {api_key, profile_picture, name})?;
|
||||||
let res = self.patch_request("api/user_info",
|
let res = self.patch_request("api/user_info",
|
||||||
Some(&req_json), None).await?;
|
Some(&req_json), None).await?;
|
||||||
Ok(Self::json_to_obj(&res)?)
|
Ok(Self::json_to_obj(&res)?)
|
||||||
|
Loading…
Reference in New Issue
Block a user