Drop Granite.ModeButton

This commit is contained in:
Bleak Grey 2020-05-31 13:28:35 +03:00
parent c9836034c0
commit 024a870228
12 changed files with 135 additions and 159 deletions

View File

@ -1,16 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<!-- Generated with glade 3.36.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<requires lib="libhandy" version="0.0"/>
<template class="TootleDialogsMainWindow" parent="GtkWindow">
<property name="width_request">450</property>
<property name="height_request">600</property>
<property name="can_focus">False</property>
<child>
<object class="GtkStack" id="view_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">slide-left-right</property>
<child>
<object class="GtkStack" id="timeline_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">slide-left-right</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">0</property>
<property name="title" translatable="yes">0</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="show_close_button">True</property>
<child type="title">
<object class="HdyViewSwitcher" id="timeline_switcher">
<property name="visible">True</property>
</object>
</child>
<child>
<object class="GtkButton" id="back_button">
<property name="can_focus">True</property>
@ -41,11 +68,6 @@
<property name="position">1</property>
</packing>
</child>
<child type="title">
<object class="GraniteWidgetsModeButton" id="timeline_switcher">
<property name="visible">True</property>
</object>
</child>
<child>
<object class="TootleWidgetsAccountsButton" id="accounts_button">
<property name="visible">True</property>
@ -57,26 +79,5 @@
</child>
</object>
</child>
<child>
<object class="GtkStack" id="view_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">slide-left-right</property>
<child>
<object class="GtkStack" id="timeline_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">slide-left-right</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">0</property>
<property name="title" translatable="yes">0</property>
</packing>
</child>
</object>
</child>
</template>
</interface>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<!-- Generated with glade 3.36.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkPopover" id="popover">

View File

@ -138,9 +138,9 @@ namespace Tootle {
refresh ();
}
private void switch_timeline_activated (SimpleAction a, Variant? parameter) {
int32 timeline_no = parameter.get_int32 ();
window.switch_timeline (timeline_no);
private void switch_timeline_activated (SimpleAction a, Variant? v) {
int32 num = v.get_int32 ();
window.switch_timeline (num);
}
}

View File

@ -58,7 +58,7 @@ public class Tootle.Desktop {
}
info ("OK");
cb (file_path);
} catch (Error e) {
warning ("Error: %s\n", e.message);
ecb (0, e.message);
@ -68,9 +68,12 @@ public class Tootle.Desktop {
.exec ();
}
public static string fallback_icon (string normal, string fallback) {
public static string fallback_icon (string normal, string fallback, string fallback2 = "broken") {
var theme = Gtk.IconTheme.get_default ();
return theme.has_icon (normal) ? normal : fallback;
if (theme.has_icon (normal))
return normal;
else
return theme.has_icon (fallback) ? fallback : fallback2;
}
public static void set_hotkey_tooltip (Gtk.Widget widget, string? description, string[] accelerators) {

View File

@ -16,9 +16,11 @@ public class Tootle.Dialogs.MainWindow: Gtk.Window, ISavedWindow {
[GtkChild]
protected Button compose_button;
[GtkChild]
protected Granite.Widgets.ModeButton timeline_switcher;
protected Hdy.ViewSwitcher timeline_switcher;
[GtkChild]
protected Widgets.AccountsButton accounts_button;
Views.Base? last_view = null;
construct {
var provider = new Gtk.CssProvider ();
@ -31,13 +33,14 @@ public class Tootle.Dialogs.MainWindow: Gtk.Window, ISavedWindow {
compose_button.clicked.connect (() => new Dialogs.Compose ());
Desktop.set_hotkey_tooltip (compose_button, _("Compose"), app.ACCEL_NEW_POST);
timeline_switcher.mode_changed.connect (on_mode_changed);
timeline_switcher.stack = timeline_stack;
timeline_switcher.valign = Align.FILL;
timeline_stack.notify["visible-child"].connect (on_timeline_changed);
add_header_view (new Views.Home (), app.ACCEL_TIMELINE_0, 0);
add_header_view (new Views.Notifications (), app.ACCEL_TIMELINE_1, 1);
add_header_view (new Views.Local (), app.ACCEL_TIMELINE_2, 2);
add_header_view (new Views.Federated (), app.ACCEL_TIMELINE_3, 3);
timeline_switcher.set_active (0);
add_timeline_view (new Views.Home (), app.ACCEL_TIMELINE_0, 0);
add_timeline_view (new Views.Notifications (), app.ACCEL_TIMELINE_1, 1);
add_timeline_view (new Views.Local (), app.ACCEL_TIMELINE_2, 2);
add_timeline_view (new Views.Federated (), app.ACCEL_TIMELINE_3, 3);
button_press_event.connect (on_button_press);
settings.changed.connect (update_theme);
@ -47,25 +50,17 @@ public class Tootle.Dialogs.MainWindow: Gtk.Window, ISavedWindow {
}
public MainWindow (Gtk.Application app) {
Object (application: app, icon_name: Build.DOMAIN, resizable: true, window_position: WindowPosition.CENTER);
Object (
application: app,
icon_name: Build.DOMAIN,
resizable: true,
window_position: WindowPosition.CENTER
);
if (accounts.is_empty ())
open_view (new Views.NewAccount (false));
}
private bool on_button_press (EventButton ev) {
if (ev.button == 8)
return back ();
return false;
}
private void add_header_view (Views.Base view, string[] accelerators, int32 num) {
var img = new Image.from_icon_name (view.get_icon (), IconSize.LARGE_TOOLBAR);
Desktop.set_hotkey_tooltip (img, view.get_name (), accelerators);
timeline_switcher.append (img);
view.image = img;
timeline_stack.add_named (view, num.to_string ());
}
public int get_visible_id () {
return int.parse (view_stack.get_visible_child_name ());
}
@ -110,15 +105,29 @@ public class Tootle.Dialogs.MainWindow: Gtk.Window, ISavedWindow {
return false;
}
public void switch_timeline (int32 timeline_no) {
timeline_switcher.set_active (timeline_no);
public void switch_timeline (int32 num) {
timeline_stack.visible_child_name = num.to_string ();
}
private void update_theme () {
bool on_button_press (EventButton ev) {
if (ev.button == 8)
return back ();
return false;
}
void add_timeline_view (Views.Base view, string[] accelerators, int32 num) {
timeline_stack.add_titled (view, num.to_string (), view.label);
timeline_stack.child_set_property (view, "icon-name", view.icon);
view.notify["needs-attention"].connect (() => {
timeline_stack.child_set_property (view, "needs-attention", view.needs_attention);
});
}
void update_theme () {
Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = settings.dark_theme;
}
private void update_header () {
void update_header () {
bool primary_mode = get_visible_id () == 0;
timeline_switcher.sensitive = primary_mode;
timeline_switcher.opacity = primary_mode ? 1 : 0; //Prevent HeaderBar height jitter
@ -126,15 +135,16 @@ public class Tootle.Dialogs.MainWindow: Gtk.Window, ISavedWindow {
back_button.visible = !primary_mode;
}
private void on_mode_changed (Widget widget) {
var visible = timeline_stack.get_visible_child () as Views.Base;
visible.current = false;
void on_timeline_changed (ParamSpec spec) {
var view = timeline_stack.visible_child as Views.Base;
timeline_stack.set_visible_child_name (timeline_switcher.selected.to_string ());
if (last_view != null)
last_view.current = false;
visible = timeline_stack.get_visible_child () as Views.Base;
visible.current = true;
visible.on_set_current ();
if (view != null) {
view.current = true;
last_view = view;
}
}
}

View File

@ -6,9 +6,11 @@ public class Tootle.Views.Base : Box {
public static string STATUS_EMPTY = _("Nothing to see here");
public static string STATUS_LOADING = " ";
public bool current = false;
public int stack_pos = -1;
public Image? image;
public int stack_pos { get; set; default = -1; }
public string? icon { get; set; default = null; }
public string label { get; set; default = ""; }
public bool needs_attention { get; set; default = false; }
public bool current { get; set; default = false; }
[GtkChild]
protected ScrolledWindow scrolled;
@ -19,11 +21,11 @@ public class Tootle.Views.Base : Box {
[GtkChild]
protected Box content;
[GtkChild]
private Label status_message_label;
[GtkChild]
protected Button status_button;
[GtkChild]
private Stack status_stack;
Stack status_stack;
[GtkChild]
Label status_message_label;
public string state { get; set; default = "status"; }
public string status_message { get; set; default = STATUS_EMPTY; }
@ -48,14 +50,13 @@ public class Tootle.Views.Base : Box {
status_message_label.label = @"<span size='large'>$status_message</span>";
status_stack.visible_child_name = status_message == STATUS_LOADING ? "spinner" : "message";
});
}
public virtual string get_icon () {
return "null";
}
public virtual string get_name () {
return "unnamed";
notify["current"].connect (() => {
if (current)
on_shown ();
else
on_hidden ();
});
}
public virtual void clear (){
@ -66,7 +67,8 @@ public class Tootle.Views.Base : Box {
}
public virtual void on_bottom_reached () {}
public virtual void on_set_current () {}
public virtual void on_shown () {}
public virtual void on_hidden () {}
public virtual void on_content_changed () {
if (empty) {

View File

@ -1,15 +1,11 @@
public class Tootle.Views.Direct : Views.Timeline {
public Direct () {
Object (timeline: "direct");
}
public override string get_icon () {
return "mail-send-symbolic";
}
public override string get_name () {
return _("Direct Messages");
Object (
timeline: "direct",
label: _("Direct Messages"),
icon: "mail-send-symbolic"
);
}
public override string? get_stream_url () {

View File

@ -1,15 +1,12 @@
public class Tootle.Views.Federated : Views.Timeline {
public Federated () {
Object (timeline: "public", is_public: true);
}
public override string get_icon () {
return "network-workgroup-symbolic";
}
public override string get_name () {
return _("Federated Timeline");
Object (
timeline: "public",
is_public: true,
label: _("Federated"),
icon: "network-workgroup-symbolic"
);
}
public override string? get_stream_url () {

View File

@ -1,15 +1,11 @@
public class Tootle.Views.Home : Views.Timeline {
public Home () {
Object (timeline: "home");
}
public override string get_icon () {
return "user-home-symbolic";
}
public override string get_name () {
return _("Home");
Object (
timeline: "home",
label: _("Home"),
icon: "user-home-symbolic"
);
}
public override string? get_stream_url () {

View File

@ -1,11 +1,8 @@
public class Tootle.Views.Local : Views.Federated {
public override string get_icon () {
return Desktop.fallback_icon ("system-users-symbolic", "document-open-recent-symbolic");
}
public override string get_name () {
return _("Local Timeline");
public Local () {
label = _("Local");
icon = Desktop.fallback_icon ("system-users-symbolic", "document-open-recent-symbolic");
}
public override Request append_params (Request req) {

View File

@ -4,30 +4,15 @@ using Gdk;
public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStreamListener {
protected int64 last_id = 0;
protected bool force_dot = false;
public Notifications () {
Object ();
Object (
label: _("Notifications"),
icon: Desktop.fallback_icon ("notification-symbolic", "preferences-system-notifications-symbolic", "user-invisible-symbolic")
);
on_notification.connect (add_notification);
}
public bool has_unread () {
if (account == null)
return false;
return last_id > account.last_seen_notification || force_dot;
}
public override string get_icon () {
if (has_unread ())
return Desktop.fallback_icon ("notification-new-symbolic", "user-available-symbolic");
else
return Desktop.fallback_icon ("notification-symbolic", "user-invisible-symbolic");
}
public override string get_name () {
return _("Notifications");
}
public override string? get_stream_url () {
return account != null ? @"$(account.instance)/api/v1/streaming/?stream=user&access_token=$(account.token)" : null;
}
@ -39,19 +24,12 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr
return "/api/v1/notifications";
}
public override void on_content_changed () {
base.on_content_changed ();
if (image != null && empty)
image.icon_name = get_icon ();
}
public override void on_set_current () {
public override void on_shown () {
if (has_unread ()) {
force_dot = false;
account.has_unread_notifications = force_dot;
needs_attention = false;
account.has_unread_notifications = false;
account.last_seen_notification = last_id;
accounts.save ();
image.icon_name = get_icon ();
}
}
@ -61,17 +39,15 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr
var notification = nw.notification;
if (reverse && !current) {
force_dot = true;
accounts.active.has_unread_notifications = force_dot;
needs_attention = accounts.active.has_unread_notifications = true;
}
if (notification.id > last_id)
last_id = notification.id;
if (has_unread ()) {
needs_attention = has_unread ();
if (needs_attention)
accounts.save ();
image.icon_name = get_icon ();
}
}
public override GLib.Object? to_entity (Json.Object? json) {
@ -94,11 +70,11 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr
base.on_account_changed (acc);
if (account == null) {
last_id = 0;
force_dot = false;
needs_attention = false;
}
else {
last_id = account.last_seen_notification;
force_dot = account.has_unread_notifications;
needs_attention = account.has_unread_notifications;
}
}
@ -112,7 +88,13 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr
return base.request ();
}
protected virtual void add_notification (API.Notification n) {
bool has_unread () {
if (account == null)
return false;
return last_id > account.last_seen_notification || needs_attention;
}
void add_notification (API.Notification n) {
prepend (widgetize (n));
}

View File

@ -25,14 +25,6 @@ public class Tootle.Views.Timeline : IAccountListener, IStreamListener, Views.Ba
streams.unsubscribe (stream, this);
}
public override string get_icon () {
return "user-home-symbolic";
}
public override string get_name () {
return _("Home");
}
public virtual bool is_status_owned (API.Status status) {
return status.is_owned ();
}