diff --git a/data/com.github.bleakgrey.tootle.gschema.xml b/data/com.github.bleakgrey.tootle.gschema.xml
index 9fec02d..518cfc4 100644
--- a/data/com.github.bleakgrey.tootle.gschema.xml
+++ b/data/com.github.bleakgrey.tootle.gschema.xml
@@ -28,8 +28,13 @@
true
- Update timelines in real-time
-
+ Real-time timelines
+ Update timelines in real-time
+
+
+ false
+ Real-time public timelines
+ Update local and federated timelines in real-time. May clog up memory on busy instances.
false
@@ -39,7 +44,7 @@
500
Default character limit
- Change this if your instance supports more than 500 characters in post
+ Change this if your instance supports more than 500 characters in posts
diff --git a/meson.build b/meson.build
index 62bf5fe..68a2069 100644
--- a/meson.build
+++ b/meson.build
@@ -51,6 +51,7 @@ executable(
'src/Dialogs/SettingsDialog.vala',
'src/Views/AbstractView.vala',
'src/Views/TimelineView.vala',
+ 'src/Views/HomeView.vala',
'src/Views/LocalView.vala',
'src/Views/FederatedView.vala',
'src/Views/NotificationsView.vala',
diff --git a/src/Dialogs/SettingsDialog.vala b/src/Dialogs/SettingsDialog.vala
index 302ffcf..254c2a3 100644
--- a/src/Dialogs/SettingsDialog.vala
+++ b/src/Dialogs/SettingsDialog.vala
@@ -7,27 +7,42 @@ public class Tootle.SettingsDialog : Gtk.Dialog {
private SettingsSwitch switch_notifications;
private SettingsSwitch switch_watcher;
+ private SettingsSwitch switch_stream;
+ private SettingsSwitch switch_stream_public;
private Gtk.Grid grid;
public SettingsDialog () {
- Object (
- border_width: 6,
- deletable: false,
- resizable: false,
- title: _("Settings"),
- transient_for: Tootle.window
- );
+ border_width = 6;
+ deletable = false;
+ resizable = false;
+ title = _("Settings");
+ transient_for = Tootle.window;
int i = 0;
grid = new Gtk.Grid ();
+ switch_watcher = new SettingsSwitch ("always-online");
+ switch_notifications = new SettingsSwitch ("notifications");
+ switch_notifications.state_set.connect (state => {
+ switch_watcher.sensitive = state;
+ return false;
+ });
+ switch_stream = new SettingsSwitch ("live-updates");
+ switch_stream_public = new SettingsSwitch ("live-updates-public");
+ switch_stream.state_set.connect (state => {
+ switch_stream_public.sensitive = state;
+ return false;
+ });
+
grid.attach (new Granite.HeaderLabel (_("Appearance")), 0, i++, 2, 1);
grid.attach (new SettingsLabel (_("Dark theme:")), 0, i);
grid.attach (new SettingsSwitch ("dark-theme"), 1, i++);
grid.attach (new Granite.HeaderLabel (_("Timelines")), 0, i++, 2, 1);
grid.attach (new SettingsLabel (_("Real-time updates:")), 0, i);
- grid.attach (new SettingsSwitch ("live-updates"), 1, i++);
+ grid.attach (switch_stream, 1, i++);
+ grid.attach (new SettingsLabel (_("Update public timelines:")), 0, i);
+ grid.attach (switch_stream_public, 1, i++);
// grid.attach (new Granite.HeaderLabel (_("Caching")), 0, i++, 2, 1);
// grid.attach (new SettingsLabel (_("Use cache:")), 0, i);
@@ -37,13 +52,6 @@ public class Tootle.SettingsDialog : Gtk.Dialog {
// settings.schema.bind ("cache-size", cache_size, "value", SettingsBindFlags.DEFAULT);
// grid.attach (cache_size, 1, i++);
- switch_watcher = new SettingsSwitch ("always-online");
- switch_notifications = new SettingsSwitch ("notifications");
- switch_notifications.state_set.connect (state => {
- switch_watcher.sensitive = state;
- return false;
- });
-
grid.attach (new Granite.HeaderLabel (_("Notifications")), 0, i++, 2, 1);
grid.attach (new SettingsLabel (_("Display notifications:")), 0, i);
grid.attach (switch_notifications, 1, i++);
diff --git a/src/InstanceAccount.vala b/src/InstanceAccount.vala
index 1b46f2b..b00ade1 100644
--- a/src/InstanceAccount.vala
+++ b/src/InstanceAccount.vala
@@ -23,16 +23,14 @@ public class Tootle.InstanceAccount : GLib.Object {
notificator.close ();
notificator = new Notificator (get_stream ());
- notificator.status_added.connect (status_added);
notificator.status_removed.connect (status_removed);
notificator.notification.connect (notification);
notificator.start ();
}
- private Soup.Message get_stream () {
+ public Soup.Message get_stream () {
var url = "%s/api/v1/streaming/?stream=user&access_token=%s".printf (instance, token);
- var msg = new Soup.Message("GET", url);
- return msg;
+ return new Soup.Message ("GET", url);
}
public void close_notificator () {
@@ -87,21 +85,8 @@ public class Tootle.InstanceAccount : GLib.Object {
network.notification (ref obj);
}
- private void status_added (ref Status status) {
- if (accounts.formal.token != this.token)
- return;
-
- if (settings.live_updates)
- network.status_added (ref status, "home");
- else
- app.toast (_("New toot available"));
- }
-
private void status_removed (int64 id) {
- if (accounts.formal.token != this.token)
- return;
-
- if (settings.live_updates)
+ if (accounts.formal.token == this.token)
network.status_removed (id);
}
diff --git a/src/MainWindow.vala b/src/MainWindow.vala
index 1982f3b..746a200 100644
--- a/src/MainWindow.vala
+++ b/src/MainWindow.vala
@@ -2,18 +2,23 @@ using Gtk;
public class Tootle.MainWindow: Gtk.Window {
- private Gtk.Overlay overlay;
+ private Overlay overlay;
private Granite.Widgets.Toast toast;
- private Gtk.Grid grid;
+ private Grid grid;
private Stack primary_stack;
private Stack secondary_stack;
- public Gtk.HeaderBar header;
+ public HeaderBar header;
private Granite.Widgets.ModeButton button_mode;
private AccountsButton button_accounts;
private Spinner spinner;
private Button button_toot;
private Button button_back;
+
+ public HomeView home = new HomeView ();
+ public NotificationsView notifications = new NotificationsView ();
+ public LocalView local = new LocalView ();
+ public FederatedView federated = new FederatedView ();
construct {
var provider = new Gtk.CssProvider ();
@@ -67,10 +72,10 @@ public class Tootle.MainWindow: Gtk.Window {
grid = new Gtk.Grid ();
grid.attach (primary_stack, 0, 0, 1, 1);
- add_header_view (new TimelineView ("home"));
- add_header_view (new NotificationsView ());
- add_header_view (new LocalView ());
- add_header_view (new FederatedView ());
+ add_header_view (home);
+ add_header_view (notifications);
+ add_header_view (local);
+ add_header_view (federated);
button_mode.set_active (0);
toast = new Granite.Widgets.Toast ("");
diff --git a/src/NetManager.vala b/src/NetManager.vala
index 67e8558..0efc14f 100644
--- a/src/NetManager.vala
+++ b/src/NetManager.vala
@@ -9,7 +9,6 @@ public class Tootle.NetManager : GLib.Object {
public abstract signal void finished ();
public abstract signal void notification (ref Notification notification);
- public abstract signal void status_added (ref Status status, string timeline);
public abstract signal void status_removed (int64 id);
private int requests_processing = 0;
diff --git a/src/Notificator.vala b/src/Notificator.vala
index 4262b6a..0c62e68 100644
--- a/src/Notificator.vala
+++ b/src/Notificator.vala
@@ -67,10 +67,16 @@ public class Tootle.Notificator : GLib.Object {
var type = root.get_string_member ("event");
switch (type) {
case "update":
+ if (!settings.live_updates)
+ return;
+
var status = Status.parse (sanitize (root));
status_added (ref status);
break;
case "delete":
+ if (!settings.live_updates)
+ return;
+
var id = int64.parse (root.get_string_member("payload"));
status_removed (id);
break;
diff --git a/src/SettingsManager.vala b/src/SettingsManager.vala
index e01351d..14ce15d 100644
--- a/src/SettingsManager.vala
+++ b/src/SettingsManager.vala
@@ -7,6 +7,7 @@ public class Tootle.SettingsManager : Granite.Services.Settings {
public int cache_size { get; set; }
public int char_limit { get; set; }
public bool live_updates { get; set; }
+ public bool live_updates_public { get; set; }
public bool dark_theme { get; set; }
public SettingsManager () {
diff --git a/src/Views/FavoritesView.vala b/src/Views/FavoritesView.vala
index 1faf718..8f03e6c 100644
--- a/src/Views/FavoritesView.vala
+++ b/src/Views/FavoritesView.vala
@@ -1,5 +1,3 @@
-using Gtk;
-
public class Tootle.FavoritesView : TimelineView {
public FavoritesView () {
@@ -10,7 +8,7 @@ public class Tootle.FavoritesView : TimelineView {
if (page_next != null)
return page_next;
- var url = "%s/api/v1/favourites/?limit=%i".printf (Tootle.accounts.formal.instance, this.limit);
+ var url = "%s/api/v1/favourites/?limit=%i".printf (accounts.formal.instance, this.limit);
return url;
}
diff --git a/src/Views/FederatedView.vala b/src/Views/FederatedView.vala
index 98dcd6f..73ac0fa 100644
--- a/src/Views/FederatedView.vala
+++ b/src/Views/FederatedView.vala
@@ -1,9 +1,12 @@
-using Gtk;
-
public class Tootle.FederatedView : TimelineView {
public FederatedView () {
base ("public");
+ notificator = new Notificator (get_stream ());
+ notificator.status_added.connect ((ref status) => {
+ if (settings.live_updates_public)
+ on_status_added (ref status);
+ });
}
public override string get_icon () {
@@ -13,5 +16,10 @@ public class Tootle.FederatedView : TimelineView {
public override string get_name () {
return _("Federated Timeline");
}
+
+ protected Soup.Message get_stream () {
+ var url = "%s/api/v1/streaming/?stream=public&access_token=%s".printf (accounts.formal.instance, accounts.formal.token);
+ return new Soup.Message("GET", url);
+ }
}
diff --git a/src/Views/FollowersView.vala b/src/Views/FollowersView.vala
index cb5105a..6d5f98f 100644
--- a/src/Views/FollowersView.vala
+++ b/src/Views/FollowersView.vala
@@ -23,7 +23,7 @@ public class Tootle.FollowersView : TimelineView {
if (page_next != null)
return page_next;
- var url = "%s/api/v1/accounts/%s/followers".printf (Tootle.accounts.formal.instance, this.timeline);
+ var url = "%s/api/v1/accounts/%s/followers".printf (accounts.formal.instance, this.timeline);
return url;
}
diff --git a/src/Views/FollowingView.vala b/src/Views/FollowingView.vala
index 38503f1..c11f473 100644
--- a/src/Views/FollowingView.vala
+++ b/src/Views/FollowingView.vala
@@ -1,5 +1,3 @@
-using Gtk;
-
public class Tootle.FollowingView : FollowersView {
public FollowingView (ref Account account) {
@@ -11,7 +9,7 @@ public class Tootle.FollowingView : FollowersView {
if (page_next != null)
return page_next;
- var url = "%s/api/v1/accounts/%s/following".printf (Tootle.accounts.formal.instance, this.timeline);
+ var url = "%s/api/v1/accounts/%s/following".printf (accounts.formal.instance, this.timeline);
return url;
}
diff --git a/src/Views/HomeView.vala b/src/Views/HomeView.vala
new file mode 100644
index 0000000..5ca85fa
--- /dev/null
+++ b/src/Views/HomeView.vala
@@ -0,0 +1,20 @@
+public class Tootle.HomeView : TimelineView {
+
+ public HomeView () {
+ base ("home");
+ notificator = new Notificator (accounts.formal.get_stream ());
+ notificator.status_added.connect ((ref status) => {
+ if (settings.live_updates)
+ on_status_added (ref status);
+ });
+ }
+
+ public override string get_icon () {
+ return "user-home-symbolic";
+ }
+
+ public override string get_name () {
+ return _("Home");
+ }
+
+}
diff --git a/src/Views/LocalView.vala b/src/Views/LocalView.vala
index 13ce9fa..6274055 100644
--- a/src/Views/LocalView.vala
+++ b/src/Views/LocalView.vala
@@ -1,9 +1,12 @@
-using Gtk;
-
public class Tootle.LocalView : TimelineView {
public LocalView () {
base ("public");
+ notificator = new Notificator (get_stream ());
+ notificator.status_added.connect ((ref status) => {
+ if (settings.live_updates_public)
+ on_status_added (ref status);
+ });
}
public override string get_icon () {
@@ -15,9 +18,14 @@ public class Tootle.LocalView : TimelineView {
}
public override string get_url (){
- string url = base.get_url ();
+ var url = base.get_url ();
url += "&local=true";
return url;
}
+
+ protected Soup.Message get_stream () {
+ var url = "%s/api/v1/streaming/?stream=public:local&access_token=%s".printf (accounts.formal.instance, accounts.formal.token);
+ return new Soup.Message("GET", url);
+ }
}
diff --git a/src/Views/TimelineView.vala b/src/Views/TimelineView.vala
index 19ed20a..16c9cda 100644
--- a/src/Views/TimelineView.vala
+++ b/src/Views/TimelineView.vala
@@ -5,20 +5,39 @@ public class Tootle.TimelineView : AbstractView {
protected string timeline;
protected string pars;
-
protected int limit = 25;
protected bool is_last_page = false;
protected string? page_next;
protected string? page_prev;
+
+ private Notificator? _notificator;
+ public Notificator? notificator {
+ get {
+ return _notificator;
+ }
+
+ set {
+ if (_notificator != null)
+ _notificator.close ();
+
+ _notificator = value;
+
+ if (_notificator != null)
+ _notificator.start ();
+ }
+ }
public TimelineView (string timeline, string pars = "") {
base ();
this.timeline = timeline;
this.pars = pars;
- Tootle.accounts.switched.connect(on_account_changed);
- Tootle.app.refresh.connect(on_refresh);
- Tootle.network.status_added.connect (on_status_added);
+ accounts.switched.connect (on_account_changed);
+ app.refresh.connect (on_refresh);
+ destroy.connect (() => {
+ if (notificator != null)
+ notificator.close ();
+ });
request ();
}
@@ -31,10 +50,7 @@ public class Tootle.TimelineView : AbstractView {
return _("Home");
}
- private void on_status_added (ref Status status, string timeline) {
- if (timeline != this.timeline)
- return;
-
+ public virtual void on_status_added (ref Status status) {
prepend (ref status);
}
@@ -138,6 +154,12 @@ public class Tootle.TimelineView : AbstractView {
public virtual void on_account_changed (Account? account){
if(account == null)
return;
+
+ if (notificator != null) {
+ notificator.close ();
+ notificator.start ();
+ }
+
on_refresh ();
}
diff --git a/src/Widgets/RichLabel.vala b/src/Widgets/RichLabel.vala
index c418d0f..b5ea55c 100644
--- a/src/Widgets/RichLabel.vala
+++ b/src/Widgets/RichLabel.vala
@@ -48,8 +48,19 @@ public class Tootle.RichLabel : Gtk.Label {
if ("/tags/" in url){
var encoded = url.split("/tags/")[1];
var hashtag = Soup.URI.decode (encoded);
- var feed = new TimelineView ("tag/" + hashtag);
- Tootle.window.open_view (feed);
+
+ var msg_url = "%s/api/v1/streaming/?stream=hashtag&access_token=%s&tag=%s"
+ .printf (accounts.formal.instance, accounts.formal.token, encoded);
+ var msg = new Soup.Message("GET", msg_url);
+
+ var timeline = new TimelineView ("tag/" + hashtag);
+ timeline.notificator = new Notificator (msg);
+ timeline.notificator.status_added.connect ((ref status) => {
+ if (settings.live_updates)
+ timeline.on_status_added (ref status);
+ });
+ window.open_view (timeline);
+
return true;
}