Work on user stats page
This commit is contained in:
parent
04fbed2c3a
commit
8754520d10
@ -205,10 +205,18 @@ template $LoginWindow : ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
label: "Forgot your password? Reset it <a href=\"https://app.simplelogin.io/auth/forgot_password\">here</a>.";
|
||||
margin-bottom: 5;
|
||||
use-markup: true;
|
||||
valign: start;
|
||||
vexpand: true;
|
||||
yalign: 0.0;
|
||||
}
|
||||
|
||||
Label {
|
||||
label: "Don\'t have an account? You can register <a href=\"https://app.simplelogin.io/auth/register\">here</a>.";
|
||||
margin-bottom: 10;
|
||||
margin-bottom: 10;
|
||||
use-markup: true;
|
||||
valign: start;
|
||||
vexpand: true;
|
||||
|
@ -5,6 +5,7 @@ template $SettingsPanel : Box {
|
||||
hexpand: true;
|
||||
|
||||
child: Box content_wrapper {
|
||||
visible: false;
|
||||
hexpand: true;
|
||||
vexpand: true;
|
||||
|
||||
@ -43,6 +44,7 @@ template $SettingsPanel : Box {
|
||||
|
||||
Entry name_label {
|
||||
editable: false;
|
||||
can-focus: false;
|
||||
has-frame: false;
|
||||
hexpand: true;
|
||||
input-hints: no_emoji | no_spellcheck;
|
||||
|
@ -88,7 +88,8 @@ mod imp {
|
||||
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();
|
||||
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())),
|
||||
|
@ -59,6 +59,28 @@ mod imp {
|
||||
|
||||
#[gtk::template_callbacks]
|
||||
impl SettingsPanel {
|
||||
fn set_is_loading(&self, loading: bool) {
|
||||
if loading {
|
||||
self.set_error(None);
|
||||
} else if !self.is_error() {
|
||||
self.content_wrapper.get().set_sensitive(true);
|
||||
}
|
||||
self.loading_overlay.get().set_visible(loading);
|
||||
}
|
||||
|
||||
fn is_error(&self) -> bool {
|
||||
self.error_overlay.get().is_visible()
|
||||
}
|
||||
|
||||
fn set_error(&self, error: Option<&str>) {
|
||||
if let Some(e) = error {
|
||||
self.set_is_loading(false);
|
||||
self.error_label.get().set_text(e);
|
||||
}
|
||||
self.content_wrapper.get().set_sensitive(error.is_none());
|
||||
self.error_overlay.get().set_visible(error.is_some());
|
||||
}
|
||||
|
||||
#[template_callback]
|
||||
fn clear_api_key_clicked(&self, _: >k::Button) {
|
||||
let main_loop = glib::MainContext::default();
|
||||
@ -79,23 +101,6 @@ mod imp {
|
||||
}));
|
||||
}
|
||||
|
||||
fn set_is_loading(&self, loading: bool) {
|
||||
if loading {
|
||||
self.set_error(None);
|
||||
}
|
||||
self.loading_overlay.get().set_visible(loading);
|
||||
self.content_wrapper.get().set_sensitive(!loading);
|
||||
}
|
||||
|
||||
fn set_error(&self, error: Option<&str>) {
|
||||
if let Some(e) = error {
|
||||
self.set_is_loading(false);
|
||||
self.error_label.get().set_text(e);
|
||||
}
|
||||
self.content_wrapper.get().set_sensitive(error.is_none());
|
||||
self.error_overlay.get().set_visible(error.is_some());
|
||||
}
|
||||
|
||||
#[template_callback]
|
||||
fn logout_clicked(&self, _: >k::Button) {
|
||||
let main_loop = glib::MainContext::default();
|
||||
@ -125,6 +130,54 @@ mod imp {
|
||||
fn close_error_clicked(&self, _: >k::Button) {
|
||||
self.set_error(None);
|
||||
}
|
||||
|
||||
async fn refresh_stats(&self) -> bool {
|
||||
let app = self.application.borrow();
|
||||
let mut ctx = app.context().borrow_mut();
|
||||
match ctx.stats().await {
|
||||
Ok(stats) => {
|
||||
self.stats_label.get().set_text(&format!(
|
||||
"Aliases: {}, Blocked: {}, Forwarded: {}, Replied: {}",
|
||||
stats.nb_alias, stats.nb_block, stats.nb_forward, stats.nb_reply
|
||||
));
|
||||
false
|
||||
},
|
||||
Err(e) => {
|
||||
self.set_error(Some(e.to_string().as_str()));
|
||||
true
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn refresh_user_info(&self) -> bool {
|
||||
let app = self.application.borrow();
|
||||
let mut ctx = app.context().borrow_mut();
|
||||
match ctx.get_user_info().await {
|
||||
Ok(user_info) => {
|
||||
self.name_label.get().set_text(
|
||||
if user_info.name.is_empty() {
|
||||
"<No name>"
|
||||
} else {
|
||||
&user_info.name
|
||||
}
|
||||
);
|
||||
self.email_label.get().set_text(&user_info.email);
|
||||
self.status_label.get().set_text(
|
||||
if user_info.is_premium {
|
||||
"Premium"
|
||||
} else if user_info.in_trial {
|
||||
"Premium (Trial)"
|
||||
} else {
|
||||
"Free"
|
||||
});
|
||||
false
|
||||
},
|
||||
Err(e) => {
|
||||
self.set_error(Some(e.to_string().as_str()));
|
||||
true
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
@ -160,7 +213,21 @@ mod imp {
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for SettingsPanel {}
|
||||
impl WidgetImpl for SettingsPanel {
|
||||
fn map(&self) {
|
||||
self.parent_map();
|
||||
let main_loop = glib::MainContext::default();
|
||||
main_loop.spawn_local(clone!(@weak self as this => async move {
|
||||
this.set_is_loading(true);
|
||||
if !this.refresh_user_info().await {
|
||||
this.refresh_stats().await;
|
||||
}
|
||||
this.set_is_loading(false);
|
||||
this.content_wrapper.get().set_visible(true);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
impl BoxImpl for SettingsPanel {}
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,30 @@ struct MfaResponse {
|
||||
email: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct UserInfoRequest<'a> {
|
||||
api_key: &'a str,
|
||||
profile_picture: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UserInfo {
|
||||
pub name: String,
|
||||
pub is_premium: bool,
|
||||
pub email: String,
|
||||
pub in_trial: bool,
|
||||
pub profile_picture_url: Option<String>,
|
||||
pub max_alias_free_plan: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Stats {
|
||||
pub nb_alias: u32,
|
||||
pub nb_block: u32,
|
||||
pub nb_forward: u32,
|
||||
pub nb_reply: u32,
|
||||
}
|
||||
|
||||
pub enum ErrorKind {
|
||||
State,
|
||||
Json,
|
||||
@ -179,6 +203,23 @@ impl Context {
|
||||
.body(body.to_owned())).await
|
||||
}
|
||||
|
||||
async fn patch_request(
|
||||
&mut self, endpoint: &str, body: Option<&str>,
|
||||
headers: Option<&[(&str, &str)]>
|
||||
) -> Result<String, Error> {
|
||||
let mut builder = self.client.patch(self.url.to_owned() + endpoint);
|
||||
if let Some(body_str) = body {
|
||||
builder = builder.header("Content-Type", "application/json")
|
||||
.body(body_str.to_owned());
|
||||
}
|
||||
if let Some(headers_arr) = headers {
|
||||
for header in headers_arr {
|
||||
builder = builder.header(header.0, header.1);
|
||||
}
|
||||
}
|
||||
Self::perform_request(builder).await
|
||||
}
|
||||
|
||||
pub fn obj_to_json<T>(
|
||||
obj: &T
|
||||
) -> Result<String, Error> where T: serde::Serialize {
|
||||
@ -250,4 +291,41 @@ impl Context {
|
||||
None => Err(Error::new(ErrorKind::State, "Not logged in")),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_user_info(&mut self) -> Result<UserInfo, Error> {
|
||||
match self.api_key.as_ref() {
|
||||
Some(api_key) => {
|
||||
let res = self.get_request("api/user_info",
|
||||
&[("Authentication", api_key.clone().as_str())]).await?;
|
||||
Ok(Self::json_to_obj(&res)?)
|
||||
},
|
||||
None => Err(Error::new(ErrorKind::State, "Not logged in")),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_user_info(
|
||||
&mut self, profile_picture: Option<&str>
|
||||
) -> Result<UserInfo, Error> {
|
||||
match self.api_key.as_ref() {
|
||||
Some(api_key) => {
|
||||
let req_json = Self::obj_to_json(
|
||||
&UserInfoRequest {api_key, profile_picture})?;
|
||||
let res = self.patch_request("api/user_info",
|
||||
Some(&req_json), None).await?;
|
||||
Ok(Self::json_to_obj(&res)?)
|
||||
},
|
||||
None => Err(Error::new(ErrorKind::State, "Not logged in")),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn stats(&mut self) -> Result<Stats, Error> {
|
||||
match self.api_key.as_ref() {
|
||||
Some(api_key) => {
|
||||
let res = self.get_request("api/stats",
|
||||
&[("Authentication", api_key.clone().as_str())]).await?;
|
||||
Ok(Self::json_to_obj(&res)?)
|
||||
},
|
||||
None => Err(Error::new(ErrorKind::State, "Not logged in")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user