Fix #5 + fix #6 + add a logout button

This commit is contained in:
Baptiste Gelez 2019-02-27 20:06:36 +01:00
parent e4191a744d
commit fa53f0ec76
4 changed files with 106 additions and 46 deletions

View File

@ -44,14 +44,14 @@ impl RequestContext {
pub fn get<S: AsRef<str>>(&self, url: S) -> reqwest::RequestBuilder {
self.client
.get(&format!("https://{}{}", self.instance, url.as_ref()))
.get(&format!("{}{}", self.instance, url.as_ref()))
.header(reqwest::header::AUTHORIZATION, format!("JWT {}", self.token))
}
/// Warning: no authentication, since it is only used for login
pub fn post<S: AsRef<str>>(&self, url: S) -> reqwest::RequestBuilder {
self.client
.post(&format!("https://{}{}", self.instance, url.as_ref()))
.post(&format!("{}{}", self.instance, url.as_ref()))
}
pub fn to_json(&self) -> serde_json::Value {

View File

@ -70,6 +70,7 @@ mod ui;
#[derive(Debug)]
pub struct AppState {
window: Rc<RefCell<Window>>,
stack: Stack,
error: InfoBar,
header: HeaderBar,
@ -156,6 +157,24 @@ fn main() {
window.set_title("Mobydick");
window.set_default_size(1080, 720);
window.connect_delete_event(move |_, _| {
gtk::main_quit();
fs::create_dir_all(dirs::config_dir().unwrap().join("mobydick")).unwrap();
fs::write(
dirs::config_dir().unwrap().join("mobydick").join("data.json"),
serde_json::to_string(&client!().to_json()).unwrap()
).unwrap();
Inhibit(false)
});
init(Rc::new(RefCell::new(window)));
gtk::main();
}
fn init(window: Rc<RefCell<Window>>) {
let connected = fs::read(dirs::config_dir().unwrap().join("mobydick").join("data.json")).ok().and_then(|f| {
let json: serde_json::Value = serde_json::from_slice(&f).ok()?;
let mut api_ctx = crate::api::API.lock().ok()?;
@ -167,6 +186,7 @@ fn main() {
}).is_some();
let state = Rc::new(RefCell::new(AppState {
window: window.clone(),
stack: {
let s = Stack::new();
s.set_vexpand(true);
@ -196,16 +216,20 @@ fn main() {
let scrolled = ScrolledWindow::new(None, None);
scrolled.add(&main_box);
window.add(&scrolled);
window.set_titlebar(&state.borrow().header);
window.show_all();
window.borrow().add(&scrolled);
window.borrow().set_titlebar(&state.borrow().header);
window.borrow().show_all();
if connected {
let main_page = ui::main_page::render(&state.borrow().header, &{
let s = StackSwitcher::new();
s.set_stack(&state.borrow().stack);
s
});
let main_page = ui::main_page::render(
state.borrow().window.clone(),
&state.borrow().header,
&{
let s = StackSwitcher::new();
s.set_stack(&state.borrow().stack);
s
}
);
state.borrow().stack.add_titled(&main_page, "main", "Search Music");
state.borrow().stack.add_titled(&*ui::dl_list::render().borrow(), "downloads", "Downloads");
state.borrow().stack.set_visible_child_name("main");
@ -213,20 +237,6 @@ fn main() {
let login_page = ui::login_page::render(state.clone());
state.borrow().stack.add_named(&login_page, "login");
}
window.connect_delete_event(move |_, _| {
gtk::main_quit();
fs::create_dir_all(dirs::config_dir().unwrap().join("mobydick")).unwrap();
fs::write(
dirs::config_dir().unwrap().join("mobydick").join("data.json"),
serde_json::to_string(&client!().to_json()).unwrap()
).unwrap();
Inhibit(false)
});
gtk::main();
}
fn show_error(state: State, msg: &str) {
@ -238,3 +248,16 @@ fn show_error(state: State, msg: &str) {
state.borrow().error.show_all();
state.borrow().error.set_revealed(true);
}
fn logout(window: Rc<RefCell<Window>>) {
fs::remove_file(dirs::config_dir().unwrap().join("mobydick").join("data.json")).ok();
*api::API.lock().unwrap() = None;
*DOWNLOADS.lock().unwrap() = HashMap::new();
{
let window = window.borrow();
for ch in window.get_children() {
window.remove(&ch);
}
}
init(window)
}

View File

@ -25,8 +25,12 @@ pub fn render(state: State) -> gtk::Box {
)));
login_bt.connect_clicked(clone!(state, widgets => move |_| {
let mut api_ctx = crate::api::API.lock().unwrap();
let mut instance_url = widgets.borrow().0.get_text().unwrap().trim_end_matches('/').to_string();
if !(instance_url.starts_with("http://") || instance_url.starts_with("https://")) {
instance_url = format!("https://{}", instance_url)
}
*api_ctx = Some(RequestContext::new(
widgets.borrow().0.get_text().unwrap()
instance_url
));
let state = state.clone();
@ -45,11 +49,16 @@ pub fn render(state: State) -> gtk::Box {
let state = state.borrow();
state.error.set_revealed(false);
state.stack.add_titled(&crate::ui::main_page::render(&state.header, &{
let s = StackSwitcher::new();
s.set_stack(&state.stack);
s
}), "main", "Search Music");
state.stack.add_titled(&crate::ui::main_page::render(
state.window.clone(),
&state.header,
&{
let s = StackSwitcher::new();
s.set_stack(&state.stack);
s
}
),
"main", "Search Music");
state.stack.set_visible_child_name("main");
state.stack.add_titled(&*crate::ui::dl_list::render().borrow(), "downloads", "Downloads");
state.stack.remove(&state.stack.get_child_by_name("login").unwrap()); // To avoid having a "Login" tab in the header
@ -59,11 +68,25 @@ pub fn render(state: State) -> gtk::Box {
});
}));
cont.add(&title);
cont.add(&widgets.borrow().0.render());
cont.add(&widgets.borrow().1.render());
cont.add(&widgets.borrow().2.render());
cont.add(&login_bt);
{
let (ref instance, ref username, ref password) = *widgets.borrow();
cont.add(&title);
cont.add(&instance.render());
cont.add(&username.render());
cont.add(&password.render());
cont.add(&login_bt);
}
widgets.borrow().0.entry.connect_activate(clone!(widgets => move |_| {
widgets.borrow().1.entry.grab_focus();
}));
widgets.borrow().1.entry.connect_activate(clone!(widgets => move |_| {
widgets.borrow().2.entry.grab_focus();
}));
widgets.borrow().2.entry.connect_activate(move |_| {
login_bt.clicked();
});
cont.show_all();
cont

View File

@ -2,11 +2,13 @@ use gdk::ContextExt;
use gdk_pixbuf::PixbufExt;
use gtk::*;
use std::{
cell::RefCell,
fs,
rc::Rc,
};
use crate::{api::{self, execute}, ui::{title, card}};
pub fn render(header: &HeaderBar, switcher: &StackSwitcher) -> gtk::Box {
pub fn render(window: Rc<RefCell<Window>>, header: &HeaderBar, switcher: &StackSwitcher) -> gtk::Box {
let cont = gtk::Box::new(Orientation::Vertical, 12);
cont.set_margin_top(48);
cont.set_margin_bottom(48);
@ -50,6 +52,12 @@ pub fn render(header: &HeaderBar, switcher: &StackSwitcher) -> gtk::Box {
}));
header.pack_start(&avatar);
header.set_custom_title(&*switcher);
let logout_bt = Button::new_from_icon_name("system-log-out", IconSize::LargeToolbar.into());
logout_bt.connect_clicked(clone!(window => move |_| {
crate::logout(window.clone());
}));
header.pack_end(&logout_bt);
header.show_all();
let search = SearchEntry::new();
@ -63,17 +71,23 @@ pub fn render(header: &HeaderBar, switcher: &StackSwitcher) -> gtk::Box {
rc!(avatar, results);
clone!(avatar, results, avatar_path);
wait!(execute(client!().get("/api/v1/users/users/me")) => |res| {
let res: api::UserInfo = res.json().unwrap();
let res: Result<api::UserInfo, _> = res.json();
match res {
Ok(res) => {
avatar.borrow().set_tooltip_text(format!("Connected as {}.", res.username).as_ref());
avatar.borrow().set_tooltip_text(format!("Connected as {}.", res.username).as_ref());
clone!(avatar_path, avatar);
wait!(execute(client!().get(&res.avatar.medium_square_crop.unwrap_or_default())) => |avatar_dl| {
fs::create_dir_all(avatar_path.parent().unwrap()).unwrap();
let mut avatar_file = fs::File::create(avatar_path.clone()).unwrap();
avatar_dl.copy_to(&mut avatar_file).unwrap();
avatar.borrow().queue_draw();
});
clone!(avatar_path, avatar);
wait!(execute(client!().get(&res.avatar.medium_square_crop.unwrap_or_default())) => |avatar_dl| {
fs::create_dir_all(avatar_path.parent().unwrap()).unwrap();
let mut avatar_file = fs::File::create(avatar_path.clone()).unwrap();
avatar_dl.copy_to(&mut avatar_file).unwrap();
avatar.borrow().queue_draw();
});
},
Err(_) => {
crate::logout(window.clone());
}
}
});
search.connect_activate(move |s| {