From bff7a3a4a6512f48a7b58c2b20404e2d3173050e Mon Sep 17 00:00:00 2001 From: frosty Date: Tue, 27 Oct 2026 12:35:27 -0400 Subject: feat: begin working on account switcher --- .../ui/conversation_selector/account_switcher.vala | 252 +++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 main/src/ui/conversation_selector/account_switcher.vala (limited to 'main/src/ui/conversation_selector/account_switcher.vala') 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 bars = new HashMap(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 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? accounts = null; + private DrawingArea drawing_area = new DrawingArea() { hexpand=true, vexpand=true }; + + public AllAccountsBar(Gee.List 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 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(); + } +} + +} -- cgit v1.3