Commit 1d31eab7 authored by Julian Sparber's avatar Julian Sparber

accountsettings: add api for changing account avatar

* add http call for changing account avatar
* update saved account avatar

https://gitlab.gnome.org/World/fractal/issues/21
parent de83098e
......@@ -159,6 +159,10 @@ impl Backend {
let r = user::get_avatar(self);
bkerror!(r, tx, BKResponse::AvatarError);
}
Ok(BKCommand::SetUserAvatar(file)) => {
let r = user::set_user_avatar(self, file);
bkerror!(r, tx, BKResponse::SetUserAvatarError);
}
Ok(BKCommand::GetAvatarAsync(member, ctx)) => {
let r = user::get_avatar_async(self, member, ctx);
bkerror!(r, tx, BKResponse::CommandError);
......
......@@ -26,6 +26,7 @@ pub enum BKCommand {
GetUsername,
SetUserName(String),
GetAvatar,
SetUserAvatar(String),
Sync,
SyncForced,
GetRoomMembers(String),
......@@ -72,6 +73,7 @@ pub enum BKResponse {
Name(String),
SetUserName(String),
Avatar(String),
SetUserAvatar(String),
Sync(String),
Rooms(Vec<Room>, Option<Room>),
NewRooms(Vec<Room>),
......@@ -107,6 +109,7 @@ pub enum BKResponse {
UserNameError(Error),
SetUserNameError(Error),
AvatarError(Error),
SetUserAvatarError(Error),
LoginError(Error),
LogoutError(Error),
GuestLoginError(Error),
......
extern crate serde_json;
use std::fs::File;
use std::io::prelude::*;
use globals;
use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::Sender;
use error::Error;
use util::json_q;
use util::build_url;
use util::put_media;
use util::get_user_avatar;
use util::get_user_avatar_img;
use backend::types::BKResponse;
......@@ -133,6 +138,43 @@ pub fn get_avatar_async(bk: &Backend, member: Option<Member>, tx: Sender<String>
Ok(())
}
pub fn set_user_avatar(bk: &Backend, avatar: String) -> Result<(), Error> {
let baseu = bk.get_base_url()?;
let id = bk.data.lock().unwrap().user_id.clone();
let tk = bk.data.lock().unwrap().access_token.clone();
let params = vec![("access_token", tk.clone())];
let mediaurl = media_url!(&baseu, "upload", params)?;
let url = bk.url(&format!("profile/{}/avatar_url", id), vec![])?;
let mut file = File::open(&avatar)?;
let mut contents: Vec<u8> = vec![];
file.read_to_end(&mut contents)?;
let tx = bk.tx.clone();
thread::spawn(
move || {
match put_media(mediaurl.as_str(), contents) {
Err(err) => {
tx.send(BKResponse::SetUserAvatarError(err)).unwrap();
}
Ok(js) => {
let uri = js["content_uri"].as_str().unwrap_or("");
let attrs = json!({ "avatar_url": uri });
match json_q("put", &url, &attrs, 0) {
Ok(_) => {
tx.send(BKResponse::SetUserAvatar(avatar)).unwrap();
},
Err(err) => {
tx.send(BKResponse::SetUserAvatarError(err)).unwrap();
}
};
}
};
});
Ok(())
}
pub fn search(bk: &Backend, term: String) -> Result<(), Error> {
let url = bk.url(&format!("user_directory/search"), vec![])?;
......
......@@ -57,6 +57,10 @@ pub fn backend_loop(rx: Receiver<BKResponse>) {
let av = Some(path);
APPOP!(set_avatar, (av));
}
Ok(BKResponse::SetUserAvatar(path)) => {
let av = Some(path);
APPOP!(set_avatar, (av));
}
Ok(BKResponse::Sync(since)) => {
println!("SYNC");
let s = Some(since);
......
......@@ -25,12 +25,16 @@ impl App {
let delete_toggle = self.ui.builder
.get_object::<gtk::EventBox>("account_settings_delete_toggle")
.expect("Can't find account_settings_delete_toggle in ui file.");
let avatar_btn = self.ui.builder
.get_object::<gtk::Button>("account_settings_avatar_button")
.expect("Can't find account_settings_avatar_button in ui file.");
dialog.connect_delete_event(clone!(op => move |_, _| {
op.lock().unwrap().close_account_settings_dialog();
glib::signal::Inhibit(true)
}));
/* Headerbar */
cancel.connect_clicked(clone!(op => move |_| {
op.lock().unwrap().close_account_settings_dialog();
}));
......@@ -40,6 +44,24 @@ impl App {
op.lock().unwrap().close_account_settings_dialog();
}));
/* Body */
avatar_btn.connect_clicked(clone!(op, builder => move |_| {
let window = builder
.get_object::<gtk::Window>("main_window")
.expect("Can't find main_window in ui file.");
let file_chooser = gtk::FileChooserNative::new("Pick a new avatar", Some(&window), gtk::FileChooserAction::Open, Some("Select"), None);
/* http://gtk-rs.org/docs/gtk/struct.FileChooser.html */
let result = gtk::NativeDialog::run(&file_chooser.clone().upcast::<gtk::NativeDialog>());
if gtk::ResponseType::from(result) == gtk::ResponseType::Accept {
if let Some(file) = file_chooser.get_filename() {
if let Some(path) = file.to_str() {
op.lock().unwrap().save_tmp_avatar_account_settings(String::from(path));
}
}
}
}));
advanced_toggle.connect_button_press_event(clone!(builder => move |this, _| {
let widget = builder
.get_object::<gtk::Revealer>("account_settings_advanced")
......
......@@ -44,6 +44,10 @@ impl AppOp {
dialog.present();
}
pub fn save_tmp_avatar_account_settings(&mut self, file: String) {
self.tmp_avatar = Some(file);
}
pub fn apply_account_settings(&self) {
let name = self.ui.builder
.get_object::<gtk::Entry>("account_settings_name")
......@@ -55,6 +59,12 @@ impl AppOp {
if old_username != username {
self.backend.send(BKCommand::SetUserName(username)).unwrap();
}
if let Some(ref user) = self.tmp_avatar {
let command = BKCommand::SetUserAvatar(user.to_string());
self.backend.send(command).unwrap();
}
}
pub fn close_account_settings_dialog(&mut self) {
......@@ -62,13 +72,13 @@ impl AppOp {
.get_object::<gtk::Dialog>("account_settings_dialog")
.expect("Can't find account_settings_dialog in ui file.");
/*
let avatar = self.ui.builder
.get_object::<gtk::Container>("account_settings_avatar")
.expect("Can't find account_settings_avatar in ui file.");
let name = self.ui.builder
.get_object::<gtk::Entry>("account_settings_name")
.expect("Can't find account_settings_name in ui file.");
*/
let avatar = self.ui.builder
.get_object::<gtk::Container>("account_settings_avatar")
.expect("Can't find account_settings_avatar in ui file.");
let name = self.ui.builder
.get_object::<gtk::Entry>("account_settings_name")
.expect("Can't find account_settings_name in ui file.");
*/
let advanced = self.ui.builder
.get_object::<gtk::Revealer>("account_settings_advanced")
.expect("Can't find account_settings_advanced in ui file.");
......@@ -83,6 +93,7 @@ impl AppOp {
.get_object::<gtk::EventBox>("account_settings_delete_toggle")
.expect("Can't find account_settings_delete_toggle in ui file.");
self.tmp_avatar = None;
advanced_toggle.get_style_context().unwrap().remove_class("advanced_revealer_divider");
delete_toggle.get_style_context().unwrap().remove_class("advanced_revealer_divider");
advanced.set_reveal_child(false);
......
......@@ -81,6 +81,8 @@ pub struct AppOp {
pub popover_search: Option<String>,
pub popover_closing: bool,
pub tmp_avatar: Option<String>,
pub state: AppState,
pub since: Option<String>,
pub member_limit: usize,
......@@ -131,6 +133,8 @@ impl AppOp {
member_limit: 50,
unsent_messages: HashMap::new(),
tmp_avatar: None,
highlighted_entry: vec![],
popover_position: None,
popover_search: None,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment