aboutsummaryrefslogtreecommitdiff
path: root/main/src
diff options
context:
space:
mode:
authorfrosty <frostinator33@airmail.cc>2026-10-27 12:35:27 -0400
committerfrosty <frostinator33@airmail.cc>2026-10-27 12:35:27 -0400
commitbff7a3a4a6512f48a7b58c2b20404e2d3173050e (patch)
tree44cff6c45b158251890c1e24dc0986c3a80021f5 /main/src
parentc7426c9fb97f1afdf2b33a055d977762af92c795 (diff)
feat: begin working on account switcherHEADmaster
Diffstat (limited to 'main/src')
-rw-r--r--main/src/ui/conversation_selector/account_switcher.vala252
-rw-r--r--main/src/ui/conversation_selector/conversation_selector.vala10
-rw-r--r--main/src/ui/main_window.vala5
3 files changed, 266 insertions, 1 deletions
diff --git a/main/src/ui/conversation_selector/account_switcher.vala b/main/src/ui/conversation_selector/account_switcher.vala
new file mode 100644
index 00000000..500fd96a
--- /dev/null
+++ b/main/src/ui/conversation_selector/account_switcher.vala
@@ -0,0 +1,252 @@
+using Gee;
+using Gdk;
+using Gtk;
+
+using Dino.Entities;
+
+namespace Dino.Ui {
+
+public class AccountSwitcher : Box {
+
+ public signal void account_filter_changed(Account? account);
+
+ public Account? selected_account { get; private set; default = null; }
+
+ private StreamInteractor stream_interactor;
+ private Box bars_box = new Box(Orientation.HORIZONTAL, 0);
+ private HashMap<Account, AccountColorBar> bars = new HashMap<Account, AccountColorBar>(Account.hash_func, Account.equals_func);
+ private AllAccountsBar? all_bar = null;
+ private ulong account_color_changed_handler_id = 0;
+
+ construct {
+ orientation = Orientation.HORIZONTAL;
+ add_css_class("dino-account-switcher");
+ bars_box.margin_start = 0;
+ bars_box.margin_end = 0;
+ bars_box.margin_top = 0;
+ bars_box.margin_bottom = 0;
+ bars_box.hexpand = true;
+ bars_box.halign = Align.FILL;
+ bars_box.add_css_class("dino-account-switcher-bars");
+ append(bars_box);
+ }
+
+ public AccountSwitcher init(StreamInteractor stream_interactor) {
+ this.stream_interactor = stream_interactor;
+
+ stream_interactor.account_added.connect(on_account_added);
+ stream_interactor.account_removed.connect(on_account_removed);
+ account_color_changed_handler_id = Dino.Application.get_default().settings.account_color_changed.connect(on_account_color_changed);
+
+ rebuild();
+
+ weak_ref((self_obj) => {
+ AccountSwitcher self = (AccountSwitcher) self_obj;
+ self.stream_interactor.account_added.disconnect(self.on_account_added);
+ self.stream_interactor.account_removed.disconnect(self.on_account_removed);
+ if (self.account_color_changed_handler_id != 0) {
+ Dino.Application.get_default().settings.disconnect(self.account_color_changed_handler_id);
+ self.account_color_changed_handler_id = 0;
+ }
+ });
+
+ return this;
+ }
+
+ private void rebuild() {
+ Widget? child = bars_box.get_first_child();
+ while (child != null) {
+ Widget? next = child.get_next_sibling();
+ bars_box.remove(child);
+ child = next;
+ }
+ bars.clear();
+
+ Gee.List<Account> accounts = stream_interactor.get_accounts();
+ all_bar = new AllAccountsBar(accounts);
+ all_bar.clicked.connect(on_all_clicked);
+ bars_box.append(all_bar);
+
+ foreach (Account account in accounts) {
+ add_account(account);
+ }
+
+ if (selected_account != null && !bars.has_key(selected_account)) {
+ selected_account = null;
+ account_filter_changed(null);
+ }
+
+ update_selection();
+ }
+
+ private void on_account_added(Account account) {
+ if (bars.has_key(account)) return;
+ add_account(account);
+ if (all_bar != null) all_bar.set_accounts(stream_interactor.get_accounts());
+ update_selection();
+ }
+
+ private void on_account_removed(Account account) {
+ if (bars.has_key(account)) {
+ AccountColorBar bar = bars[account];
+ bars.unset(account);
+ bars_box.remove(bar);
+ }
+
+ if (all_bar != null) all_bar.set_accounts(stream_interactor.get_accounts());
+
+ if (selected_account != null && selected_account.equals(account)) {
+ selected_account = null;
+ update_selection();
+ account_filter_changed(null);
+ }
+ }
+
+ private void add_account(Account account) {
+ AccountColorBar bar = new AccountColorBar(account);
+ bar.clicked.connect(() => on_bar_clicked(account));
+ bars_box.append(bar);
+ bars[account] = bar;
+ }
+
+ private void on_all_clicked() {
+ if (selected_account == null) return;
+
+ selected_account = null;
+ update_selection();
+ account_filter_changed(null);
+ }
+
+ private void on_bar_clicked(Account account) {
+ if (selected_account != null && selected_account.equals(account)) {
+ selected_account = null;
+ } else {
+ selected_account = account;
+ }
+
+ update_selection();
+ account_filter_changed(selected_account);
+ }
+
+ private void update_selection() {
+ if (all_bar != null) {
+ all_bar.set_active(selected_account == null);
+ }
+ foreach (var entry in bars.entries) {
+ entry.value.set_active(selected_account != null && entry.key.equals(selected_account));
+ }
+ }
+
+ private void on_account_color_changed(Account account, string color) {
+ if (bars.has_key(account)) {
+ bars[account].redraw();
+ }
+ if (all_bar != null) {
+ all_bar.redraw();
+ }
+ }
+}
+
+private class AccountColorBar : Button {
+
+ public Account account { get; private set; }
+
+ private DrawingArea drawing_area = new DrawingArea() { hexpand=true, vexpand=true };
+ private double bar_opacity = 1.0;
+
+ public AccountColorBar(Account account) {
+ this.account = account;
+
+ add_css_class("flat");
+ add_css_class("dino-account-color-bar");
+ hexpand = true;
+ set_child(drawing_area);
+ drawing_area.set_draw_func(draw);
+
+ set_tooltip_text(account.display_name);
+ }
+
+ public void set_active(bool active) {
+ bar_opacity = active ? 1.0 : 0.4;
+ redraw();
+ }
+
+ public void redraw() {
+ drawing_area.queue_draw();
+ }
+
+ private void draw(DrawingArea area, Cairo.Context context, int width, int height) {
+ RGBA color = RGBA();
+ if (!color.parse(Dino.Application.get_default().settings.get_account_color(account))) return;
+
+ color.alpha = (float) (color.alpha * bar_opacity);
+ Gdk.cairo_set_source_rgba(context, color);
+ context.rectangle(0, 0, width, height);
+ context.fill();
+ }
+}
+
+private class AllAccountsBar : Button {
+
+ private Gee.List<Account>? accounts = null;
+ private DrawingArea drawing_area = new DrawingArea() { hexpand=true, vexpand=true };
+
+ public AllAccountsBar(Gee.List<Account> accounts) {
+ this.accounts = accounts;
+
+ add_css_class("flat");
+ add_css_class("dino-account-color-bar");
+ add_css_class("dino-account-all-bar");
+ set_child(drawing_area);
+ drawing_area.set_draw_func(draw);
+ set_tooltip_text(_("All conversations"));
+ }
+
+ public void set_accounts(Gee.List<Account> accounts) {
+ this.accounts = accounts;
+ redraw();
+ }
+
+ public void redraw() {
+ drawing_area.queue_draw();
+ }
+
+ public void set_active(bool active) {
+ if (active) {
+ remove_css_class("dimmed");
+ } else {
+ add_css_class("dimmed");
+ }
+ }
+
+ private void draw(DrawingArea area, Cairo.Context context, int width, int height) {
+ if (accounts == null || accounts.size == 0) {
+ context.set_source_rgba(0.5, 0.5, 0.5, 0.3);
+ context.rectangle(0, 0, width, height);
+ context.fill();
+ return;
+ }
+
+ if (accounts.size == 1) {
+ RGBA color = RGBA();
+ if (!color.parse(Dino.Application.get_default().settings.get_account_color(accounts[0]))) return;
+ Gdk.cairo_set_source_rgba(context, color);
+ context.rectangle(0, 0, width, height);
+ context.fill();
+ return;
+ }
+
+ Cairo.Pattern gradient = new Cairo.Pattern.linear(0, 0, width, 0);
+ for (int i = 0; i < accounts.size; i++) {
+ RGBA color = RGBA();
+ if (!color.parse(Dino.Application.get_default().settings.get_account_color(accounts[i]))) continue;
+ gradient.add_color_stop_rgba((double) i / (accounts.size - 1), color.red, color.green, color.blue, color.alpha);
+ }
+
+ context.set_source(gradient);
+ context.rectangle(0, 0, width, height);
+ context.fill();
+ }
+}
+
+}
diff --git a/main/src/ui/conversation_selector/conversation_selector.vala b/main/src/ui/conversation_selector/conversation_selector.vala
index 25ea1b1e..c087cde0 100644
--- a/main/src/ui/conversation_selector/conversation_selector.vala
+++ b/main/src/ui/conversation_selector/conversation_selector.vala
@@ -15,6 +15,7 @@ public class ConversationSelector : Widget {
private StreamInteractor stream_interactor;
private string search_text = "";
+ private Account? account_filter = null;
private HashMap<Conversation, ConversationSelectorRow> rows = new HashMap<Conversation, ConversationSelectorRow>(Conversation.hash_func, Conversation.equals_func);
public ConversationSelector init(StreamInteractor stream_interactor) {
@@ -60,9 +61,16 @@ public class ConversationSelector : Widget {
list_box.invalidate_filter();
}
+ public void set_account_filter(Account? account) {
+ account_filter = account;
+ list_box.invalidate_filter();
+ }
+
private bool filter(ListBoxRow list_box_row) {
ConversationSelectorRow? row = list_box_row as ConversationSelectorRow;
- return row != null && (search_text == "" || row.matches_search(search_text));
+ if (row == null) return false;
+ if (account_filter != null && !row.conversation.account.equals(account_filter)) return false;
+ return search_text == "" || row.matches_search(search_text);
}
public void row_activated(ListBoxRow r) {
diff --git a/main/src/ui/main_window.vala b/main/src/ui/main_window.vala
index fc18d2bd..4a20f41d 100644
--- a/main/src/ui/main_window.vala
+++ b/main/src/ui/main_window.vala
@@ -17,6 +17,7 @@ public class MainWindow : Gtk.ApplicationWindow {
[GtkChild] public unowned SearchEntry conversation_search_entry;
[GtkChild] public unowned MenuButton menu_button;
[GtkChild] private unowned Box conversation_list_toolbar;
+ [GtkChild] public unowned AccountSwitcher account_switcher;
[GtkChild] public unowned Adw.HeaderBar conversation_headerbar;
[GtkChild] public unowned Button conversation_title_button;
@@ -72,6 +73,10 @@ public class MainWindow : Gtk.ApplicationWindow {
conversation_search_entry.stop_search.connect(() => {
conversation_search_entry.text = "";
});
+ account_switcher.init(stream_interactor);
+ account_switcher.account_filter_changed.connect((account) => {
+ conversation_selector.set_account_filter(account);
+ });
global_search = new GlobalSearch(stream_interactor);
search_frame.set_child(global_search.get_widget());