use std::rc::Rc;
use async_trait::async_trait;
use gui::derive::Widget;
use gui::Cap;
use gui::Handleable;
use gui::Id;
use gui::MutCap;
use gui::Widget;
use crate::tasks::Task;
use crate::text::EditableText;
use super::event::Event;
use super::input::InputResult;
use super::input::InputText;
use super::message::Message;
use super::message::MessageExt;
use super::modal::Modal;
#[derive(Debug)]
struct Data {
prev_focused: Option<Id>,
task: Rc<Task>,
to_edit: Task,
details: InputText,
}
impl Data {
fn new(task: Rc<Task>, to_edit: Task) -> Self {
let mut text = EditableText::from_string(to_edit.details());
let () = text.move_end();
Self {
prev_focused: None,
task,
details: InputText::builder().with_multi_line(true).build(text),
to_edit,
}
}
fn into_task(self) -> (Rc<Task>, Task) {
(self.task, self.to_edit)
}
}
#[derive(Debug)]
pub struct DetailDialogData {
data: Option<Data>,
}
impl DetailDialogData {
pub fn new() -> Self {
Self { data: None }
}
pub fn details(&self) -> &EditableText {
self
.data
.as_ref()
.map(|data| &data.details)
.expect("detail dialog has no data set")
}
}
#[derive(Debug, Widget)]
#[gui(Event = Event, Message = Message)]
pub struct DetailDialog {
id: Id,
}
impl DetailDialog {
pub fn new(id: Id) -> Self {
Self { id }
}
}
impl Modal for DetailDialog {
fn prev_focused(&self, cap: &dyn Cap) -> Option<Id> {
let data = self.data::<DetailDialogData>(cap);
data
.data
.as_ref()
.map(|data| data.prev_focused)
.expect("dialog has no data set")
}
fn set_prev_focused(&self, cap: &mut dyn MutCap<Event, Message>, focused: Option<Id>) {
let data = self.data_mut::<DetailDialogData>(cap);
data
.data
.as_mut()
.map(|data| data.prev_focused = focused)
.expect("dialog has no data set")
}
}
#[async_trait(?Send)]
impl Handleable<Event, Message> for DetailDialog {
async fn handle(&self, cap: &mut dyn MutCap<Event, Message>, event: Event) -> Option<Event> {
match event {
Event::Key(key, raw) => {
let data = self.data_mut::<DetailDialogData>(cap);
let data = data.data.as_mut().unwrap();
let message = match data.details.handle_key(key, &raw) {
InputResult::Completed(text) => {
let widget = self.restore_focus(cap);
let () = cap.hide(self.id);
let data = self.data_mut::<DetailDialogData>(cap);
let data = data.data.take();
let (task, mut updated) = data.map(Data::into_task).expect("dialog has no data set");
let () = updated.set_details(text);
cap.send(widget, Message::UpdateTask(task, updated)).await
},
InputResult::Canceled => {
let _widget = self.restore_focus(cap);
let () = cap.hide(self.id);
let data = self.data_mut::<DetailDialogData>(cap);
let _data = data.data.take();
Some(Message::updated(cap.parent_id(self.id).unwrap()))
},
InputResult::Updated => Some(Message::updated(self.id)),
InputResult::Unchanged => None,
};
message.into_event()
},
_ => Some(event),
}
}
async fn react(&self, message: Message, cap: &mut dyn MutCap<Event, Message>) -> Option<Message> {
match message {
Message::EditDetails(task, edited) => {
let data = self.data_mut::<DetailDialogData>(cap);
debug_assert!(data.data.is_none());
data.data = Some(Data::new(task, edited));
let () = self.make_focused(cap);
Some(Message::updated(self.id))
},
message => panic!("Received unexpected message: {message:?}"),
}
}
}