From 6d41de860cf7f21aa874b604845f740f0b233943 Mon Sep 17 00:00:00 2001 From: Andrei Zisu Date: Sun, 24 Sep 2023 21:44:48 +0200 Subject: [PATCH] Fix adwaita UI --- data/resources/window.blp | 63 +--- src/ui/window.rs | 481 +++++++++++++++-------------- src/ui/window/dynamic_list_view.rs | 131 ++++---- 3 files changed, 330 insertions(+), 345 deletions(-) diff --git a/data/resources/window.blp b/data/resources/window.blp index 700ddcd..c68049e 100644 --- a/data/resources/window.blp +++ b/data/resources/window.blp @@ -17,7 +17,7 @@ template $Window : Adw.ApplicationWindow { max-sidebar-width: 260; sidebar-width-fraction: 0.38; sidebar: Adw.NavigationPage { - title: _("Mail"); + title: _("Envoyer"); child: Adw.ToolbarView { [top] Adw.HeaderBar { @@ -38,15 +38,14 @@ template $Window : Adw.ApplicationWindow { } content: Gtk.ScrolledWindow { hscrollbar-policy: never; - child: Gtk.ListBox folders_list { - selection-mode: browse; - row-activated => $folders_row_activated_cb(); + child: Gtk.ListView folders_list { + single-click-activate: true; styles ["navigation-sidebar"] }; }; }; }; - content: Adw.NavigationPage inbox_page { + content: Adw.NavigationPage threads_page { title: _("Inbox"); tag: "inbox"; child: Adw.ToolbarView { @@ -54,12 +53,12 @@ template $Window : Adw.ApplicationWindow { Adw.HeaderBar { [start] Gtk.ToggleButton start_inbox_search_btn { - active: bind inbox_search_bar.search-mode-enabled bidirectional; + active: bind threads_list_search_bar.search-mode-enabled bidirectional; icon-name: "edit-find-symbolic"; } [end] Gtk.ToggleButton end_inbox_search_btn { - active: bind inbox_search_bar.search-mode-enabled bidirectional; + active: bind threads_list_search_bar.search-mode-enabled bidirectional; icon-name: "edit-find-symbolic"; visible: false; } @@ -69,8 +68,8 @@ template $Window : Adw.ApplicationWindow { } } [top] - Gtk.SearchBar inbox_search_bar { - key-capture-widget: inbox_page; + Gtk.SearchBar threads_list_search_bar { + key-capture-widget: threads_page; child: Adw.Clamp { maximum-size: 400; child: Gtk.SearchEntry inbox_search_entry { @@ -78,21 +77,13 @@ template $Window : Adw.ApplicationWindow { }; }; } - content: Gtk.Overlay { - [overlay] - Gtk.Button { - halign: end; - valign: end; - icon-name: "document-edit-symbolic"; - styles ["suggested-action", "circular", "fab"] - } - child: Gtk.ScrolledWindow { - hscrollbar-policy: never; - child: Gtk.ListBox inbox_list { - selection-mode: browse; - row-activated => $inbox_row_activated_cb(); - styles ["navigation-sidebar"] - }; + content: Gtk.ScrolledWindow { + hscrollbar-policy: never; + vexpand: true; + width-request: 200; + child: $DynamicListView threads_list_view { + height_per_row: 50; + styles ["navigation-sidebar"] }; }; }; @@ -151,27 +142,6 @@ template $Window : Adw.ApplicationWindow { child: Gtk.Box { orientation: vertical; styles ["conversation"] - Gtk.Label { - label: "Weekend Hike"; - xalign: 0; - styles ["title-2"] - } - Adw.Bin { - height-request: 240; - styles ["card"] - } - Adw.Bin { - height-request: 240; - styles ["card"] - } - Adw.Bin { - height-request: 240; - styles ["card"] - } - Adw.Bin { - height-request: 240; - styles ["card"] - } }; }; }; @@ -205,7 +175,6 @@ template $Window : Adw.ApplicationWindow { unapply => $two_pane_unapply_cb(); setters { outer_view.collapsed: true; - inbox_list.selection-mode: none; inner_view.sidebar-width-fraction: 0.33; } } @@ -214,11 +183,9 @@ template $Window : Adw.ApplicationWindow { unapply => $one_pane_unapply_cb(); setters { outer_view.collapsed: true; - inbox_list.selection-mode: none; inner_view.sidebar-width-fraction: 0.33; inner_view.collapsed: true; - folders_list.selection-mode: none; start_inbox_search_btn.visible: false; end_inbox_search_btn.visible: true; diff --git a/src/ui/window.rs b/src/ui/window.rs index 14cf752..b2e5d53 100644 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -309,6 +309,10 @@ mod imp { pub conversation_model: RefCell>, pub settings: gio::Settings, pub sender: Rc>>>, + #[template_child] + pub threads_list_view: TemplateChild, + #[template_child] + pub folders_list: TemplateChild, } impl Default for Window { @@ -319,6 +323,8 @@ mod imp { conversation_model: Default::default(), settings: gio::Settings::new(APP_ID), sender: Default::default(), + threads_list_view: Default::default(), + folders_list: Default::default(), } } } @@ -331,6 +337,8 @@ mod imp { fn class_init(klass: &mut Self::Class) { + DynamicListView::ensure_type(); + klass.bind_template(); klass.bind_template_callbacks(); } @@ -371,8 +379,8 @@ mod imp { // obj.set_titlebar(Some(&header)); // obj.set_default_size(1600, 900); - let conversation_model_borrow = self.conversation_model.borrow(); - let conversation_model = conversation_model_borrow.as_ref().expect("Conversation model not available"); + // let conversation_model_borrow = self.conversation_model.borrow(); + // let conversation_model = conversation_model_borrow.as_ref().expect("Conversation model not available"); let folders_list_model_borrow = self.folders_list_model.borrow(); let folders_list_model = folders_list_model_borrow.as_ref().expect("Folder list model not available"); @@ -409,16 +417,14 @@ mod imp { }); let folders_list_selection_model = gtk::NoSelection::new(Some(folders_list_model.clone())); - let folders_list_view = gtk::ListView::new(Some(folders_list_selection_model), Some(folders_list_factory)); - folders_list_view.style_context().add_class("folders_sidebar"); - folders_list_view.set_single_click_activate(true); - let folders_scroll_box = gtk::ScrolledWindow::new(); - folders_scroll_box.set_vexpand(true); - folders_scroll_box.set_size_request(200, -1); - folders_scroll_box.set_child(Some(&folders_list_view)); + self.folders_list.get().set_model(Some(&folders_list_selection_model)); + self.folders_list.get().set_factory(Some(&folders_list_factory)); - let threads_list_view = DynamicListView::new(50, conversations_list_model.clone(), move |item_index, item| { + self.threads_list_view.get().set_conversations_list_model(conversations_list_model.clone()); + self.threads_list_view.get().set_factory(move |item_index, item| { + + info!("Factory called"); let item_data = item .downcast_ref::() .expect("Row data is of wrong type"); @@ -431,60 +437,55 @@ mod imp { box_row.upcast::() }); - let dynamic_list_scroll_box = gtk::ScrolledWindow::new(); - dynamic_list_scroll_box.set_vexpand(true); - dynamic_list_scroll_box.set_size_request(200, -1); - dynamic_list_scroll_box.set_child(Some(&threads_list_view)); - - let conversation_viewer_list_box = gtk::ListBox::new(); - conversation_viewer_list_box.style_context().add_class("conversation_viewer"); + // let conversation_viewer_list_box = gtk::ListBox::new(); + // conversation_viewer_list_box.style_context().add_class("conversation_viewer"); - let conversation_viewer_scroll_box = gtk::ScrolledWindow::new(); - conversation_viewer_scroll_box.set_hexpand(true); - conversation_viewer_scroll_box.set_hscrollbar_policy(gtk::PolicyType::Never); - conversation_viewer_scroll_box.set_child(Some(&conversation_viewer_list_box)); + // let conversation_viewer_scroll_box = gtk::ScrolledWindow::new(); + // conversation_viewer_scroll_box.set_hexpand(true); + // conversation_viewer_scroll_box.set_hscrollbar_policy(gtk::PolicyType::Never); + // conversation_viewer_scroll_box.set_child(Some(&conversation_viewer_list_box)); - let spinner = gtk::Spinner::new(); + // let spinner = gtk::Spinner::new(); - spinner.set_size_request(40, 40); - spinner.set_halign(gtk::Align::Center); - spinner.set_valign(gtk::Align::Center); + // spinner.set_size_request(40, 40); + // spinner.set_halign(gtk::Align::Center); + // spinner.set_valign(gtk::Align::Center); - let please_wait_label = gtk::Label::new(Some("Please wait")); - please_wait_label.style_context().add_class("h1"); - please_wait_label.set_halign(gtk::Align::Start); + // let please_wait_label = gtk::Label::new(Some("Please wait")); + // please_wait_label.style_context().add_class("h1"); + // please_wait_label.set_halign(gtk::Align::Start); - let loading_label = gtk::Label::new(Some("Loading message contents.")); - loading_label.set_margin_bottom(40); + // let loading_label = gtk::Label::new(Some("Loading message contents.")); + // loading_label.set_margin_bottom(40); - let please_wait_loading_contents_grid = gtk::Grid::new(); - please_wait_loading_contents_grid.set_orientation(gtk::Orientation::Vertical); - please_wait_loading_contents_grid.set_halign(gtk::Align::Center); - please_wait_loading_contents_grid.set_valign(gtk::Align::Center); - please_wait_loading_contents_grid - .style_context() - .add_class("please_wait_loading_contents_grid"); - please_wait_loading_contents_grid.attach(&please_wait_label, 0, 0, 1, 1); - please_wait_loading_contents_grid.attach(&loading_label, 0, 1, 1, 1); - please_wait_loading_contents_grid.attach(&spinner, 0, 2, 1, 1); + // let please_wait_loading_contents_grid = gtk::Grid::new(); + // please_wait_loading_contents_grid.set_orientation(gtk::Orientation::Vertical); + // please_wait_loading_contents_grid.set_halign(gtk::Align::Center); + // please_wait_loading_contents_grid.set_valign(gtk::Align::Center); + // please_wait_loading_contents_grid + // .style_context() + // .add_class("please_wait_loading_contents_grid"); + // please_wait_loading_contents_grid.attach(&please_wait_label, 0, 0, 1, 1); + // please_wait_loading_contents_grid.attach(&loading_label, 0, 1, 1, 1); + // please_wait_loading_contents_grid.attach(&spinner, 0, 2, 1, 1); - let conversation_viewer_stack = gtk::Stack::new(); - conversation_viewer_stack.add_named(&conversation_viewer_scroll_box, Some("conversation-viewer")); - conversation_viewer_stack.add_named(&please_wait_loading_contents_grid, Some("loading")); + // let conversation_viewer_stack = gtk::Stack::new(); + // conversation_viewer_stack.add_named(&conversation_viewer_scroll_box, Some("conversation-viewer")); + // conversation_viewer_stack.add_named(&please_wait_loading_contents_grid, Some("loading")); - let main_grid = gtk::Grid::new(); + // let main_grid = gtk::Grid::new(); - main_grid.set_orientation(gtk::Orientation::Horizontal); + // main_grid.set_orientation(gtk::Orientation::Horizontal); - main_grid.attach(&folders_scroll_box, 0, 0, 1, 1); - main_grid.attach(&dynamic_list_scroll_box, 1, 0, 1, 1); - main_grid.attach(&conversation_viewer_stack, 2, 0, 1, 1); + // main_grid.attach(&folders_scroll_box, 0, 0, 1, 1); + // main_grid.attach(&dynamic_list_scroll_box, 1, 0, 1, 1); + // main_grid.attach(&conversation_viewer_stack, 2, 0, 1, 1); - // obj.set_child(Some(&main_grid)); + // // obj.set_child(Some(&main_grid)); let sender_clone = self.sender.clone(); - folders_list_view.connect_activate(move |list_view, position| { + self.folders_list.get().connect_activate(move |list_view, position| { let model = list_view.model().unwrap(); let item = model.item(position); @@ -510,196 +511,196 @@ mod imp { } }); - let sender_clone = self.sender.clone(); - - threads_list_view.connect_activate(move |list_view, position| { - let model = list_view.model().unwrap(); - let item = model.item(position); - - if let Some(item) = item { - let item = item.downcast_ref::().expect("Row data is of the wrong type"); - let conversation_rc = item.get_conversation(); - let conversation_borrow = conversation_rc.borrow(); - let conversation = conversation_borrow.as_ref().expect("Model contents invalid"); - - let message = conversation; - - info!("Selected conversation with subject \"{}\"", message.subject); - - sender_clone - .borrow() - .as_ref() - .expect("Message sender not available") - .send(ApplicationMessage::ShowConversation { - conversation: message.clone(), - }) - .expect("Unable to send application message"); - } else { - // application.unload_current_conversation_thread (); - } - }); - - conversation_model.connect_is_loading(move |args| { - let is_loading = args[1].get::().expect("The is_loading value needs to be of type `bool`."); - - if is_loading { - conversation_viewer_stack.set_visible_child_name("loading"); - spinner.start(); - } else { - conversation_viewer_stack.set_visible_child_name("conversation-viewer"); - spinner.stop(); - } - - None - }); - - conversation_viewer_list_box.bind_model(Some(conversation_model), |item| { - let item = item - .downcast_ref::() - .expect("Row data is of wrong type"); - let message_rc = item.get_message(); - let message_borrow = message_rc.borrow(); - let message = message_borrow.as_ref().expect("Model contents invalid"); - - let box_row = conversation_message_item::ConversationMessageItem::new_with_message(&message); - box_row.style_context().add_class("conversation_message_item"); - box_row.set_selectable(false); - - let subject_label = gtk::Label::new(None); - subject_label.set_ellipsize(gtk::pango::EllipsizeMode::End); - subject_label.set_halign(gtk::Align::Start); - subject_label.style_context().add_class("subject"); - subject_label.set_xalign(0.0); - - let from_addresses_list = gtk::Label::new(None); - from_addresses_list.set_ellipsize(gtk::pango::EllipsizeMode::End); - from_addresses_list.set_halign(gtk::Align::Start); - from_addresses_list.style_context().add_class("from"); - from_addresses_list.style_context().add_class("addresses"); - - let to_addresses_label = gtk::Label::new(Some(&"to")); - to_addresses_label.style_context().add_class("addresses_label"); - let to_addresses_list = gtk::Label::new(None); - to_addresses_list.set_ellipsize(gtk::pango::EllipsizeMode::End); - to_addresses_list.set_hexpand(true); - to_addresses_list.set_halign(gtk::Align::Start); - let to_addresses_grid = gtk::Grid::new(); - to_addresses_grid.style_context().add_class("to"); - to_addresses_grid.style_context().add_class("addresses"); - to_addresses_grid.attach(&to_addresses_label, 0, 0, 1, 1); - to_addresses_grid.attach(&to_addresses_list, 1, 0, 1, 1); - - let cc_addresses_label = gtk::Label::new(Some(&"cc")); - cc_addresses_label.style_context().add_class("addresses_label"); - let cc_addresses_list = gtk::Label::new(None); - cc_addresses_list.set_ellipsize(gtk::pango::EllipsizeMode::End); - cc_addresses_list.set_hexpand(true); - cc_addresses_list.set_halign(gtk::Align::Start); - let cc_addresses_grid = gtk::Grid::new(); - cc_addresses_grid.style_context().add_class("cc"); - cc_addresses_grid.style_context().add_class("addresses"); - cc_addresses_grid.attach(&cc_addresses_label, 0, 0, 1, 1); - cc_addresses_grid.attach(&cc_addresses_list, 1, 0, 1, 1); - - let bcc_addresses_label = gtk::Label::new(Some(&"bcc")); - bcc_addresses_label.style_context().add_class("addresses_label"); - let bcc_addresses_list = gtk::Label::new(None); - bcc_addresses_list.set_ellipsize(gtk::pango::EllipsizeMode::End); - bcc_addresses_list.set_hexpand(true); - bcc_addresses_list.set_halign(gtk::Align::Start); - let bcc_addresses_grid = gtk::Grid::new(); - bcc_addresses_grid.style_context().add_class("bcc"); - bcc_addresses_grid.style_context().add_class("addresses"); - bcc_addresses_grid.attach(&bcc_addresses_label, 0, 0, 1, 1); - bcc_addresses_grid.attach(&bcc_addresses_list, 1, 0, 1, 1); - - let header_summary_fields = gtk::Grid::new(); - header_summary_fields.set_row_spacing(1); - header_summary_fields.set_hexpand(true); - header_summary_fields.set_valign(gtk::Align::Start); - header_summary_fields.set_orientation(gtk::Orientation::Vertical); - header_summary_fields.style_context().add_class("header_summary_fields"); - header_summary_fields.attach(&subject_label, 0, 0, 1, 1); - header_summary_fields.attach(&from_addresses_list, 0, 1, 1, 1); - header_summary_fields.attach(&to_addresses_grid, 0, 2, 1, 1); - header_summary_fields.attach(&cc_addresses_grid, 0, 3, 1, 1); - header_summary_fields.attach(&bcc_addresses_grid, 0, 4, 1, 1); - - let datetime_received_label = gtk::Label::new(None); - datetime_received_label.style_context().add_class("received"); - datetime_received_label.set_valign(gtk::Align::Start); - - let attachment_indicator = gtk::Image::from_icon_name(&"mail-attachment-symbolic"); - attachment_indicator.style_context().add_class("attachment_indicator"); - attachment_indicator.set_valign(gtk::Align::Start); - attachment_indicator.set_sensitive(false); - attachment_indicator.set_tooltip_text(Some(&"This message contains one or more attachments")); - - let message_header = gtk::Grid::new(); - message_header.set_can_focus(false); - message_header.set_orientation(gtk::Orientation::Horizontal); - message_header.attach(&header_summary_fields, 0, 0, 1, 1); - message_header.attach(&attachment_indicator, 1, 0, 1, 1); - message_header.attach(&datetime_received_label, 2, 0, 1, 1); - - let message_view = gtk::TextView::new(); - - let buffer = message_view.buffer(); - - let attachments_list = gtk::Grid::new(); - attachments_list.set_orientation(gtk::Orientation::Vertical); - - let view = message_view::MessageView::new(); - - let grid = gtk::Grid::new(); - grid.set_orientation(gtk::Orientation::Vertical); - grid.attach(&message_header, 0, 0, 1, 1); - grid.attach(&attachments_list, 0, 1, 1, 1); - grid.attach(&view, 0, 2, 1, 1); - - box_row.set_child(Some(&grid)); - - if message.subject.trim().is_empty() { - subject_label.hide(); - } else { - subject_label.set_text(&message.subject); - } - - if message.to.trim().is_empty() { - to_addresses_grid.hide(); - } else { - to_addresses_list.set_text(&message.to); - } - - if message.from.trim().is_empty() { - from_addresses_list.hide(); - } else { - from_addresses_list.set_text(&message.from); - } - - if message.cc.trim().is_empty() { - cc_addresses_grid.hide(); - } else { - cc_addresses_list.set_text(&message.cc); - } - - if message.bcc.trim().is_empty() { - bcc_addresses_grid.hide(); - } else { - bcc_addresses_list.set_text(&message.bcc); - } - - attachment_indicator.hide(); - - //@TODO implement an autoupdating timestamp - datetime_received_label.set_text(&message.get_relative_time_ago()); - //@TODO - datetime_received_label.set_tooltip_text(Some(&message.time_received.to_string())); - - view.load_content(message.content.as_ref().unwrap_or(&"".to_string())); - - box_row.upcast::() - }); + // let sender_clone = self.sender.clone(); + + // threads_list_view.connect_activate(move |list_view, position| { + // let model = list_view.model().unwrap(); + // let item = model.item(position); + + // if let Some(item) = item { + // let item = item.downcast_ref::().expect("Row data is of the wrong type"); + // let conversation_rc = item.get_conversation(); + // let conversation_borrow = conversation_rc.borrow(); + // let conversation = conversation_borrow.as_ref().expect("Model contents invalid"); + + // let message = conversation; + + // info!("Selected conversation with subject \"{}\"", message.subject); + + // sender_clone + // .borrow() + // .as_ref() + // .expect("Message sender not available") + // .send(ApplicationMessage::ShowConversation { + // conversation: message.clone(), + // }) + // .expect("Unable to send application message"); + // } else { + // // application.unload_current_conversation_thread (); + // } + // }); + + // conversation_model.connect_is_loading(move |args| { + // let is_loading = args[1].get::().expect("The is_loading value needs to be of type `bool`."); + + // if is_loading { + // conversation_viewer_stack.set_visible_child_name("loading"); + // spinner.start(); + // } else { + // conversation_viewer_stack.set_visible_child_name("conversation-viewer"); + // spinner.stop(); + // } + + // None + // }); + + // conversation_viewer_list_box.bind_model(Some(conversation_model), |item| { + // let item = item + // .downcast_ref::() + // .expect("Row data is of wrong type"); + // let message_rc = item.get_message(); + // let message_borrow = message_rc.borrow(); + // let message = message_borrow.as_ref().expect("Model contents invalid"); + + // let box_row = conversation_message_item::ConversationMessageItem::new_with_message(&message); + // box_row.style_context().add_class("conversation_message_item"); + // box_row.set_selectable(false); + + // let subject_label = gtk::Label::new(None); + // subject_label.set_ellipsize(gtk::pango::EllipsizeMode::End); + // subject_label.set_halign(gtk::Align::Start); + // subject_label.style_context().add_class("subject"); + // subject_label.set_xalign(0.0); + + // let from_addresses_list = gtk::Label::new(None); + // from_addresses_list.set_ellipsize(gtk::pango::EllipsizeMode::End); + // from_addresses_list.set_halign(gtk::Align::Start); + // from_addresses_list.style_context().add_class("from"); + // from_addresses_list.style_context().add_class("addresses"); + + // let to_addresses_label = gtk::Label::new(Some(&"to")); + // to_addresses_label.style_context().add_class("addresses_label"); + // let to_addresses_list = gtk::Label::new(None); + // to_addresses_list.set_ellipsize(gtk::pango::EllipsizeMode::End); + // to_addresses_list.set_hexpand(true); + // to_addresses_list.set_halign(gtk::Align::Start); + // let to_addresses_grid = gtk::Grid::new(); + // to_addresses_grid.style_context().add_class("to"); + // to_addresses_grid.style_context().add_class("addresses"); + // to_addresses_grid.attach(&to_addresses_label, 0, 0, 1, 1); + // to_addresses_grid.attach(&to_addresses_list, 1, 0, 1, 1); + + // let cc_addresses_label = gtk::Label::new(Some(&"cc")); + // cc_addresses_label.style_context().add_class("addresses_label"); + // let cc_addresses_list = gtk::Label::new(None); + // cc_addresses_list.set_ellipsize(gtk::pango::EllipsizeMode::End); + // cc_addresses_list.set_hexpand(true); + // cc_addresses_list.set_halign(gtk::Align::Start); + // let cc_addresses_grid = gtk::Grid::new(); + // cc_addresses_grid.style_context().add_class("cc"); + // cc_addresses_grid.style_context().add_class("addresses"); + // cc_addresses_grid.attach(&cc_addresses_label, 0, 0, 1, 1); + // cc_addresses_grid.attach(&cc_addresses_list, 1, 0, 1, 1); + + // let bcc_addresses_label = gtk::Label::new(Some(&"bcc")); + // bcc_addresses_label.style_context().add_class("addresses_label"); + // let bcc_addresses_list = gtk::Label::new(None); + // bcc_addresses_list.set_ellipsize(gtk::pango::EllipsizeMode::End); + // bcc_addresses_list.set_hexpand(true); + // bcc_addresses_list.set_halign(gtk::Align::Start); + // let bcc_addresses_grid = gtk::Grid::new(); + // bcc_addresses_grid.style_context().add_class("bcc"); + // bcc_addresses_grid.style_context().add_class("addresses"); + // bcc_addresses_grid.attach(&bcc_addresses_label, 0, 0, 1, 1); + // bcc_addresses_grid.attach(&bcc_addresses_list, 1, 0, 1, 1); + + // let header_summary_fields = gtk::Grid::new(); + // header_summary_fields.set_row_spacing(1); + // header_summary_fields.set_hexpand(true); + // header_summary_fields.set_valign(gtk::Align::Start); + // header_summary_fields.set_orientation(gtk::Orientation::Vertical); + // header_summary_fields.style_context().add_class("header_summary_fields"); + // header_summary_fields.attach(&subject_label, 0, 0, 1, 1); + // header_summary_fields.attach(&from_addresses_list, 0, 1, 1, 1); + // header_summary_fields.attach(&to_addresses_grid, 0, 2, 1, 1); + // header_summary_fields.attach(&cc_addresses_grid, 0, 3, 1, 1); + // header_summary_fields.attach(&bcc_addresses_grid, 0, 4, 1, 1); + + // let datetime_received_label = gtk::Label::new(None); + // datetime_received_label.style_context().add_class("received"); + // datetime_received_label.set_valign(gtk::Align::Start); + + // let attachment_indicator = gtk::Image::from_icon_name(&"mail-attachment-symbolic"); + // attachment_indicator.style_context().add_class("attachment_indicator"); + // attachment_indicator.set_valign(gtk::Align::Start); + // attachment_indicator.set_sensitive(false); + // attachment_indicator.set_tooltip_text(Some(&"This message contains one or more attachments")); + + // let message_header = gtk::Grid::new(); + // message_header.set_can_focus(false); + // message_header.set_orientation(gtk::Orientation::Horizontal); + // message_header.attach(&header_summary_fields, 0, 0, 1, 1); + // message_header.attach(&attachment_indicator, 1, 0, 1, 1); + // message_header.attach(&datetime_received_label, 2, 0, 1, 1); + + // let message_view = gtk::TextView::new(); + + // let buffer = message_view.buffer(); + + // let attachments_list = gtk::Grid::new(); + // attachments_list.set_orientation(gtk::Orientation::Vertical); + + // let view = message_view::MessageView::new(); + + // let grid = gtk::Grid::new(); + // grid.set_orientation(gtk::Orientation::Vertical); + // grid.attach(&message_header, 0, 0, 1, 1); + // grid.attach(&attachments_list, 0, 1, 1, 1); + // grid.attach(&view, 0, 2, 1, 1); + + // box_row.set_child(Some(&grid)); + + // if message.subject.trim().is_empty() { + // subject_label.hide(); + // } else { + // subject_label.set_text(&message.subject); + // } + + // if message.to.trim().is_empty() { + // to_addresses_grid.hide(); + // } else { + // to_addresses_list.set_text(&message.to); + // } + + // if message.from.trim().is_empty() { + // from_addresses_list.hide(); + // } else { + // from_addresses_list.set_text(&message.from); + // } + + // if message.cc.trim().is_empty() { + // cc_addresses_grid.hide(); + // } else { + // cc_addresses_list.set_text(&message.cc); + // } + + // if message.bcc.trim().is_empty() { + // bcc_addresses_grid.hide(); + // } else { + // bcc_addresses_list.set_text(&message.bcc); + // } + + // attachment_indicator.hide(); + + // //@TODO implement an autoupdating timestamp + // datetime_received_label.set_text(&message.get_relative_time_ago()); + // //@TODO + // datetime_received_label.set_tooltip_text(Some(&message.time_received.to_string())); + + // view.load_content(message.content.as_ref().unwrap_or(&"".to_string())); + + // box_row.upcast::() + // }); } } diff --git a/src/ui/window/dynamic_list_view.rs b/src/ui/window/dynamic_list_view.rs index fe539d5..4463362 100644 --- a/src/ui/window/dynamic_list_view.rs +++ b/src/ui/window/dynamic_list_view.rs @@ -7,7 +7,7 @@ mod imp { use std::{cell::Cell, ops::Range}; use gtk::{ - glib::{ParamSpec, ParamSpecEnum, ParamSpecObject, SignalHandlerId}, + glib::{ParamSpec, ParamSpecUInt, ParamSpecEnum, ParamSpecObject, SignalHandlerId}, Adjustment, ScrollablePolicy, }; use once_cell::sync::Lazy; @@ -218,58 +218,60 @@ mod imp { let factory_function_cell = self.factory_function.borrow(); let activate_function_cell = self.activate_function.borrow(); if let Some(factory_function) = factory_function_cell.as_ref() { - if let Some(activate_function) = activate_function_cell.as_ref() { - let obj = self.obj(); - - // We're reverting when location is top so we can use the insert_after to - // prepend new items - let range_items: Vec = match creation_location { - Location::Top => range.rev().collect(), - Location::Bottom => range.collect(), - }; - - let store_borrow = self.conversations_list_model.borrow(); - for item_index in range_items { - // It's okay to unwrap because we initialize at creation time - if let Some(item_data) = store_borrow.as_ref().unwrap().item(item_index) { - let row = factory_function(item_index, &item_data); - - let allocation = gtk::Allocation::new( - 0, - (item_index * self.height_per_row.get()) as i32, - obj.allocated_width(), - self.height_per_row.get() as i32, - ); - - let list_row_widget = row - .downcast_ref::() - .expect("Row is expected to be ListBoxRow"); - let activate_function_clone = activate_function.clone(); - let obj_clone = obj.clone(); - - list_row_widget.connect_activate(move || { - children_foreach(&obj_clone, &Order::Forward, move |row| { - if row.get_item_index() == item_index { - row.set_state_flags(gtk::StateFlags::SELECTED, false); - } else { - row.unset_state_flags(gtk::StateFlags::SELECTED); - } - - true - }); - - activate_function_clone(&obj_clone, item_index); + info!("Factory function found"); + + let obj = self.obj(); + + // We're reverting when location is top so we can use the insert_after to + // prepend new items + let range_items: Vec = match creation_location { + Location::Top => range.rev().collect(), + Location::Bottom => range.collect(), + }; + + let store_borrow = self.conversations_list_model.borrow(); + for item_index in range_items { + // It's okay to unwrap because we initialize at creation time + if let Some(item_data) = store_borrow.as_ref().unwrap().item(item_index) { + let row = factory_function(item_index, &item_data); + + let allocation = gtk::Allocation::new( + 0, + (item_index * self.height_per_row.get()) as i32, + obj.allocated_width(), + self.height_per_row.get() as i32, + ); + + let list_row_widget = row + .downcast_ref::() + .expect("Row is expected to be ListBoxRow"); + let activate_function_cell_clone = activate_function_cell.clone(); + let obj_clone = obj.clone(); + + list_row_widget.connect_activate(move || { + children_foreach(&obj_clone, &Order::Forward, move |row| { + if row.get_item_index() == item_index { + row.set_state_flags(gtk::StateFlags::SELECTED, false); + } else { + row.unset_state_flags(gtk::StateFlags::SELECTED); + } + + true }); - row.size_allocate(&allocation, -1); + if let Some(activate_function) = activate_function_cell_clone.as_ref() { + activate_function(&obj_clone, item_index); + } + }); - match creation_location { - Location::Top => { - row.insert_after(obj.upcast_ref::(), gtk::Widget::NONE); - } - Location::Bottom => { - row.insert_before(obj.upcast_ref::(), gtk::Widget::NONE); - } + row.size_allocate(&allocation, -1); + + match creation_location { + Location::Top => { + row.insert_after(obj.upcast_ref::(), gtk::Widget::NONE); + } + Location::Bottom => { + row.insert_before(obj.upcast_ref::(), gtk::Widget::NONE); } } } @@ -371,6 +373,7 @@ mod imp { ParamSpecObject::builder::("vadjustment").build(), ParamSpecEnum::builder_with_default::("hscroll-policy", ScrollablePolicy::Minimum).build(), ParamSpecEnum::builder_with_default::("vscroll-policy", ScrollablePolicy::Minimum).build(), + ParamSpecUInt::builder("height-per-row").build(), ] }); PROPERTIES.as_ref() @@ -407,6 +410,11 @@ mod imp { self.vscroll_policy.set(Some(value)); } } + "height-per-row" => { + if let Ok(value) = value.get::() { + self.height_per_row.set(value); + } + } _ => {} } } @@ -417,6 +425,7 @@ mod imp { "hscroll-policy" => self.hscroll_policy.get().unwrap_or(ScrollablePolicy::Minimum).to_value(), "vadjustment" => (*self.vertical_adjustment).borrow().to_value(), "vscroll-policy" => self.vscroll_policy.get().unwrap_or(ScrollablePolicy::Minimum).to_value(), + "height-per-row" => self.height_per_row.get().to_value(), _ => unimplemented!(), } } @@ -434,15 +443,11 @@ mod imp { } fn size_allocate(&self, width: i32, height: i32, baseline: i32) { - let obj = self.obj(); - - let allocation = gtk::Allocation::new(0, 0, width, height); - obj.size_allocate(&allocation, baseline); - self.configure_adjustment(height as u32); self.update_visible_children(); self.size_allocate_children(width); + let obj = self.obj(); obj.queue_draw(); } } @@ -465,8 +470,8 @@ impl DynamicListView { let self_ = imp::DynamicListView::from_obj(&instance); self_.set_height_per_row(height); - self_.set_conversations_list_model(conversations_list_model); - self_.set_factory(factory_function); + // self_.set_conversations_list_model(conversations_list_model); + // self_.set_factory(factory_function); instance } @@ -477,6 +482,18 @@ impl DynamicListView { self_.set_activate_function(activate_function); } + pub fn set_conversations_list_model(&self, conversations_list_model: FolderModel) { + let self_ = imp::DynamicListView::from_obj(self); + + self_.set_conversations_list_model(conversations_list_model); + } + + pub fn set_factory(&self, factory_function: impl Fn(u32, &glib::Object) -> gtk::Widget + 'static) { + let self_ = imp::DynamicListView::from_obj(self); + + self_.set_factory(factory_function); + } + pub fn model(&self) -> Option { let self_ = imp::DynamicListView::from_obj(self);