Reenable and update code for embedded message composer.

The embedded composer is now added to the the conversation list
box. Still needs some work to fix focus and scrolling issues, also to
insert the composer in the right place in the list.

* src/client/components/main-window.vala (MainWindow::set_styling):
  Adjust theme CSS to make padding around embedded coposer not so
  terrible. Fix style for embedded headerbar.

* src/client/composer/composer-embed.vala: Don't attempt to up-manage
  it's parent's state, since the parent has a much better idea of how
  best to do that. Instead of passing in a ConversationViewer, just pass
  in a Gtk.ScrolledWindow that needs to be adjusted as the embededded
  editor and add some signals needed by the ConversationViewer. Reenabled
  some code needed to get scroll event passthrough working.

* src/client/conversation-viewer/conversation-viewer.vala: Remove old
  embedded composer code. Adjust conversation_listbox callbacks to handle
  the embedded composer being present.
  (ConversationViewer::get_selected_message): Fixed to actually return a
  message.
  (ConversationViewer::do_embedded_composer): New method to set up an
  embedded composer.

* src/client/application/geary-controller.vala
  (GearyController::create_compose_widget_async): Call new
  ConversationViewer::do_embedded_composer to let it set up a new
  embedded composer when needed.
This commit is contained in:
Michael James Gratton 2016-04-12 01:06:09 +10:00
parent c55285f7f6
commit 69a53d9db9
5 changed files with 90 additions and 90 deletions

View file

@ -2166,10 +2166,11 @@ public class GearyController : Geary.BaseObject {
if (inline) {
if (widget.state == ComposerWidget.ComposerState.NEW ||
widget.state == ComposerWidget.ComposerState.PANED)
widget.state == ComposerWidget.ComposerState.PANED) {
main_window.conversation_viewer.do_compose(widget);
else
new ComposerEmbed(widget, main_window.conversation_viewer, referred); // is_draft
} else {
main_window.conversation_viewer.do_embedded_composer(widget, referred);
}
} else {
new ComposerWindow(widget);
widget.state = ComposerWidget.ComposerState.DETACHED;

View file

@ -18,12 +18,8 @@ public class ComposerBox : Gtk.Frame, ComposerContainer {
public Gtk.ApplicationWindow top_window {
get { return (Gtk.ApplicationWindow) get_toplevel(); }
public Gtk.Window top_window {
get { return (Gtk.Window) get_toplevel(); }
}
public signal void vanished();

View file

@ -12,57 +12,43 @@ public class ComposerEmbed : Gtk.EventBox, ComposerContainer {
private const int MIN_EDITOR_HEIGHT = 200;
private ConversationViewer conversation_viewer;
// The id of the composer HTML element
private string embed_id;
private bool setting_inner_scroll;
private bool scrolled_to_bottom = false;
//private double inner_scroll_adj_value;
private int inner_view_height;
private int min_height = MIN_EDITOR_HEIGHT;
protected ComposerWidget composer { get; set; }
protected Gee.MultiMap<string, string>? old_accelerators { get; set; }
public Geary.Email referred { get; private set; }
public Gtk.ApplicationWindow top_window {
get { return (Gtk.ApplicationWindow) get_toplevel(); }
}
public ComposerEmbed(ComposerWidget composer, ConversationViewer conversation_viewer,
Geary.Email referred) {
protected ComposerWidget composer { get; set; }
protected Gee.MultiMap<string, string>? old_accelerators { get; set; }
private Gtk.ScrolledWindow outer_scroller;
private bool setting_inner_scroll;
private bool scrolled_to_bottom = false;
private double inner_scroll_adj_value;
private int inner_view_height;
private int min_height = MIN_EDITOR_HEIGHT;
public signal void loaded();
public signal void vanished();
public ComposerEmbed(Geary.Email referred,
ComposerWidget composer,
Gtk.ScrolledWindow outer_scroller) {
this.referred = referred;
this.composer = composer;
this.conversation_viewer = conversation_viewer;
this.outer_scroller = outer_scroller;
this.halign = Gtk.Align.FILL;
this.valign = Gtk.Align.FILL;
WebKit.DOM.HTMLElement? email_element = null;
// email_element = conversation_viewer.web_view.get_dom_document().get_element_by_id(
// conversation_viewer.get_div_id(referred.id)) as WebKit.DOM.HTMLElement;
// embed_id = referred.id.to_string() + "_reply";
// if (email_element == null) {
// warning("Embedded composer could not find email to follow.");
// email_element = conversation_viewer.web_view.get_dom_document().get_element_by_id(
// "placeholder") as WebKit.DOM.HTMLElement;
// }
try {
email_element.insert_adjacent_html("afterend",
@"<div id='$embed_id' class='composer_embed'></div>");
} catch (Error error) {
debug("Error creating embed element: %s", error.message);
return;
}
add(composer);
realize.connect(on_realize);
this.composer.editor.focus_in_event.connect(on_focus_in);
this.composer.editor.focus_out_event.connect(on_focus_out);
this.composer.editor.document_load_finished.connect(on_loaded);
this.conversation_viewer.compose_overlay.add_overlay(this);
show();
present();
}
private void on_realize() {
@ -86,7 +72,7 @@ public class ComposerEmbed : Gtk.EventBox, ComposerContainer {
}
Idle.add(() => {
recalc_height();
conversation_viewer.compose_overlay.queue_resize();
loaded();
return false;
});
}
@ -190,12 +176,12 @@ public class ComposerEmbed : Gtk.EventBox, ComposerContainer {
}
private void on_inner_scroll(Gtk.Adjustment adj) {
// double delta = adj.value - this.inner_scroll_adj_value;
// this.inner_scroll_adj_value = adj.value;
// if (delta != 0 && !setting_inner_scroll) {
// Gtk.Adjustment outer_adj = this.conversation_viewer.web_view.vadjustment;
// outer_adj.set_value(outer_adj.value + delta);
// }
double delta = adj.value - this.inner_scroll_adj_value;
this.inner_scroll_adj_value = adj.value;
if (delta != 0 && !this.setting_inner_scroll) {
Gtk.Adjustment outer_adj = outer_scroller.vadjustment;
this.outer_adj.set_value(outer_adj.value + delta);
}
}
private void on_adjust_changed(Gtk.Adjustment adj) {
@ -225,30 +211,21 @@ public class ComposerEmbed : Gtk.EventBox, ComposerContainer {
if (view_height != inner_view_height || min_height != base_height + MIN_EDITOR_HEIGHT) {
this.inner_view_height = view_height;
this.min_height = base_height + MIN_EDITOR_HEIGHT;
// Calculate height widget should be to avoid scrolling in editor
// int widget_height = int.max(view_height + base_height - 2, min_height); //? about 2
// WebKit.DOM.Element embed = this.conversation_viewer.web_view
// .get_dom_document().get_element_by_id(this.embed_id);
// if (embed != null) {
// try {
// embed.style.set_property("height", @"$widget_height", "");
// } catch (Error error) {
// debug("Error setting height of composer widget");
// }
// }
int widget_height = int.max(view_height + base_height - 2, min_height); //? about 2
set_size_request(-1, widget_height);
}
return false;
}
private bool on_inner_scroll_event(Gdk.EventScroll event) {
//this.conversation_viewer.web_view.scroll_event(event);
this.outer_scroller.scroll_event(event);
return true;
}
public void present() {
this.top_window.present();
// this.conversation_viewer.web_view.get_dom_document().get_element_by_id(this.embed_id)
// .scroll_into_view_if_needed(false);
top_window.present();
}
public void vanish() {
@ -256,20 +233,12 @@ public class ComposerEmbed : Gtk.EventBox, ComposerContainer {
this.composer.state = ComposerWidget.ComposerState.DETACHED;
this.composer.editor.focus_in_event.disconnect(on_focus_in);
this.composer.editor.focus_out_event.disconnect(on_focus_out);
// WebKit.DOM.Element embed = this.conversation_viewer.web_view.get_dom_document().
// get_element_by_id(this.embed_id);
// try{
// embed.parent_element.remove_child(embed);
// } catch (Error error) {
// warning("Could not remove embed from WebView: %s", error.message);
// }
vanished();
}
public void close_container() {
if (visible)
vanish();
this.conversation_viewer.compose_overlay.remove(this);
}
}

View file

@ -86,9 +86,6 @@ public class ConversationViewer : Gtk.Stack {
// Current conversation, or null if none.
public Geary.App.Conversation? current_conversation = null;
// Overlay containing any inline composers.
public ScrollableOverlay compose_overlay;
// Stack pages
[GtkChild]
private Gtk.Image splash_page;
@ -135,13 +132,23 @@ public class ConversationViewer : Gtk.Stack {
public ConversationViewer() {
// Setup the conversation list box
conversation_listbox.set_sort_func((row1, row2) => {
return Geary.Email.compare_sent_date_ascending(
((ConversationMessage) row1.get_child()).email,
((ConversationMessage) row2.get_child()).email
);
// If not a ConversationMessage, will be an
// embedded composer and should always be last.
ConversationMessage? msg1 = row1.get_child() as ConversationMessage;
if (msg1 == null) {
return 1;
}
ConversationMessage? msg2 = row2.get_child() as ConversationMessage;
if (msg2 == null) {
return -1;
}
return Geary.Email.compare_sent_date_ascending(msg1.email, msg2.email);
});
conversation_listbox.row_activated.connect((box, row) => {
if (email_to_row.size > 1) {
// If not a ConversationMessage, will be an
// embedded composer and should not be activated.
ConversationMessage? msg = row.get_child() as ConversationMessage;
if (email_to_row.size > 1 && msg != null) {
toggle_show_message(row);
}
});
@ -171,9 +178,6 @@ public class ConversationViewer : Gtk.Stack {
GearyApplication.instance.controller.folder_selected.connect(on_folder_selected);
GearyApplication.instance.controller.conversation_count_changed.connect(on_conversation_count_changed);
//compose_overlay = new ScrollableOverlay(web_view);
//conversation_viewer_scrolled.add(compose_overlay);
//conversation_find_bar = new ConversationFindBar(web_view);
//conversation_find_bar.no_show_all = true;
//conversation_find_bar.close.connect(() => { fsm.issue(SearchEvent.CLOSE_FIND_BAR); });
@ -187,9 +191,10 @@ public class ConversationViewer : Gtk.Stack {
}
public Geary.Email? get_selected_message(out string? quote) {
// XXX
quote = "";
return null;
// XXX check to see if there is a message with selected text,
// if so return that
quote = null;
return messages.is_empty ? null : messages.last();
}
public void check_mark_read() {
@ -270,6 +275,30 @@ public class ConversationViewer : Gtk.Stack {
set_visible_child(composer_page);
}
public void do_embedded_composer(ComposerWidget composer, Geary.Email referred) {
state = ViewState.CONVERSATION;
ComposerEmbed embed = new ComposerEmbed(
referred, composer, conversation_page
);
embed.set_property("name", "composer_embed"); // Bug 764622
Gtk.ListBoxRow row = new Gtk.ListBoxRow();
row.get_style_context().add_class("composer");
row.get_style_context().add_class("frame");
row.show();
row.add(embed);
conversation_listbox.add(row);
embed.loaded.connect((box) => {
row.grab_focus();
});
embed.vanished.connect((box) => {
conversation_listbox.remove(row);
});
}
// Removes all displayed e-mails from the view.
private void clear() {
foreach (Gtk.Widget child in conversation_listbox.get_children()) {

View file

@ -58,7 +58,7 @@ row.geary-folder-popover-list-row > label {
}
#conversation_listbox {
padding: 18px 18px 0;
padding: 18px 18px calc(18px/2);
}
#conversation_listbox > row {
margin: 0;
@ -67,8 +67,9 @@ row.geary-folder-popover-list-row > label {
box-shadow: 0 4px 8px 1px rgba(0,0,0,0.4);
transition: margin 0.1s;
}
#conversation_listbox > row.show-message {
margin-bottom: 18px;
#conversation_listbox > row.show-message,
#conversation_listbox > row.composer {
margin-bottom: calc(18px/2);
border-bottom-width: 1px;
}
@ -81,3 +82,7 @@ row.geary-folder-popover-list-row > label {
#ConversationMessage separator {
margin: 12px 0;
}
#composer_embed headerbar {
border-radius: 0px;
}