improve sidebar UI
- only display messages that are content items - only display messages for active accounts - "fix" textview issue - add empty states (no search, no results)
This commit is contained in:
parent
4901b09670
commit
e376a577b6
|
@ -43,8 +43,9 @@ public class Database : Qlite.Database {
|
||||||
public Column<int> foreign_id = new Column.Integer("foreign_id") { not_null = true };
|
public Column<int> foreign_id = new Column.Integer("foreign_id") { not_null = true };
|
||||||
|
|
||||||
internal ContentTable(Database db) {
|
internal ContentTable(Database db) {
|
||||||
base(db, "content");
|
base(db, "contentx");
|
||||||
init({id, conversation_id, time, local_time, content_type, foreign_id});
|
init({id, conversation_id, time, local_time, content_type, foreign_id});
|
||||||
|
unique({content_type, foreign_id}, "IGNORE");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +228,7 @@ public class Database : Qlite.Database {
|
||||||
message.fts_rebuild();
|
message.fts_rebuild();
|
||||||
} else if (oldVersion < 8) {
|
} else if (oldVersion < 8) {
|
||||||
exec("""
|
exec("""
|
||||||
insert into content (conversation_id, time, local_time, content_type, foreign_id)
|
insert into contentx (conversation_id, time, local_time, content_type, foreign_id)
|
||||||
select conversation.id, message.time, message.local_time, 1, message.id
|
select conversation.id, message.time, message.local_time, 1, message.id
|
||||||
from message join conversation on
|
from message join conversation on
|
||||||
message.account_id=conversation.account_id and
|
message.account_id=conversation.account_id and
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class MessageStorage : StreamInteractionModule, Object {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Gee.List<Message>? get_messages_before_message(Conversation? conversation, DateTime before, int id, int count = 20) {
|
public Gee.List<MessageItem> get_messages_before_message(Conversation? conversation, DateTime before, int id, int count = 20) {
|
||||||
// SortedSet<Message>? before = messages[conversation].head_set(message);
|
// SortedSet<Message>? before = messages[conversation].head_set(message);
|
||||||
// if (before != null && before.size >= count) {
|
// if (before != null && before.size >= count) {
|
||||||
// Gee.List<Message> ret = new ArrayList<Message>(Message.equals_func);
|
// Gee.List<Message> ret = new ArrayList<Message>(Message.equals_func);
|
||||||
|
@ -66,14 +66,22 @@ public class MessageStorage : StreamInteractionModule, Object {
|
||||||
// }
|
// }
|
||||||
// return ret;
|
// return ret;
|
||||||
// } else {
|
// } else {
|
||||||
Gee.List<Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, Util.get_message_type_for_conversation(conversation), count, before, null, id);
|
Gee.List<Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, Util.get_message_type_for_conversation(conversation), count, before, null, id);
|
||||||
return db_messages;
|
Gee.List<MessageItem> ret = new ArrayList<MessageItem>();
|
||||||
|
foreach (Message message in db_messages) {
|
||||||
|
ret.add(new MessageItem(message, conversation, -1));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Gee.List<Message>? get_messages_after_message(Conversation? conversation, DateTime after, int id, int count = 20) {
|
public Gee.List<MessageItem> get_messages_after_message(Conversation? conversation, DateTime after, int id, int count = 20) {
|
||||||
Gee.List<Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, Util.get_message_type_for_conversation(conversation), count, null, after, id);
|
Gee.List<Message> db_messages = db.get_messages(conversation.counterpart, conversation.account, Util.get_message_type_for_conversation(conversation), count, null, after, id);
|
||||||
return db_messages;
|
Gee.List<MessageItem> ret = new ArrayList<MessageItem>();
|
||||||
|
foreach (Message message in db_messages) {
|
||||||
|
ret.add(new MessageItem(message, conversation, -1));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Message? get_message_by_id(int id, Conversation conversation) {
|
public Message? get_message_by_id(int id, Conversation conversation) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ public class SearchProcessor : StreamInteractionModule, Object {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryBuilder prepare_search(string query) {
|
private QueryBuilder prepare_search(string query, bool join_content) {
|
||||||
string words = "";
|
string words = "";
|
||||||
string? with = null;
|
string? with = null;
|
||||||
string? in_ = null;
|
string? in_ = null;
|
||||||
|
@ -60,7 +60,12 @@ public class SearchProcessor : StreamInteractionModule, Object {
|
||||||
.order_by(db.message.id, "DESC")
|
.order_by(db.message.id, "DESC")
|
||||||
.join_with(db.jid, db.jid.id, db.message.counterpart_id)
|
.join_with(db.jid, db.jid.id, db.message.counterpart_id)
|
||||||
.join_with(db.account, db.account.id, db.message.account_id)
|
.join_with(db.account, db.account.id, db.message.account_id)
|
||||||
.outer_join_with(db.real_jid, db.real_jid.message_id, db.message.id);
|
.outer_join_with(db.real_jid, db.real_jid.message_id, db.message.id)
|
||||||
|
.with(db.account.enabled, "=", true);
|
||||||
|
if (join_content) {
|
||||||
|
rows.join_on(db.content, "message.id=contentx.foreign_id AND contentx.content_type=1")
|
||||||
|
.with(db.content.content_type, "=", 1);
|
||||||
|
}
|
||||||
if (with != null) {
|
if (with != null) {
|
||||||
if (with.index_of("/") > 0) {
|
if (with.index_of("/") > 0) {
|
||||||
rows.with(db.message.type_, "=", Message.Type.GROUPCHAT_PM)
|
rows.with(db.message.type_, "=", Message.Type.GROUPCHAT_PM)
|
||||||
|
@ -85,20 +90,22 @@ public class SearchProcessor : StreamInteractionModule, Object {
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Gee.List<Message> match_messages(string query, int offset = -1) {
|
public Gee.List<MessageItem> match_messages(string query, int offset = -1) {
|
||||||
Gee.List<Message> ret = new ArrayList<Message>(Message.equals_func);
|
Gee.List<MessageItem> ret = new ArrayList<MessageItem>();
|
||||||
var rows = prepare_search(query).limit(10);
|
var rows = prepare_search(query, true).limit(10);
|
||||||
if (offset > 0) {
|
if (offset > 0) {
|
||||||
rows.offset(offset);
|
rows.offset(offset);
|
||||||
}
|
}
|
||||||
foreach (Row row in rows) {
|
foreach (Row row in rows) {
|
||||||
ret.add(new Message.from_row(db, row));
|
Message message = new Message.from_row(db, row);
|
||||||
|
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_for_message(message);
|
||||||
|
ret.add(new MessageItem(message, conversation, row[db.content.id]));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int count_match_messages(string query) {
|
public int count_match_messages(string query) {
|
||||||
return (int)prepare_search(query).select({db.message.id}).count();
|
return (int)prepare_search(query, false).select({db.message.id}).count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,24 +10,135 @@
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkLabel" id="entry_number_label">
|
<object class="GtkStack" id="results_empty_stack">
|
||||||
<property name="xalign">0</property>
|
|
||||||
<property name="use-markup">True</property>
|
|
||||||
<property name="margin-left">17</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkScrolledWindow" id="results_scrolled">
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox" id="results_box">
|
<object class="GtkBox">
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="spacing">25</property>
|
<property name="spacing">10</property>
|
||||||
<property name="margin">10</property>
|
<property name="valign">center</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="icon-name">system-search-symbolic</property>
|
||||||
|
<property name="icon-size">4</property>
|
||||||
|
<property name="pixel-size">72</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="label" translatable="yes">No active search</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
|
||||||
|
<attribute name="scale" value="1.3"/>
|
||||||
|
</attributes>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="label" translatable="yes">Type to start a search</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">empty</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">10</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="icon-name">face-uncertain-symbolic</property>
|
||||||
|
<property name="icon-size">4</property>
|
||||||
|
<property name="pixel-size">72</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="label" translatable="yes">No matching messages</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
|
||||||
|
<attribute name="scale" value="1.3"/>
|
||||||
|
</attributes>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="label" translatable="yes">Check the spelling or try to remove filters</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">no-result</property>
|
||||||
|
</packing>
|
||||||
|
</child>z
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="entry_number_label">
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="use-markup">True</property>
|
||||||
|
<property name="margin-left">17</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="results_scrolled">
|
||||||
|
<property name="hscrollbar-policy">never</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="results_box">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">25</property>
|
||||||
|
<property name="margin">10</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">results</property>
|
||||||
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
|
|
@ -17,6 +17,22 @@ window.dino-main .dino-conversation undershoot {
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes highlight {
|
||||||
|
from { background: alpha(@warning_color, 0.5) }
|
||||||
|
to { background: transparent }
|
||||||
|
}
|
||||||
|
|
||||||
|
window.dino-main .dino-conversation .highlight-once {
|
||||||
|
animation-duration: 3s;
|
||||||
|
animation-timing-function: ease-out;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
animation-name: highlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.dino-main .dino-conversation textview, window.dino-main .dino-conversation textview text {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
window.dino-main .dino-sidebar frame {
|
window.dino-main .dino-sidebar frame {
|
||||||
background: @insensitive_bg_color;
|
background: @insensitive_bg_color;
|
||||||
border-left: 1px solid @borders;
|
border-left: 1px solid @borders;
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class Dino.Ui.Application : Gtk.Application, Dino.Application {
|
||||||
window = new UnifiedWindow(this, stream_interactor);
|
window = new UnifiedWindow(this, stream_interactor);
|
||||||
notifications = new Notifications(stream_interactor, window);
|
notifications = new Notifications(stream_interactor, window);
|
||||||
notifications.start();
|
notifications.start();
|
||||||
notifications.conversation_selected.connect(window.on_conversation_selected);
|
notifications.conversation_selected.connect((conversation) => window.on_conversation_selected(conversation));
|
||||||
}
|
}
|
||||||
window.present();
|
window.present();
|
||||||
});
|
});
|
||||||
|
|
|
@ -34,6 +34,7 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
private bool animate = false;
|
private bool animate = false;
|
||||||
private bool firstLoad = true;
|
private bool firstLoad = true;
|
||||||
private bool at_current_content = true;
|
private bool at_current_content = true;
|
||||||
|
private bool reload_messages = true;
|
||||||
|
|
||||||
public ConversationView init(StreamInteractor stream_interactor) {
|
public ConversationView init(StreamInteractor stream_interactor) {
|
||||||
this.stream_interactor = stream_interactor;
|
this.stream_interactor = stream_interactor;
|
||||||
|
@ -57,7 +58,6 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
Util.force_base_background(this);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,14 +66,71 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
if (firstLoad) {
|
if (firstLoad) {
|
||||||
int timeout = firstLoad ? 1000 : 0;
|
int timeout = firstLoad ? 1000 : 0;
|
||||||
Timeout.add(timeout, () => {
|
Timeout.add(timeout, () => {
|
||||||
|
stack.set_visible_child_name("void");
|
||||||
initialize_for_conversation_(conversation);
|
initialize_for_conversation_(conversation);
|
||||||
|
display_latest();
|
||||||
|
stack.set_visible_child_name("main");
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
firstLoad = false;
|
firstLoad = false;
|
||||||
} else {
|
} else {
|
||||||
|
stack.set_visible_child_name("void");
|
||||||
initialize_for_conversation_(conversation);
|
initialize_for_conversation_(conversation);
|
||||||
|
display_latest();
|
||||||
|
stack.set_visible_child_name("main");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize_around_message(Conversation conversation, ContentItem content_item) {
|
||||||
|
stack.set_visible_child_name("void");
|
||||||
|
clear();
|
||||||
|
initialize_for_conversation_(conversation);
|
||||||
|
Gee.List<ContentMetaItem> before_items = content_populator.populate_before(conversation, content_item, 40);
|
||||||
|
foreach (ContentMetaItem item in before_items) {
|
||||||
|
do_insert_item(item);
|
||||||
|
}
|
||||||
|
ContentMetaItem meta_item = content_populator.get_content_meta_item(content_item);
|
||||||
|
meta_item.can_merge = false;
|
||||||
|
Widget w = insert_new(meta_item);
|
||||||
|
content_items.add(meta_item);
|
||||||
|
meta_items.add(meta_item);
|
||||||
|
|
||||||
|
Gee.List<ContentMetaItem> after_items = content_populator.populate_after(conversation, content_item, 40);
|
||||||
|
foreach (ContentMetaItem item in after_items) {
|
||||||
|
do_insert_item(item);
|
||||||
|
}
|
||||||
|
if (after_items.size == 40) {
|
||||||
|
at_current_content = false;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int h = 0, i = 0;
|
||||||
|
main.@foreach((widget) => {
|
||||||
|
if (i >= before_items.size) return;
|
||||||
|
ConversationItemSkeleton? sk = widget as ConversationItemSkeleton;
|
||||||
|
i += sk != null ? sk.items.size : 1;
|
||||||
|
int minimum_height, natural_height;
|
||||||
|
widget.get_preferred_height_for_width(main.get_allocated_width() - 2 * main.margin, out minimum_height, out natural_height);
|
||||||
|
h += minimum_height + 15;
|
||||||
|
});
|
||||||
|
print(@"height_for_w: $(h)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reload_messages = false;
|
||||||
|
Timeout.add(700, () => {
|
||||||
|
int h = 0, i = 0;
|
||||||
|
main.@foreach((widget) => {
|
||||||
|
if (i >= before_items.size) return;
|
||||||
|
ConversationItemSkeleton? sk = widget as ConversationItemSkeleton;
|
||||||
|
i += sk != null ? sk.items.size : 1;
|
||||||
|
h += widget.get_allocated_height() + 15;
|
||||||
|
});
|
||||||
|
print(@"timeout: $(h)\n");
|
||||||
|
scrolled.vadjustment.value = h - scrolled.vadjustment.page_size * 1/3;
|
||||||
|
w.get_style_context().add_class("highlight-once");
|
||||||
|
reload_messages = true;
|
||||||
|
stack.set_visible_child_name("main");
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize_for_conversation_(Conversation? conversation) {
|
private void initialize_for_conversation_(Conversation? conversation) {
|
||||||
|
@ -84,7 +141,6 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.conversation = conversation;
|
this.conversation = conversation;
|
||||||
stack.set_visible_child_name("void");
|
|
||||||
|
|
||||||
foreach (Plugins.ConversationItemPopulator populator in app.plugin_registry.conversation_addition_populators) {
|
foreach (Plugins.ConversationItemPopulator populator in app.plugin_registry.conversation_addition_populators) {
|
||||||
populator.init(conversation, this, Plugins.WidgetType.GTK);
|
populator.init(conversation, this, Plugins.WidgetType.GTK);
|
||||||
|
@ -92,17 +148,12 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
content_populator.init(this, conversation, Plugins.WidgetType.GTK);
|
content_populator.init(this, conversation, Plugins.WidgetType.GTK);
|
||||||
subscription_notification.init(conversation, this);
|
subscription_notification.init(conversation, this);
|
||||||
|
|
||||||
display_latest();
|
animate = false;
|
||||||
|
Timeout.add(20, () => { animate = true; return false; });
|
||||||
stack.set_visible_child_name("main");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void display_latest() {
|
private void display_latest() {
|
||||||
clear();
|
clear();
|
||||||
was_upper = null;
|
|
||||||
was_page_size = null;
|
|
||||||
animate = false;
|
|
||||||
Timeout.add(20, () => { animate = true; return false; });
|
|
||||||
|
|
||||||
Gee.List<ContentMetaItem> items = content_populator.populate_latest(conversation, 40);
|
Gee.List<ContentMetaItem> items = content_populator.populate_latest(conversation, 40);
|
||||||
foreach (ContentMetaItem item in items) {
|
foreach (ContentMetaItem item in items) {
|
||||||
|
@ -163,7 +214,7 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
lower_start_item.encryption == item.encryption &&
|
lower_start_item.encryption == item.encryption &&
|
||||||
(item.mark == Message.Marked.WONTSEND) == (lower_start_item.mark == Message.Marked.WONTSEND)) {
|
(item.mark == Message.Marked.WONTSEND) == (lower_start_item.mark == Message.Marked.WONTSEND)) {
|
||||||
lower_skeleton.add_meta_item(item);
|
lower_skeleton.add_meta_item(item);
|
||||||
force_alloc_width(lower_skeleton, main.get_allocated_width());
|
Util.force_alloc_width(lower_skeleton, main.get_allocated_width());
|
||||||
|
|
||||||
widgets[item] = widgets[lower_start_item];
|
widgets[item] = widgets[lower_start_item];
|
||||||
item_item_skeletons[item] = lower_skeleton;
|
item_item_skeletons[item] = lower_skeleton;
|
||||||
|
@ -174,7 +225,7 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insert_new(Plugins.MetaConversationItem item) {
|
private Widget insert_new(Plugins.MetaConversationItem item) {
|
||||||
Plugins.MetaConversationItem? lower_item = meta_items.lower(item);
|
Plugins.MetaConversationItem? lower_item = meta_items.lower(item);
|
||||||
|
|
||||||
// Does another skeleton need to be split?
|
// Does another skeleton need to be split?
|
||||||
|
@ -206,7 +257,7 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
main.add(insert);
|
main.add(insert);
|
||||||
}
|
}
|
||||||
widgets[item] = insert;
|
widgets[item] = insert;
|
||||||
force_alloc_width(insert, main.get_allocated_width());
|
Util.force_alloc_width(insert, main.get_allocated_width());
|
||||||
main.reorder_child(insert, index);
|
main.reorder_child(insert, index);
|
||||||
|
|
||||||
// If an item from the past was added, add everything between that item and the (post-)first present item
|
// If an item from the past was added, add everything between that item and the (post-)first present item
|
||||||
|
@ -222,6 +273,7 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return insert;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void split_at_time(ConversationItemSkeleton split_skeleton, DateTime time) {
|
private void split_at_time(ConversationItemSkeleton split_skeleton, DateTime time) {
|
||||||
|
@ -273,10 +325,6 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
Gee.List<ContentMetaItem> items = content_populator.populate_before(conversation, (content_items.first() as ContentMetaItem).content_item, 20);
|
Gee.List<ContentMetaItem> items = content_populator.populate_before(conversation, (content_items.first() as ContentMetaItem).content_item, 20);
|
||||||
foreach (ContentMetaItem item in items) {
|
foreach (ContentMetaItem item in items) {
|
||||||
do_insert_item(item);
|
do_insert_item(item);
|
||||||
if (content_items.size > 50) {
|
|
||||||
do_remove_item(content_items.last());
|
|
||||||
at_current_content = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reloading_mutex.unlock();
|
reloading_mutex.unlock();
|
||||||
|
@ -310,21 +358,14 @@ public class ConversationView : Box, Plugins.ConversationItemCollection {
|
||||||
int res = a.sort_time.compare(b.sort_time);
|
int res = a.sort_time.compare(b.sort_time);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
if (a.seccondary_sort_indicator < b.seccondary_sort_indicator) res = -1;
|
if (a.seccondary_sort_indicator < b.seccondary_sort_indicator) res = -1;
|
||||||
else if (a.seccondary_sort_indicator > b.seccondary_sort_indicator) res = 1;
|
else if (a.seccondary_sort_indicator > b.seccondary_sort_indicator) res = 1;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workaround GTK TextView issues
|
|
||||||
private void force_alloc_width(Widget widget, int width) {
|
|
||||||
Allocation alloc = Allocation();
|
|
||||||
widget.get_preferred_width(out alloc.width, null);
|
|
||||||
widget.get_preferred_height(out alloc.height, null);
|
|
||||||
alloc.width = width;
|
|
||||||
widget.size_allocate(alloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clear() {
|
private void clear() {
|
||||||
|
was_upper = null;
|
||||||
|
was_page_size = null;
|
||||||
content_items.clear();
|
content_items.clear();
|
||||||
meta_items.clear();
|
meta_items.clear();
|
||||||
item_skeletons.clear();
|
item_skeletons.clear();
|
||||||
|
|
|
@ -24,7 +24,6 @@ public class MessageTextView : TextView {
|
||||||
motion_notify_event.connect(change_cursor_over_url);
|
motion_notify_event.connect(change_cursor_over_url);
|
||||||
|
|
||||||
update_display_style();
|
update_display_style();
|
||||||
Util.force_base_background(this, "textview, text:not(:selected)");
|
|
||||||
style_updated.connect(update_display_style);
|
style_updated.connect(update_display_style);
|
||||||
populate_popup.connect(populate_context_menu);
|
populate_popup.connect(populate_context_menu);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,7 @@ public class SearchMenuEntry : Plugins.ConversationTitlebarEntry, Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GlobalSearchButton : Plugins.ConversationTitlebarWidget, Gtk.ToggleButton {
|
public class GlobalSearchButton : Plugins.ConversationTitlebarWidget, Gtk.ToggleButton {
|
||||||
public new void set_conversation(Conversation conversation) {
|
public new void set_conversation(Conversation conversation) { }
|
||||||
active = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Gee;
|
||||||
using Gtk;
|
using Gtk;
|
||||||
using Pango;
|
using Pango;
|
||||||
|
|
||||||
|
@ -7,6 +8,8 @@ namespace Dino.Ui {
|
||||||
|
|
||||||
[GtkTemplate (ui = "/im/dino/Dino/global_search.ui")]
|
[GtkTemplate (ui = "/im/dino/Dino/global_search.ui")]
|
||||||
class GlobalSearch : Box {
|
class GlobalSearch : Box {
|
||||||
|
public signal void selected_item(MessageItem item);
|
||||||
|
|
||||||
private StreamInteractor stream_interactor;
|
private StreamInteractor stream_interactor;
|
||||||
private string search = "";
|
private string search = "";
|
||||||
private int loaded_results = -1;
|
private int loaded_results = -1;
|
||||||
|
@ -16,6 +19,7 @@ class GlobalSearch : Box {
|
||||||
[GtkChild] public Label entry_number_label;
|
[GtkChild] public Label entry_number_label;
|
||||||
[GtkChild] public ScrolledWindow results_scrolled;
|
[GtkChild] public ScrolledWindow results_scrolled;
|
||||||
[GtkChild] public Box results_box;
|
[GtkChild] public Box results_box;
|
||||||
|
[GtkChild] public Stack results_empty_stack;
|
||||||
|
|
||||||
public GlobalSearch init(StreamInteractor stream_interactor) {
|
public GlobalSearch init(StreamInteractor stream_interactor) {
|
||||||
this.stream_interactor = stream_interactor;
|
this.stream_interactor = stream_interactor;
|
||||||
|
@ -27,7 +31,7 @@ class GlobalSearch : Box {
|
||||||
results_scrolled.vadjustment.notify["value"].connect(() => {
|
results_scrolled.vadjustment.notify["value"].connect(() => {
|
||||||
if (results_scrolled.vadjustment.upper - (results_scrolled.vadjustment.value + results_scrolled.vadjustment.page_size) < 100) {
|
if (results_scrolled.vadjustment.upper - (results_scrolled.vadjustment.value + results_scrolled.vadjustment.page_size) < 100) {
|
||||||
if (!reloading_mutex.trylock()) return;
|
if (!reloading_mutex.trylock()) return;
|
||||||
Gee.List<Message> new_messages = stream_interactor.get_module(SearchProcessor.IDENTITY).match_messages(search, loaded_results);
|
Gee.List<MessageItem> new_messages = stream_interactor.get_module(SearchProcessor.IDENTITY).match_messages(search, loaded_results);
|
||||||
if (new_messages.size == 0) {
|
if (new_messages.size == 0) {
|
||||||
reloading_mutex.unlock();
|
reloading_mutex.unlock();
|
||||||
return;
|
return;
|
||||||
|
@ -51,37 +55,47 @@ class GlobalSearch : Box {
|
||||||
clear_search();
|
clear_search();
|
||||||
this.search = search;
|
this.search = search;
|
||||||
|
|
||||||
int match_count = stream_interactor.get_module(SearchProcessor.IDENTITY).count_match_messages(search);
|
if (get_keywords(search).is_empty) {
|
||||||
entry_number_label.label = "<i>" + _("%i search results").printf(match_count) + "</i>";
|
results_empty_stack.set_visible_child_name("empty");
|
||||||
Gee.List<Message> messages = stream_interactor.get_module(SearchProcessor.IDENTITY).match_messages(search);
|
return;
|
||||||
loaded_results += messages.size;
|
}
|
||||||
append_messages(messages);
|
|
||||||
|
Gee.List<MessageItem> messages = stream_interactor.get_module(SearchProcessor.IDENTITY).match_messages(search);
|
||||||
|
if (messages.size == 0) {
|
||||||
|
results_empty_stack.set_visible_child_name("no-result");
|
||||||
|
} else {
|
||||||
|
results_empty_stack.set_visible_child_name("results");
|
||||||
|
|
||||||
|
int match_count = messages.size < 10 ? messages.size : stream_interactor.get_module(SearchProcessor.IDENTITY).count_match_messages(search);
|
||||||
|
entry_number_label.label = "<i>" + _("%i search results").printf(match_count) + "</i>";
|
||||||
|
loaded_results += messages.size;
|
||||||
|
append_messages(messages);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void append_messages(Gee.List<Message> messages) {
|
private void append_messages(Gee.List<MessageItem> messages) {
|
||||||
foreach (Message message in messages) {
|
foreach (MessageItem item in messages) {
|
||||||
if (message.from == null) {
|
Gee.List<MessageItem> before_message = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages_before_message(item.conversation, item.message.local_time, item.message.id, 1);
|
||||||
print("wtf null\n");
|
Gee.List<MessageItem> after_message = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages_after_message(item.conversation, item.message.local_time, item.message.id, 1);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_for_message(message);
|
|
||||||
Gee.List<Message> before_message = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages_before_message(conversation, message.local_time, message.id, 1);
|
|
||||||
Gee.List<Message> after_message = stream_interactor.get_module(MessageStorage.IDENTITY).get_messages_after_message(conversation, message.local_time, message.id, 1);
|
|
||||||
|
|
||||||
Box context_box = new Box(Orientation.VERTICAL, 5) { visible=true };
|
Box context_box = new Box(Orientation.VERTICAL, 5) { visible=true };
|
||||||
if (before_message != null && before_message.size > 0) {
|
if (before_message != null && before_message.size > 0) {
|
||||||
context_box.add(get_context_message_widget(before_message.first()));
|
context_box.add(get_context_message_widget(before_message.first()));
|
||||||
}
|
}
|
||||||
context_box.add(get_match_message_widget(message));
|
|
||||||
|
Widget match_widget = get_match_message_widget(item);
|
||||||
|
Util.force_alloc_width(match_widget, results_empty_stack.get_allocated_width() - results_box.margin * 2);
|
||||||
|
context_box.add(match_widget);
|
||||||
|
|
||||||
if (after_message != null && after_message.size > 0) {
|
if (after_message != null && after_message.size > 0) {
|
||||||
context_box.add(get_context_message_widget(after_message.first()));
|
context_box.add(get_context_message_widget(after_message.first()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Label date_label = new Label(ConversationSummary.DefaultSkeletonHeader.get_relative_time(message.time)) { xalign=0, visible=true };
|
Label date_label = new Label(ConversationSummary.DefaultSkeletonHeader.get_relative_time(item.display_time)) { xalign=0, visible=true };
|
||||||
date_label.get_style_context().add_class("dim-label");
|
date_label.get_style_context().add_class("dim-label");
|
||||||
|
|
||||||
string display_name = Util.get_conversation_display_name(stream_interactor, conversation);
|
string display_name = Util.get_conversation_display_name(stream_interactor, item.conversation);
|
||||||
string title = message.type_ == Message.Type.GROUPCHAT ? _("In %s").printf(display_name) : _("With %s").printf(display_name);
|
string title = item.message.type_ == Message.Type.GROUPCHAT ? _("In %s").printf(display_name) : _("With %s").printf(display_name);
|
||||||
Box header_box = new Box(Orientation.HORIZONTAL, 10) { margin_left=7, visible=true };
|
Box header_box = new Box(Orientation.HORIZONTAL, 10) { margin_left=7, visible=true };
|
||||||
header_box.add(new Label(@"<b>$(Markup.escape_text(title))</b>") { ellipsize=EllipsizeMode.END, xalign=0, use_markup=true, visible=true });
|
header_box.add(new Label(@"<b>$(Markup.escape_text(title))</b>") { ellipsize=EllipsizeMode.END, xalign=0, use_markup=true, visible=true });
|
||||||
header_box.add(date_label);
|
header_box.add(date_label);
|
||||||
|
@ -94,21 +108,12 @@ class GlobalSearch : Box {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workaround GTK TextView issues
|
private Widget get_match_message_widget(MessageItem item) {
|
||||||
private void force_alloc_width(Widget widget, int width) {
|
Grid grid = get_skeleton(item);
|
||||||
Allocation alloc = Allocation();
|
|
||||||
widget.get_preferred_width(out alloc.width, null);
|
|
||||||
widget.get_preferred_height(out alloc.height, null);
|
|
||||||
alloc.width = width;
|
|
||||||
widget.size_allocate(alloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Widget get_match_message_widget(Message message) {
|
|
||||||
Grid grid = get_skeleton(message);
|
|
||||||
grid.margin_top = 3;
|
grid.margin_top = 3;
|
||||||
grid.margin_bottom = 3;
|
grid.margin_bottom = 3;
|
||||||
|
|
||||||
string text = message.body.replace("\n", "").replace("\r", "");
|
string text = item.message.body.replace("\n", "").replace("\r", "");
|
||||||
if (text.length > 200) {
|
if (text.length > 200) {
|
||||||
int index = text.index_of(search);
|
int index = text.index_of(search);
|
||||||
if (index + search.length <= 100) {
|
if (index + search.length <= 100) {
|
||||||
|
@ -123,52 +128,68 @@ class GlobalSearch : Box {
|
||||||
tv.buffer.text = text;
|
tv.buffer.text = text;
|
||||||
TextTag link_tag = tv.buffer.create_tag("hit", background: "yellow");
|
TextTag link_tag = tv.buffer.create_tag("hit", background: "yellow");
|
||||||
|
|
||||||
Regex url_regex = new Regex(search.down());
|
Gee.List<string> keywords = get_keywords(Regex.escape_string(search.down()));
|
||||||
MatchInfo match_info;
|
foreach (string keyword in keywords) {
|
||||||
url_regex.match(text.down(), 0, out match_info);
|
Regex url_regex = new Regex(keyword.down());
|
||||||
for (; match_info.matches(); match_info.next()) {
|
MatchInfo match_info;
|
||||||
int start;
|
url_regex.match(text.down(), 0, out match_info);
|
||||||
int end;
|
for (; match_info.matches(); match_info.next()) {
|
||||||
match_info.fetch_pos(0, out start, out end);
|
int start;
|
||||||
start = text[0:start].char_count();
|
int end;
|
||||||
end = text[0:end].char_count();
|
match_info.fetch_pos(0, out start, out end);
|
||||||
TextIter start_iter;
|
start = text[0:start].char_count();
|
||||||
TextIter end_iter;
|
end = text[0:end].char_count();
|
||||||
tv.buffer.get_iter_at_offset(out start_iter, start);
|
TextIter start_iter;
|
||||||
tv.buffer.get_iter_at_offset(out end_iter, end);
|
TextIter end_iter;
|
||||||
tv.buffer.apply_tag(link_tag, start_iter, end_iter);
|
tv.buffer.get_iter_at_offset(out start_iter, start);
|
||||||
|
tv.buffer.get_iter_at_offset(out end_iter, end);
|
||||||
|
tv.buffer.apply_tag(link_tag, start_iter, end_iter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
grid.attach(tv, 1, 1, 1, 1);
|
grid.attach(tv, 1, 1, 1, 1);
|
||||||
|
|
||||||
// force_alloc_width(tv, this.width_request);
|
|
||||||
|
|
||||||
Button button = new Button() { relief=ReliefStyle.NONE, visible=true };
|
Button button = new Button() { relief=ReliefStyle.NONE, visible=true };
|
||||||
|
button.clicked.connect(() => {
|
||||||
|
selected_item(item);
|
||||||
|
});
|
||||||
button.add(grid);
|
button.add(grid);
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Grid get_context_message_widget(Message message) {
|
private Grid get_context_message_widget(MessageItem item) {
|
||||||
Grid grid = get_skeleton(message);
|
Grid grid = get_skeleton(item);
|
||||||
grid.margin_left = 7;
|
grid.margin_left = 7;
|
||||||
Label label = new Label(message.body.replace("\n", "").replace("\r", "")) { ellipsize=EllipsizeMode.MIDDLE, xalign=0, visible=true };
|
Label label = new Label(item.message.body.replace("\n", "").replace("\r", "")) { ellipsize=EllipsizeMode.MIDDLE, xalign=0, visible=true };
|
||||||
grid.attach(label, 1, 1, 1, 1);
|
grid.attach(label, 1, 1, 1, 1);
|
||||||
grid.opacity = 0.55;
|
grid.opacity = 0.55;
|
||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Grid get_skeleton(Message message) {
|
private Grid get_skeleton(MessageItem item) {
|
||||||
AvatarImage image = new AvatarImage() { height=32, width=32, margin_right=7, valign=Align.START, visible=true, allow_gray = false };
|
AvatarImage image = new AvatarImage() { height=32, width=32, margin_right=7, valign=Align.START, visible=true, allow_gray = false };
|
||||||
image.set_jid(stream_interactor, message.from, message.account);
|
image.set_jid(stream_interactor, item.jid, item.message.account);
|
||||||
Grid grid = new Grid() { row_homogeneous=false, visible=true };
|
Grid grid = new Grid() { row_homogeneous=false, visible=true };
|
||||||
grid.attach(image, 0, 0, 1, 2);
|
grid.attach(image, 0, 0, 1, 2);
|
||||||
|
|
||||||
string display_name = Util.get_display_name(stream_interactor, message.from, message.account);
|
string display_name = Util.get_display_name(stream_interactor, item.jid, item.message.account);
|
||||||
string color = Util.get_name_hex_color(stream_interactor, message.account, message.from, false); // TODO Util.is_dark_theme(name_label)
|
string color = Util.get_name_hex_color(stream_interactor, item.message.account, item.jid, false); // TODO Util.is_dark_theme(name_label)
|
||||||
Label name_label = new Label("") { use_markup=true, xalign=0, visible=true };
|
Label name_label = new Label("") { use_markup=true, xalign=0, visible=true };
|
||||||
name_label.label = @"<span size='small' foreground=\"#$color\">$display_name</span>";
|
name_label.label = @"<span size='small' foreground=\"#$color\">$display_name</span>";
|
||||||
grid.attach(name_label, 1, 0, 1, 1);
|
grid.attach(name_label, 1, 0, 1, 1);
|
||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Gee.List<string> get_keywords(string search_string) {
|
||||||
|
Gee.List<string> ret = new ArrayList<string>();
|
||||||
|
foreach (string search in search_string.split(" ")) {
|
||||||
|
bool is_filter = search.has_prefix("from:") || search.has_prefix("in:") || search.has_prefix("with:");
|
||||||
|
if (!is_filter && search != "") {
|
||||||
|
ret.add(search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,10 @@ public class UnifiedWindow : Window {
|
||||||
setup_unified();
|
setup_unified();
|
||||||
setup_stack();
|
setup_stack();
|
||||||
|
|
||||||
conversation_titlebar.search_button.bind_property("active", search_revealer, "reveal-child", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
|
|
||||||
|
conversation_titlebar.search_button.clicked.connect(() => {
|
||||||
|
search_revealer.reveal_child = conversation_titlebar.search_button.active;
|
||||||
|
});
|
||||||
search_revealer.notify["child-revealed"].connect(() => {
|
search_revealer.notify["child-revealed"].connect(() => {
|
||||||
if (search_revealer.child_revealed) {
|
if (search_revealer.child_revealed) {
|
||||||
if (conversation_frame.conversation != null) {
|
if (conversation_frame.conversation != null) {
|
||||||
|
@ -58,6 +61,10 @@ public class UnifiedWindow : Window {
|
||||||
search_box.search_entry.text = "";
|
search_box.search_entry.text = "";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
search_box.selected_item.connect((item) => {
|
||||||
|
on_conversation_selected(item.conversation, false, false);
|
||||||
|
conversation_frame.initialize_around_message(item.conversation, item);
|
||||||
|
});
|
||||||
|
|
||||||
paned.bind_property("position", headerbar_paned, "position", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
|
paned.bind_property("position", headerbar_paned, "position", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
|
||||||
|
|
||||||
|
@ -71,8 +78,8 @@ public class UnifiedWindow : Window {
|
||||||
accounts_placeholder.primary_button.clicked.connect(() => { get_application().activate_action("accounts", null); });
|
accounts_placeholder.primary_button.clicked.connect(() => { get_application().activate_action("accounts", null); });
|
||||||
conversations_placeholder.primary_button.clicked.connect(() => { get_application().activate_action("add_chat", null); });
|
conversations_placeholder.primary_button.clicked.connect(() => { get_application().activate_action("add_chat", null); });
|
||||||
conversations_placeholder.secondary_button.clicked.connect(() => { get_application().activate_action("add_conference", null); });
|
conversations_placeholder.secondary_button.clicked.connect(() => { get_application().activate_action("add_conference", null); });
|
||||||
filterable_conversation_list.conversation_list.conversation_selected.connect(on_conversation_selected);
|
filterable_conversation_list.conversation_list.conversation_selected.connect((conversation) => on_conversation_selected(conversation));
|
||||||
conversation_list_titlebar.conversation_opened.connect(on_conversation_selected);
|
conversation_list_titlebar.conversation_opened.connect((conversation) => on_conversation_selected(conversation));
|
||||||
|
|
||||||
check_stack();
|
check_stack();
|
||||||
}
|
}
|
||||||
|
@ -89,15 +96,21 @@ public class UnifiedWindow : Window {
|
||||||
search_revealer.valign = Align.FILL;
|
search_revealer.valign = Align.FILL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void on_conversation_selected(Conversation conversation) {
|
public void on_conversation_selected(Conversation conversation, bool close_search = true, bool default_initialize_conversation = true) {
|
||||||
if (this.conversation == null || !this.conversation.equals(conversation)) {
|
if (this.conversation == null || !this.conversation.equals(conversation)) {
|
||||||
this.conversation = conversation;
|
this.conversation = conversation;
|
||||||
stream_interactor.get_module(ChatInteraction.IDENTITY).on_conversation_selected(conversation);
|
stream_interactor.get_module(ChatInteraction.IDENTITY).on_conversation_selected(conversation);
|
||||||
conversation.active = true; // only for conversation_selected
|
conversation.active = true; // only for conversation_selected
|
||||||
filterable_conversation_list.conversation_list.on_conversation_selected(conversation); // only for conversation_opened
|
filterable_conversation_list.conversation_list.on_conversation_selected(conversation); // only for conversation_opened
|
||||||
|
|
||||||
|
if (close_search) {
|
||||||
|
conversation_titlebar.search_button.active = false;
|
||||||
|
search_revealer.reveal_child = false;
|
||||||
|
}
|
||||||
chat_input.initialize_for_conversation(conversation);
|
chat_input.initialize_for_conversation(conversation);
|
||||||
conversation_frame.initialize_for_conversation(conversation);
|
if (default_initialize_conversation) {
|
||||||
|
conversation_frame.initialize_for_conversation(conversation);
|
||||||
|
}
|
||||||
conversation_titlebar.initialize_for_conversation(conversation);
|
conversation_titlebar.initialize_for_conversation(conversation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,10 +118,6 @@ public static void force_background(Gtk.Widget widget, string color, string sele
|
||||||
force_css(widget, force_background_css.printf(selector, color));
|
force_css(widget, force_background_css.printf(selector, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void force_base_background(Gtk.Widget widget, string selector = "*") {
|
|
||||||
force_background(widget, "@theme_base_color", selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void force_color(Gtk.Widget widget, string color, string selector = "*") {
|
public static void force_color(Gtk.Widget widget, string color, string selector = "*") {
|
||||||
force_css(widget, force_color_css.printf(selector, color));
|
force_css(widget, force_color_css.printf(selector, color));
|
||||||
}
|
}
|
||||||
|
@ -142,4 +138,13 @@ public static bool is_24h_format() {
|
||||||
return settings_format == "24h" || p_format == " ";
|
return settings_format == "24h" || p_format == " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Workaround GTK TextView issues
|
||||||
|
public static void force_alloc_width(Widget widget, int width) {
|
||||||
|
Allocation alloc = Allocation();
|
||||||
|
widget.get_preferred_width(out alloc.width, null);
|
||||||
|
widget.get_preferred_height(out alloc.height, null);
|
||||||
|
alloc.width = width;
|
||||||
|
widget.size_allocate(alloc);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue