diff --git a/src/application.vala b/src/application.vala index e2b0914..f5d7205 100644 --- a/src/application.vala +++ b/src/application.vala @@ -85,7 +85,7 @@ public class Wavelet.Application : Adw.Application { Timeout.add (100, () => { int64 position_ns; if (playbin.query_position (Gst.Format.TIME, out position_ns)) { - win.play_position_ms = position_ns / 1000000; + win.play_position_ms = (int) (position_ns / 1000000); } return Source.CONTINUE; }); @@ -100,7 +100,7 @@ public class Wavelet.Application : Adw.Application { print("%lld\n", duration_ns); win.play_position_ms = 0; - win.play_duration_ms = duration_ns / 1000000; + win.play_duration_ms = (int) (duration_ns / 1000000); break; diff --git a/src/play_queue.blp b/src/play_queue.blp index 9e0b9cd..5663e5a 100644 --- a/src/play_queue.blp +++ b/src/play_queue.blp @@ -12,6 +12,8 @@ template $WaveletPlayQueue: Adw.NavigationPage { ListView list_view { single-click-activate: true; + activate => $on_song_activate (); + factory: BuilderListItemFactory { template ListItem { child: Label { diff --git a/src/play_queue.vala b/src/play_queue.vala index 03de8c9..ddc270f 100644 --- a/src/play_queue.vala +++ b/src/play_queue.vala @@ -32,11 +32,6 @@ public class Wavelet.PlayQueue : Adw.NavigationPage { this.current = 0; this.list_view.model = new Gtk.NoSelection (this.songs); - this.list_view.activate.connect ((position) => { - this.current = position; - Song song = (Song) this.songs.get_item (position); - this.play_now (song); - }); } public void clear () { @@ -57,4 +52,10 @@ public class Wavelet.PlayQueue : Adw.NavigationPage { public Song? peek () { return (Song?) this.songs.get_item (this.current+1); } + + [GtkCallback] private void on_song_activate (uint position) { + this.current = position; + Song song = (Song) this.songs.get_item (position); + this.play_now (song); + } } diff --git a/src/setup.blp b/src/setup.blp index 01dc055..c271b56 100644 --- a/src/setup.blp +++ b/src/setup.blp @@ -12,31 +12,52 @@ template $WaveletSetup: Adw.NavigationPage { child: Adw.PreferencesGroup { title: _("Authentication"); - Adw.EntryRow server_url { + [header-suffix] + Gtk.Button { + styles [ "flat" ] + icon-name: "edit-undo"; + sensitive: bind template.authn_can_validate; + } + + Adw.EntryRow { title: _("Server URL"); input-purpose: url; + sensitive: bind template.authn_can_edit; + text: bind template.server_url bidirectional; + + changed => $on_authn_changed (); } - Adw.EntryRow username { + Adw.EntryRow { title: _("Username"); + sensitive: bind template.authn_can_edit; + text: bind template.username bidirectional; + + changed => $on_authn_changed (); } - Adw.PasswordEntryRow password { + Adw.PasswordEntryRow { title: _("Password"); + sensitive: bind template.authn_can_edit; + text: bind template.password bidirectional; + + changed => $on_authn_changed (); } - Adw.ActionRow status { + Adw.ActionRow { title: _("Status"); - subtitle: _("Not connected"); + subtitle: bind template.status; styles [ "property", ] } - Adw.ButtonRow validate { + Adw.ButtonRow { title: _("Connect and save"); - sensitive: false; + sensitive: bind template.authn_can_validate; + + activated => $on_authn_validate_activated (); } }; } diff --git a/src/setup.vala b/src/setup.vala index 7acb4ad..138dd0d 100644 --- a/src/setup.vala +++ b/src/setup.vala @@ -23,68 +23,56 @@ public extern void randomness (int N, void *P); [GtkTemplate (ui = "/eu/callcc/Wavelet/setup.ui")] public class Wavelet.Setup : Adw.NavigationPage { - [GtkChild] private unowned Adw.EntryRow server_url; - [GtkChild] private unowned Adw.EntryRow username; - [GtkChild] private unowned Adw.PasswordEntryRow password; + public string status { get; private set; default = _("Not connected"); } - [GtkChild] private unowned Adw.ActionRow status; - [GtkChild] private unowned Adw.ButtonRow validate; + public bool authn_can_edit { get; private set; default = true; } + public bool authn_can_validate { get; private set; default = false; } - private string token; - private string salt; + public string server_url { get; set; default = ""; } + public string username { get; set; default = ""; } + public string password { get; set; default = ""; } + public string token; + public string salt; public signal void connected (Wavelet.Subsonic api); - construct { - this.server_url.changed.connect (() => { - this.validate.set_sensitive (true); - }); - this.username.changed.connect (() => { - this.validate.set_sensitive (true); - }); - this.password.changed.connect (() => { - this.validate.set_sensitive (true); - }); + [GtkCallback] private void on_authn_changed () { + this.authn_can_validate = true; + } - this.validate.activated.connect (() => { - this.server_url.set_sensitive (false); - this.username.set_sensitive (false); - this.password.set_sensitive (false); - this.status.set_subtitle (_("Connecting...")); - this.validate.set_sensitive (false); + [GtkCallback] private void on_authn_validate_activated () { + this.authn_can_validate = false; + this.authn_can_edit = false; + this.status = _("Connecting..."); - string new_token, new_salt; - if (this.password.get_text () != "") { - this.salt_password (this.password.get_text (), out new_token, out new_salt); - } else { - new_token = this.token; - new_salt = this.salt; + string new_token, new_salt; + if (this.password != "") { + this.salt_password (this.password, out new_token, out new_salt); + } else { + new_token = this.token; + new_salt = this.salt; + } + var api = new Wavelet.Subsonic.with_token ( + this.server_url, + this.username, + new_token, + new_salt); + + api.ping.begin ((obj, res) => { + try { + api.ping.end (res); + this.status = _("Connected"); + this.token = new_token; + this.salt = new_salt; + this.save (); + + this.connected (api); + } catch (Error e) { + this.status = @"$(_("Ping failed")): $(e.message)"; + this.authn_can_validate = true; } - var api = new Wavelet.Subsonic.with_token ( - this.server_url.get_text (), - this.username.get_text (), - new_token, - new_salt); - api.ping.begin ((obj, res) => { - try { - api.ping.end (res); - this.status.set_subtitle (_("Connected")); - this.token = new_token; - this.salt = new_salt; - this.save (); - this.validate.set_sensitive (false); - - this.connected (api); - } catch (Error e) { - this.status.set_subtitle(@"$(_("Ping failed")): $(e.message)"); - this.validate.set_sensitive (true); - } - - this.server_url.set_sensitive (true); - this.username.set_sensitive (true); - this.password.set_sensitive (true); - }); + this.authn_can_edit = true; }); } @@ -97,17 +85,17 @@ public class Wavelet.Setup : Adw.NavigationPage { stmt.bind_text (1, "server_url"); if (stmt.step () == Sqlite.ROW) { - this.server_url.set_text (stmt.column_text (0)); + this.server_url = stmt.column_text (0); } else { - this.server_url.set_text (""); + this.server_url = ""; } assert (stmt.reset () == Sqlite.OK); stmt.bind_text (1, "username"); if (stmt.step () == Sqlite.ROW) { - this.username.set_text (stmt.column_text (0)); + this.username = stmt.column_text (0); } else { - this.username.set_text (""); + this.username = ""; } assert (stmt.reset () == Sqlite.OK); @@ -127,11 +115,11 @@ public class Wavelet.Setup : Adw.NavigationPage { } assert (stmt.reset () == Sqlite.OK); - this.password.set_text (""); - this.validate.set_sensitive (false); + this.password = ""; // first connection - this.validate.activate (); + this.authn_can_validate = true; + this.on_authn_validate_activated (); } private void salt_password (string password, out string token, out string salt) { @@ -159,12 +147,12 @@ public class Wavelet.Setup : Adw.NavigationPage { assert (rc == Sqlite.OK); stmt.bind_text (1, "server_url"); - stmt.bind_text (2, this.server_url.get_text ()); + stmt.bind_text (2, this.server_url); assert (stmt.step () == Sqlite.DONE); assert (stmt.reset () == Sqlite.OK); stmt.bind_text (1, "username"); - stmt.bind_text (2, this.username.get_text ()); + stmt.bind_text (2, this.username); assert (stmt.step () == Sqlite.DONE); assert (stmt.reset () == Sqlite.OK); @@ -178,6 +166,6 @@ public class Wavelet.Setup : Adw.NavigationPage { assert (stmt.step () == Sqlite.DONE); assert (stmt.reset () == Sqlite.OK); - this.password.set_text (""); + this.password = ""; } } diff --git a/src/window.blp b/src/window.blp index ec978da..4b24e1e 100644 --- a/src/window.blp +++ b/src/window.blp @@ -29,6 +29,8 @@ template $WaveletWindow: Adw.ApplicationWindow { "navigation-sidebar", ] + row-activated => $on_sidebar_row_activated(); + ListBoxRow sidebar_setup { Label { xalign: 0; @@ -152,7 +154,7 @@ template $WaveletWindow: Adw.ApplicationWindow { "numeric", ] - label: "00:00"; + label: bind $format_timestamp (template.play_position_ms) as ; } Scale play_position { @@ -173,7 +175,7 @@ template $WaveletWindow: Adw.ApplicationWindow { "numeric", ] - label: "00:00"; + label: bind $format_timestamp (template.play_duration_ms) as ; } } } diff --git a/src/window.vala b/src/window.vala index 6b92b7a..f75d86f 100644 --- a/src/window.vala +++ b/src/window.vala @@ -36,8 +36,8 @@ public class Wavelet.Window : Adw.ApplicationWindow { [GtkChild] public unowned Gtk.Scale play_position; [GtkChild] private unowned Gtk.Label play_duration; - public int64 play_position_ms { get; set; default = 0; } - public int64 play_duration_ms { get; set; default = 1; } + public int play_position_ms { get; set; default = 0; } + public int play_duration_ms { get; set; default = 1; } public double volume { get; set; default = 1.0; } @@ -48,23 +48,6 @@ public class Wavelet.Window : Adw.ApplicationWindow { } construct { - this.notify["play-position-ms"].connect ((s, p) => { - int seconds = (int)(this.play_position_ms/1000); - this.play_position_label.label = "%02d:%02d".printf(seconds/60, seconds%60); - }); - this.notify["play-duration-ms"].connect ((s, p) => { - int seconds = (int)(this.play_duration_ms/1000); - this.play_duration.label = "%02d:%02d".printf(seconds/60, seconds%60); - }); - - this.sidebar.row_activated.connect ((row) => { - if (row == this.sidebar_setup) { - this.stack.set_visible_child_name("setup"); - } else if (row == this.sidebar_play_queue) { - this.stack.set_visible_child_name("play_queue"); - } - }); - this.sidebar.select_row (this.sidebar.get_row_at_index (0)); } @@ -75,4 +58,17 @@ public class Wavelet.Window : Adw.ApplicationWindow { public void show_unmute () { this.mute.icon_name = "audio-volume-high"; } + + [GtkCallback] private void on_sidebar_row_activated (Gtk.ListBoxRow row) { + if (row == this.sidebar_setup) { + this.stack.set_visible_child_name("setup"); + } else if (row == this.sidebar_play_queue) { + this.stack.set_visible_child_name("play_queue"); + } + } + + [GtkCallback] private string format_timestamp (int ms) { + int s = ms / 1000; + return "%02d:%02d".printf (s/60, s%60); + } }