[banshee] [LastFm] Improved authentication experience



commit 5391ed0be2986ed8b43ba588661b2410f8648295
Author: Aaron Bockover <abockover novell com>
Date:   Mon May 3 22:19:06 2010 -0400

    [LastFm] Improved authentication experience
    
    Overhauled the workflow for logging in and authorizing Banshee to use
    Last.fm. The phases should be more clear now, and it is possible to log
    out and change accounts.
    
    Also show the AudioScrobbler enable/disable check box in the preferences
    dialog under the Last.fm page.

 .../Banshee.Lastfm.Radio/LastfmPreferences.cs      |  314 ++++++++++++++++++++
 .../Banshee.Lastfm.Radio/LastfmSource.cs           |  102 +------
 .../Banshee.Lastfm/Banshee.Lastfm.csproj           |    1 +
 src/Extensions/Banshee.Lastfm/Makefile.am          |    1 +
 4 files changed, 322 insertions(+), 96 deletions(-)
---
diff --git a/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmPreferences.cs b/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmPreferences.cs
new file mode 100644
index 0000000..ab3ce5e
--- /dev/null
+++ b/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmPreferences.cs
@@ -0,0 +1,314 @@
+// 
+// LastfmPreferences.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright (c) 2010 Novell, Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using Gtk;
+using Mono.Unix;
+
+using Lastfm.Gui;
+
+using Banshee.ServiceStack;
+using Banshee.Preferences;
+
+using Banshee.Lastfm.Audioscrobbler;
+
+using StationError = Lastfm.StationError;
+using RadioConnection = Lastfm.RadioConnection;
+
+namespace Banshee.Lastfm.Radio
+{
+    public class LastfmPreferences : IDisposable
+    {
+        private SourcePage source_page;
+        private Section account_section;
+        private Section prefs_section;
+        private SchemaPreference<string> username_preference;
+        private Preference<bool> reporting_preference;
+        private LastfmSource source;
+        private AudioscrobblerService scrobbler;
+
+        private bool Authorized {
+            get { return !String.IsNullOrEmpty (source.Account.SessionKey); }
+        }
+
+        private bool NeedAuthorization {
+            get { return !String.IsNullOrEmpty (username_preference.Value) && !Authorized; }
+        }
+
+        public string PageId {
+            get { return source_page.Id; }
+        }
+
+        public LastfmPreferences (LastfmSource source)
+        {
+            var service = ServiceManager.Get<PreferenceService> ();
+            if (service == null) {
+                return;
+            }
+
+            this.source = source;
+
+            service.InstallWidgetAdapters += OnPreferencesServiceInstallWidgetAdapters;
+            source_page = new Banshee.Preferences.SourcePage (source) {
+                (account_section = new Section ("lastfm-account", Catalog.GetString ("Account"), 20) {
+                    (username_preference = new SchemaPreference<string> (LastfmSource.LastUserSchema,
+                        Catalog.GetString ("_Username")) {
+                        ShowLabel = false
+                    }),
+                    new VoidPreference ("lastfm-signup")
+                }),
+                (prefs_section = new Section ("lastfm-settings", Catalog.GetString ("Preferences"), 30))
+            };
+
+            scrobbler = ServiceManager.Get<Banshee.Lastfm.Audioscrobbler.AudioscrobblerService> ();
+            if (scrobbler != null) {
+                reporting_preference = new Preference<bool> ("enable-song-reporting",
+                    Catalog.GetString ("_Enable Song Reporting"), null, scrobbler.Enabled);
+                reporting_preference.ValueChanged += root => scrobbler.Enabled = reporting_preference.Value;
+                prefs_section.Add (reporting_preference);
+            }
+        }
+
+        public void Dispose ()
+        {
+            PreferenceService service = ServiceManager.Get<PreferenceService> ();
+            if (service == null || source_page == null) {
+                return;
+            }
+
+            service.InstallWidgetAdapters -= OnPreferencesServiceInstallWidgetAdapters;
+            source_page.Dispose ();
+            source_page = null;
+        }
+
+        private enum SignInState {
+            SignedOut,
+            NeedAuthorization,
+            Failed,
+            SignedIn
+        }
+
+        private SignInState sign_in_state;
+        private StationError last_sign_in_error;
+        private Table sign_in_box;
+        private LinkButton signup_button;
+        private LinkButton profile_page_button;
+        private bool need_authorization_checked = true; // state for at which button the auth arrows should point
+
+        private void OnPreferencesServiceInstallWidgetAdapters (object sender, EventArgs args)
+        {
+            if (reporting_preference != null && scrobbler != null) {
+                reporting_preference.Value = scrobbler.Enabled;
+            }
+
+            if (account_section == null) {
+                return;
+            }
+
+            var align = new Alignment (0.0f, 0.0f, 1.0f, 1.0f) {
+                LeftPadding = 20,
+                RightPadding = 20
+            };
+
+            sign_in_box = new Table (0, 0, false) {
+                ColumnSpacing = 6,
+                RowSpacing = 2
+            };
+
+            align.Add (sign_in_box);
+            align.Show ();
+
+            username_preference.DisplayWidget = align;
+
+            align = new Alignment (0.5f, 0.5f, 1.0f, 1.0f) {
+                LeftPadding = 20,
+                RightPadding = 20,
+                TopPadding = 5
+            };
+
+            var button_box = new HBox () {
+                Spacing = 6
+            };
+
+            button_box.PackStart (new Badge (source.Account), false, false, 0);
+
+            signup_button = new Gtk.LinkButton (source.Account.SignUpUrl, Catalog.GetString ("Sign up for Last.fm"));
+            signup_button.Xalign = 0f;
+            button_box.PackStart (signup_button, false, false, 0);
+
+            profile_page_button = new Gtk.LinkButton (String.Empty, Catalog.GetString ("Visit Your Last.fm Profile Page"));
+            profile_page_button.Clicked += (o, e) => source.Account.VisitUserProfile (source.Account.UserName);
+            profile_page_button.Xalign = 0f;
+            button_box.PackStart (profile_page_button, false, false, 0);
+
+            align.Add (button_box);
+            align.ShowAll ();
+
+            account_section["lastfm-signup"].DisplayWidget = align;
+
+            GetSignInState ();
+            BuildSignIn ();
+        }
+
+        private void SignOut ()
+        {
+            LastfmSource.LastSessionKeySchema.Set (String.Empty);
+            username_preference.Value = String.Empty;
+            source.Account.UserName = String.Empty;
+            source.Account.SessionKey = null;
+            source.Account.Save ();
+        }
+
+        private void OnSignInClicked (object o, EventArgs args)
+        {
+            if (sign_in_state != SignInState.NeedAuthorization) {
+                sign_in_state = SignInState.NeedAuthorization;
+            }
+
+            need_authorization_checked = !need_authorization_checked;
+            BuildSignIn ();
+
+            source.Account.SessionKey = null;
+            source.Account.RequestAuthorization ();
+        }
+
+        private void OnSignOutClicked (object o, EventArgs args)
+        {
+            SignOut ();
+            GetSignInState ();
+            BuildSignIn ();
+        }
+
+        private void OnFinishSignInClicked (object o, EventArgs args)
+        {
+            last_sign_in_error = source.Account.FetchSessionKey ();
+            Hyena.Log.InformationFormat ("Last.fm authorization result = {0}", last_sign_in_error);
+            if (last_sign_in_error == StationError.TokenNotAuthorized) {
+                need_authorization_checked = true;
+                GetSignInState ();
+            } else if (last_sign_in_error == StationError.None) {
+                LastfmSource.LastSessionKeySchema.Set (source.Account.SessionKey);
+                source.Account.UserName = LastfmSource.LastUserSchema.Get ();
+                source.Account.Save ();
+                GetSignInState ();
+            } else {
+                SignOut ();
+                sign_in_state = SignInState.Failed;
+            }
+            BuildSignIn ();
+        }
+
+        private void GetSignInState ()
+        {
+            if (Authorized) {
+                sign_in_state = SignInState.SignedIn;
+            } else if (NeedAuthorization) {
+                sign_in_state = SignInState.NeedAuthorization;
+            } else {
+                sign_in_state = SignInState.SignedOut;
+            }
+        }
+
+        private void BuildSignIn ()
+        {
+            signup_button.Visible = sign_in_state != SignInState.SignedIn;
+            profile_page_button.Visible = sign_in_state == SignInState.SignedIn;
+
+            var children = sign_in_box.Children;
+            foreach (var child in children) {
+                sign_in_box.Remove (child);
+            }
+
+            var oauth_explain = Catalog.GetString ("Open Last.fm in a browser, giving you the option to authorize Banshee to work with your account");
+
+            switch (sign_in_state) {
+                case SignInState.SignedOut:
+                case SignInState.Failed:
+                    need_authorization_checked = true;
+
+                    var username_entry = new Entry () { Text = username_preference.Value };
+                    username_entry.Changed += (o, e) => username_preference.Value = username_entry.Text;
+                    username_entry.GrabFocus ();
+
+                    var sign_in_button = new Button (Catalog.GetString ("Log in to Last.fm")) {
+                        TooltipText = oauth_explain
+                    };
+                    sign_in_button.Clicked += OnSignInClicked;
+
+                    sign_in_box.Attach (new Label (Catalog.GetString ("_Username")),
+                        0, 1, 0, 1, AttachOptions.Shrink, AttachOptions.Shrink, 0, 0);
+                    sign_in_box.Attach (username_entry,
+                        1, 2, 0, 1, AttachOptions.Fill | AttachOptions.Expand, AttachOptions.Shrink, 0, 0);
+                    sign_in_box.Attach (sign_in_button,
+                        2, 3, 0, 1, AttachOptions.Shrink, AttachOptions.Shrink, 0, 0);
+                    if (sign_in_state == SignInState.Failed) {
+                        sign_in_box.Attach (new Hyena.Widgets.WrapLabel () {
+                            Markup = String.Format ("<i>{0}</i>", GLib.Markup.EscapeText (
+                                RadioConnection.ErrorMessageFor (last_sign_in_error)))
+                        }, 1, 3, 1, 2, AttachOptions.Fill | AttachOptions.Expand, AttachOptions.Shrink, 0, 0);
+                    }
+                    break;
+                case SignInState.NeedAuthorization:
+                    sign_in_box.Attach (new Hyena.Widgets.WrapLabel () {
+                        Markup = String.Format ("<i>{0}</i>", GLib.Markup.EscapeText (
+                            Catalog.GetString ("You need to allow Banshee to access your Last.fm account."))),
+                    }, 0, 1, 0, 2, AttachOptions.Fill | AttachOptions.Expand, AttachOptions.Shrink, 0, 0);
+
+                    var r = need_authorization_checked ? 1u : 0u;
+                    sign_in_box.Attach (new Image (Stock.GoForward, IconSize.Button),
+                        1, 2, r, r + 1, AttachOptions.Shrink, AttachOptions.Shrink, 0, 0);
+
+                    sign_in_box.Attach (new Image (Stock.GoBack, IconSize.Button),
+                        3, 4, r, r + 1, AttachOptions.Shrink, AttachOptions.Shrink, 0, 0);
+
+                    var check_auth_button = new Button (Catalog.GetString ("Finish Logging In"));
+                    check_auth_button.Clicked += OnFinishSignInClicked;
+                    sign_in_box.Attach (check_auth_button,
+                        2, 3, 0, 1, AttachOptions.Fill, AttachOptions.Shrink, 0, 0);
+
+                    var try_again_button = new Button (Catalog.GetString ("Try Again")) {
+                        TooltipText = oauth_explain
+                    };
+                    try_again_button.Clicked += OnSignInClicked;
+                    sign_in_box.Attach (try_again_button,
+                        2, 3, 1, 2, AttachOptions.Fill, AttachOptions.Shrink, 0, 0);
+                    break;
+                case SignInState.SignedIn:
+                    sign_in_box.Attach (new Hyena.Widgets.WrapLabel () {
+                        Markup = String.Format (Catalog.GetString ("You are logged in to Last.fm as the user <i>{0}</i>."),
+                            source.Account.UserName)
+                    }, 0, 1, 0, 1, AttachOptions.Fill | AttachOptions.Expand, AttachOptions.Shrink, 0, 0);
+                    var log_out_button = new Button (Catalog.GetString ("Log out of Last.fm"));
+                    log_out_button.Clicked += OnSignOutClicked;
+                    sign_in_box.Attach (log_out_button, 1, 2, 0, 1,
+                        AttachOptions.Shrink, AttachOptions.Shrink, 0, 0);
+                    break;
+            }
+
+            sign_in_box.ShowAll ();
+        }
+    }
+}
diff --git a/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmSource.cs b/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmSource.cs
index 1ef4fbf..23f1fcc 100644
--- a/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmSource.cs
+++ b/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmSource.cs
@@ -71,6 +71,8 @@ namespace Banshee.Lastfm.Radio
             get { return actions; }
         }
 
+        private LastfmPreferences preferences;
+
         public LastfmSource () : base (lastfm, lastfm, 210, lastfm)
         {
             account = LastfmCore.Account;
@@ -112,7 +114,7 @@ namespace Banshee.Lastfm.Radio
             Properties.Set<bool> ("Nereid.SourceContents.HeaderVisible", false);
 
             actions = new LastfmActions (this);
-            InstallPreferences ();
+            preferences = new LastfmPreferences (this);
 
             ServiceManager.SourceManager.AddSource (this);
 
@@ -125,11 +127,12 @@ namespace Banshee.Lastfm.Radio
             Connection.StateChanged -= HandleConnectionStateChanged;
             ServiceManager.Get<Network> ().StateChanged -= HandleNetworkStateChanged;
             Connection.Dispose ();
-            UninstallPreferences ();
+            preferences.Dispose ();
             actions.Dispose ();
 
             actions = null;
             connection = null;
+            preferences = null;
             account = null;
         }
 
@@ -278,101 +281,8 @@ namespace Banshee.Lastfm.Radio
             status_message.ThawNotify ();
         }
 
-        private SourcePage pref_page;
-        private Section pref_section;
-        private SchemaPreference<string> user_pref;
-
-        private void InstallPreferences ()
-        {
-            PreferenceService service = ServiceManager.Get<PreferenceService> ();
-            if (service == null) {
-                return;
-            }
-
-            service.InstallWidgetAdapters += OnPreferencesServiceInstallWidgetAdapters;
-            pref_page = new Banshee.Preferences.SourcePage (this);
-            pref_section = pref_page.Add (new Section ("lastfm-account", Catalog.GetString ("Account"), 20));
-            pref_section.ShowLabel = false;
-
-            user_pref = new SchemaPreference<string> (LastUserSchema, Catalog.GetString ("_Username"));
-            pref_section.Add (user_pref);
-            pref_section.Add (new VoidPreference ("lastfm-signup"));
-        }
-
-        private void UninstallPreferences ()
-        {
-            PreferenceService service = ServiceManager.Get<PreferenceService> ();
-            if (service == null || pref_page == null) {
-                return;
-            }
-
-            service.InstallWidgetAdapters -= OnPreferencesServiceInstallWidgetAdapters;
-            pref_page.Dispose ();
-            pref_page = null;
-        }
-
-        private bool Authorized { get { return !String.IsNullOrEmpty (account.SessionKey); } }
-        private bool NeedAuth { get { return !String.IsNullOrEmpty (user_pref.Value) && !Authorized; } }
-
-        private void OnPreferencesServiceInstallWidgetAdapters (object sender, EventArgs args)
-        {
-            if (pref_section == null) {
-                return;
-            }
-
-            var user_entry = new Gtk.Entry (user_pref.Value ?? "");
-            user_entry.Changed += (o, a) => { user_pref.Value = user_entry.Text; };
-
-            var auth_button = new Gtk.Button (Authorized ? Catalog.GetString ("Authorized!") : Catalog.GetString ("Authorize..."));
-            user_pref.ValueChanged += (s) => { auth_button.Sensitive = NeedAuth; };
-            auth_button.Sensitive = NeedAuth;
-            auth_button.TooltipText = Catalog.GetString ("Open Last.fm in a browser, giving you the option to authorize Banshee to work with your account");
-            auth_button.Clicked += delegate {
-                account.SessionKey = null;
-                account.RequestAuthorization ();
-            };
-
-            var signup_button = new Gtk.LinkButton (account.SignUpUrl, Catalog.GetString ("Sign up for Last.fm"));
-            signup_button.Xalign = 0f;
-
-            var refresh_button = new Gtk.Button (new Gtk.Image (Gtk.Stock.Refresh, Gtk.IconSize.Button));
-            user_pref.ValueChanged += (s) => { refresh_button.Sensitive = NeedAuth; };
-            refresh_button.Sensitive = NeedAuth;
-            refresh_button.TooltipText = Catalog.GetString ("Check if Banshee has been authorized");
-            refresh_button.Clicked += delegate {
-                if (String.IsNullOrEmpty (account.UserName) || account.SessionKey == null) {
-                    account.UserName = LastUserSchema.Get ();
-                    account.FetchSessionKey ();
-                    account.Save ();
-                    if (account.SessionKey != null) {
-                        LastSessionKeySchema.Set (account.SessionKey);
-                    }
-                }
-
-                auth_button.Sensitive = refresh_button.Sensitive = NeedAuth;
-                auth_button.Label = Authorized
-                    ? Catalog.GetString ("Authorized!")
-                    : Catalog.GetString ("Authorize...");
-            };
-
-            var auth_box = new Gtk.HBox () { Spacing = 6 };
-            auth_box.PackStart (user_entry, true, true, 0);
-            auth_box.PackStart (auth_button, false, false, 0);
-            auth_box.PackStart (refresh_button, false, false, 0);
-            auth_box.ShowAll ();
-
-            signup_button.Visible = String.IsNullOrEmpty (user_pref.Value);
-
-            var button_box = new Gtk.HBox () { Spacing = 6 };
-            button_box.PackStart (new Badge (account) { Visible = true}, false, false, 0);
-            button_box.PackStart (signup_button, true, true, 0);
-
-            user_pref.DisplayWidget = auth_box;
-            pref_section["lastfm-signup"].DisplayWidget = button_box;
-        }
-
         public override string PreferencesPageId {
-            get { return pref_page.Id; }
+            get { return preferences.PageId; }
         }
 
         public static readonly SchemaEntry<bool> EnabledSchema = new SchemaEntry<bool> (
diff --git a/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.csproj b/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.csproj
index 602311f..668f10e 100644
--- a/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.csproj
+++ b/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.csproj
@@ -100,6 +100,7 @@
     <Compile Include="Banshee.Lastfm.Recommendations\ContextPage.cs" />
     <Compile Include="Banshee.Lastfm.Recommendations\RecommendationPane.cs" />
     <Compile Include="Banshee.Lastfm.Recommendations\SimilarArtistTile.cs" />
+    <Compile Include="Banshee.Lastfm.Radio\LastfmPreferences.cs" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Banshee.Lastfm.addin.xml">
diff --git a/src/Extensions/Banshee.Lastfm/Makefile.am b/src/Extensions/Banshee.Lastfm/Makefile.am
index 5352929..41444eb 100644
--- a/src/Extensions/Banshee.Lastfm/Makefile.am
+++ b/src/Extensions/Banshee.Lastfm/Makefile.am
@@ -8,6 +8,7 @@ SOURCES =  \
 	Banshee.Lastfm.Audioscrobbler/Queue.cs \
 	Banshee.Lastfm.Radio/LastfmActions.cs \
 	Banshee.Lastfm.Radio/LastfmColumnController.cs \
+	Banshee.Lastfm.Radio/LastfmPreferences.cs \
 	Banshee.Lastfm.Radio/LastfmSource.cs \
 	Banshee.Lastfm.Radio/LastfmSourceContents.cs \
 	Banshee.Lastfm.Radio/LastfmTrackInfo.cs \



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]