parent
e4191a744d
commit
fa53f0ec76
|
@ -44,14 +44,14 @@ impl RequestContext {
|
||||||
|
|
||||||
pub fn get<S: AsRef<str>>(&self, url: S) -> reqwest::RequestBuilder {
|
pub fn get<S: AsRef<str>>(&self, url: S) -> reqwest::RequestBuilder {
|
||||||
self.client
|
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))
|
.header(reqwest::header::AUTHORIZATION, format!("JWT {}", self.token))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Warning: no authentication, since it is only used for login
|
/// Warning: no authentication, since it is only used for login
|
||||||
pub fn post<S: AsRef<str>>(&self, url: S) -> reqwest::RequestBuilder {
|
pub fn post<S: AsRef<str>>(&self, url: S) -> reqwest::RequestBuilder {
|
||||||
self.client
|
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 {
|
pub fn to_json(&self) -> serde_json::Value {
|
||||||
|
|
61
src/main.rs
61
src/main.rs
|
@ -70,6 +70,7 @@ mod ui;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
|
window: Rc<RefCell<Window>>,
|
||||||
stack: Stack,
|
stack: Stack,
|
||||||
error: InfoBar,
|
error: InfoBar,
|
||||||
header: HeaderBar,
|
header: HeaderBar,
|
||||||
|
@ -156,6 +157,24 @@ fn main() {
|
||||||
window.set_title("Mobydick");
|
window.set_title("Mobydick");
|
||||||
window.set_default_size(1080, 720);
|
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 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 json: serde_json::Value = serde_json::from_slice(&f).ok()?;
|
||||||
let mut api_ctx = crate::api::API.lock().ok()?;
|
let mut api_ctx = crate::api::API.lock().ok()?;
|
||||||
|
@ -167,6 +186,7 @@ fn main() {
|
||||||
}).is_some();
|
}).is_some();
|
||||||
|
|
||||||
let state = Rc::new(RefCell::new(AppState {
|
let state = Rc::new(RefCell::new(AppState {
|
||||||
|
window: window.clone(),
|
||||||
stack: {
|
stack: {
|
||||||
let s = Stack::new();
|
let s = Stack::new();
|
||||||
s.set_vexpand(true);
|
s.set_vexpand(true);
|
||||||
|
@ -196,16 +216,20 @@ fn main() {
|
||||||
|
|
||||||
let scrolled = ScrolledWindow::new(None, None);
|
let scrolled = ScrolledWindow::new(None, None);
|
||||||
scrolled.add(&main_box);
|
scrolled.add(&main_box);
|
||||||
window.add(&scrolled);
|
window.borrow().add(&scrolled);
|
||||||
window.set_titlebar(&state.borrow().header);
|
window.borrow().set_titlebar(&state.borrow().header);
|
||||||
window.show_all();
|
window.borrow().show_all();
|
||||||
|
|
||||||
if connected {
|
if connected {
|
||||||
let main_page = ui::main_page::render(&state.borrow().header, &{
|
let main_page = ui::main_page::render(
|
||||||
|
state.borrow().window.clone(),
|
||||||
|
&state.borrow().header,
|
||||||
|
&{
|
||||||
let s = StackSwitcher::new();
|
let s = StackSwitcher::new();
|
||||||
s.set_stack(&state.borrow().stack);
|
s.set_stack(&state.borrow().stack);
|
||||||
s
|
s
|
||||||
});
|
}
|
||||||
|
);
|
||||||
state.borrow().stack.add_titled(&main_page, "main", "Search Music");
|
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.add_titled(&*ui::dl_list::render().borrow(), "downloads", "Downloads");
|
||||||
state.borrow().stack.set_visible_child_name("main");
|
state.borrow().stack.set_visible_child_name("main");
|
||||||
|
@ -213,20 +237,6 @@ fn main() {
|
||||||
let login_page = ui::login_page::render(state.clone());
|
let login_page = ui::login_page::render(state.clone());
|
||||||
state.borrow().stack.add_named(&login_page, "login");
|
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) {
|
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.show_all();
|
||||||
state.borrow().error.set_revealed(true);
|
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)
|
||||||
|
}
|
|
@ -25,8 +25,12 @@ pub fn render(state: State) -> gtk::Box {
|
||||||
)));
|
)));
|
||||||
login_bt.connect_clicked(clone!(state, widgets => move |_| {
|
login_bt.connect_clicked(clone!(state, widgets => move |_| {
|
||||||
let mut api_ctx = crate::api::API.lock().unwrap();
|
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(
|
*api_ctx = Some(RequestContext::new(
|
||||||
widgets.borrow().0.get_text().unwrap()
|
instance_url
|
||||||
));
|
));
|
||||||
|
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
|
@ -45,11 +49,16 @@ pub fn render(state: State) -> gtk::Box {
|
||||||
|
|
||||||
let state = state.borrow();
|
let state = state.borrow();
|
||||||
state.error.set_revealed(false);
|
state.error.set_revealed(false);
|
||||||
state.stack.add_titled(&crate::ui::main_page::render(&state.header, &{
|
state.stack.add_titled(&crate::ui::main_page::render(
|
||||||
|
state.window.clone(),
|
||||||
|
&state.header,
|
||||||
|
&{
|
||||||
let s = StackSwitcher::new();
|
let s = StackSwitcher::new();
|
||||||
s.set_stack(&state.stack);
|
s.set_stack(&state.stack);
|
||||||
s
|
s
|
||||||
}), "main", "Search Music");
|
}
|
||||||
|
),
|
||||||
|
"main", "Search Music");
|
||||||
state.stack.set_visible_child_name("main");
|
state.stack.set_visible_child_name("main");
|
||||||
state.stack.add_titled(&*crate::ui::dl_list::render().borrow(), "downloads", "Downloads");
|
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
|
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 {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
let (ref instance, ref username, ref password) = *widgets.borrow();
|
||||||
cont.add(&title);
|
cont.add(&title);
|
||||||
cont.add(&widgets.borrow().0.render());
|
cont.add(&instance.render());
|
||||||
cont.add(&widgets.borrow().1.render());
|
cont.add(&username.render());
|
||||||
cont.add(&widgets.borrow().2.render());
|
cont.add(&password.render());
|
||||||
cont.add(&login_bt);
|
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.show_all();
|
||||||
cont
|
cont
|
||||||
|
|
|
@ -2,11 +2,13 @@ use gdk::ContextExt;
|
||||||
use gdk_pixbuf::PixbufExt;
|
use gdk_pixbuf::PixbufExt;
|
||||||
use gtk::*;
|
use gtk::*;
|
||||||
use std::{
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
fs,
|
fs,
|
||||||
|
rc::Rc,
|
||||||
};
|
};
|
||||||
use crate::{api::{self, execute}, ui::{title, card}};
|
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);
|
let cont = gtk::Box::new(Orientation::Vertical, 12);
|
||||||
cont.set_margin_top(48);
|
cont.set_margin_top(48);
|
||||||
cont.set_margin_bottom(48);
|
cont.set_margin_bottom(48);
|
||||||
|
@ -50,6 +52,12 @@ pub fn render(header: &HeaderBar, switcher: &StackSwitcher) -> gtk::Box {
|
||||||
}));
|
}));
|
||||||
header.pack_start(&avatar);
|
header.pack_start(&avatar);
|
||||||
header.set_custom_title(&*switcher);
|
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();
|
header.show_all();
|
||||||
|
|
||||||
let search = SearchEntry::new();
|
let search = SearchEntry::new();
|
||||||
|
@ -63,8 +71,9 @@ pub fn render(header: &HeaderBar, switcher: &StackSwitcher) -> gtk::Box {
|
||||||
rc!(avatar, results);
|
rc!(avatar, results);
|
||||||
clone!(avatar, results, avatar_path);
|
clone!(avatar, results, avatar_path);
|
||||||
wait!(execute(client!().get("/api/v1/users/users/me")) => |res| {
|
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);
|
clone!(avatar_path, avatar);
|
||||||
|
@ -74,6 +83,11 @@ pub fn render(header: &HeaderBar, switcher: &StackSwitcher) -> gtk::Box {
|
||||||
avatar_dl.copy_to(&mut avatar_file).unwrap();
|
avatar_dl.copy_to(&mut avatar_file).unwrap();
|
||||||
avatar.borrow().queue_draw();
|
avatar.borrow().queue_draw();
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
crate::logout(window.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
search.connect_activate(move |s| {
|
search.connect_activate(move |s| {
|
||||||
|
|
Loading…
Reference in New Issue