OSDN Git Service

アカウント追加時にTwitter{Cookie,OAuth}SetupDialogを使用する
authorKimura Youichi <kim.upsilon@bucyou.net>
Sun, 19 May 2024 17:37:13 +0000 (02:37 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Sun, 19 May 2024 18:20:07 +0000 (03:20 +0900)
CHANGELOG.txt
OpenTween/AppendSettingDialog.cs
OpenTween/Setting/Panel/BasedPanel.Designer.cs
OpenTween/Setting/Panel/BasedPanel.cs
OpenTween/Setting/Panel/BasedPanel.resx
OpenTween/SocialProtocol/AccountSetupDispatcher.cs [new file with mode: 0644]
OpenTween/SocialProtocol/IAccountFactory.cs [new file with mode: 0644]
OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.cs
OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.cs

index 1df31a3..451e9a1 100644 (file)
@@ -4,6 +4,7 @@
  * NEW: Twemoji 15.1.0 に対応しました
    - Unicode 15.1 で追加された絵文字が表示されるようになります
  * CHG: 設定画面でのアカウント一覧の表示形式を変更
+ * CHG: 新規アカウント追加時のダイアログの構成を変更
  * CHG: 新規タブの初回に読み込まれた発言を既読状態にする(起動時の初回の読み込みと同じ動作となる)
  * CHG: ドメインに x.com が使われている引用ツイートの展開・投稿に対応
  * FIX: 発言の削除中にタブを切り替えるとエラーが発生する不具合を修正 (thx @Tan90909090!)
index 9f0939a..435e762 100644 (file)
@@ -32,7 +32,6 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Windows.Forms;
-using OpenTween.Api;
 using OpenTween.Connection;
 using OpenTween.Models;
 using OpenTween.Setting.Panel;
@@ -47,7 +46,8 @@ namespace OpenTween
         {
             this.InitializeComponent();
 
-            this.BasedPanel.AddAccountButton.Click += this.AddAccountButton_Click;
+            this.BasedPanel.ApplyNetworkSettings = this.ApplyNetworkSettings;
+            this.BasedPanel.OpenInBrowser = this.OpenInBrowser;
             this.GetPeriodPanel.CheckPostAndGet.CheckedChanged += this.CheckPostAndGet_CheckedChanged;
             this.ActionPanel.UReadMng.CheckedChanged += this.UReadMng_CheckedChanged;
 
@@ -166,60 +166,6 @@ namespace OpenTween
             }
         }
 
-        private async void AddAccountButton_Click(object sender, EventArgs e)
-        {
-            using (ControlTransaction.Disabled(this.BasedPanel.AddAccountButton))
-            {
-                try
-                {
-                    this.ApplyNetworkSettings();
-
-                    var appToken = this.SelectAuthType();
-                    if (appToken == null)
-                        return;
-
-                    UserAccount newAccount;
-                    if (appToken.AuthType == APIAuthType.TwitterComCookie)
-                    {
-                        newAccount = new()
-                        {
-                            TwitterAuthType = appToken.AuthType,
-                            TwitterComCookie = appToken.TwitterComCookie,
-                        };
-
-                        using var twitterApi = new TwitterApi();
-                        using var apiConnection = new TwitterApiConnection(new TwitterCredentialCookie(appToken), new());
-                        twitterApi.Initialize(apiConnection);
-                        var twitterUser = await twitterApi.AccountVerifyCredentials();
-                        newAccount.UserId = twitterUser.IdStr;
-                        newAccount.Username = twitterUser.ScreenName;
-                    }
-                    else
-                    {
-                        var account = await this.PinAuth(appToken);
-                        if (account == null)
-                            return;
-                        newAccount = account;
-                    }
-
-                    this.BasedPanel.AddAccount(newAccount);
-
-                    MessageBox.Show(
-                        this,
-                        Properties.Resources.AuthorizeButton_Click1,
-                        "Authenticate",
-                        MessageBoxButtons.OK);
-                }
-                catch (TwitterApiException ex)
-                {
-                    var message = Properties.Resources.AuthorizeButton_Click2 + Environment.NewLine +
-                        string.Join(Environment.NewLine, ex.LongMessages);
-
-                    MessageBox.Show(this, message, "Authenticate", MessageBoxButtons.OK);
-                }
-            }
-        }
-
         /// <summary>
         /// 現在設定画面に入力されているネットワーク関係の設定を適用します
         /// </summary>
@@ -250,40 +196,10 @@ namespace OpenTween
             TwitterApiConnection.RestApiHost = this.ConnectionPanel.TwitterAPIText.Text.Trim();
         }
 
-        private TwitterAppToken? SelectAuthType()
-        {
-            using var dialog = new AuthTypeSelectDialog();
-
-            var ret = dialog.ShowDialog(this);
-            if (ret != DialogResult.OK)
-                return null;
-
-            return dialog.Result;
-        }
-
-        private async Task<UserAccount?> PinAuth(TwitterAppToken appToken)
+        private async Task OpenInBrowser(IWin32Window? owner, Uri uri)
         {
-            var requestToken = await TwitterApiConnection.GetRequestTokenAsync(appToken);
-
-            var pinPageUrl = TwitterApiConnection.GetAuthorizeUri(requestToken);
-
             var browserPath = this.ActionPanel.BrowserPathText.Text;
-            var pin = AuthDialog.DoAuth(this, pinPageUrl, browserPath);
-            if (MyCommon.IsNullOrEmpty(pin))
-                return null; // キャンセルされた場合
-
-            var accessTokenResponse = await TwitterApiConnection.GetAccessTokenAsync(requestToken, pin);
-
-            return new UserAccount
-            {
-                TwitterAuthType = appToken.AuthType,
-                TwitterOAuth1ConsumerKey = appToken.OAuth1CustomConsumerKey?.Value ?? "",
-                TwitterOAuth1ConsumerSecret = appToken.OAuth1CustomConsumerSecret?.Value ?? "",
-                Username = accessTokenResponse["screen_name"],
-                UserId = accessTokenResponse["user_id"],
-                Token = accessTokenResponse["oauth_token"],
-                TokenSecret = accessTokenResponse["oauth_token_secret"],
-            };
+            await MyCommon.OpenInBrowserAsync(owner, browserPath, uri);
         }
 
         private void CheckPostAndGet_CheckedChanged(object sender, EventArgs e)
index a111e99..2aa8e5b 100644 (file)
@@ -28,6 +28,7 @@
         /// </summary>
         private void InitializeComponent()
         {
+            this.components = new System.ComponentModel.Container();
             System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BasedPanel));
             this.AccountListLabel = new System.Windows.Forms.Label();
             this.AccountsListBox = new System.Windows.Forms.ListBox();
@@ -35,6 +36,7 @@
             this.RemoveAccountButton = new System.Windows.Forms.Button();
             this.MakePrimaryButton = new System.Windows.Forms.Button();
             this.panel1 = new System.Windows.Forms.Panel();
+            this.contextMenuAddAccount = new System.Windows.Forms.ContextMenuStrip(this.components);
             this.panel1.SuspendLayout();
             this.SuspendLayout();
             // 
@@ -54,6 +56,7 @@
             resources.ApplyResources(this.AddAccountButton, "AddAccountButton");
             this.AddAccountButton.Name = "AddAccountButton";
             this.AddAccountButton.UseVisualStyleBackColor = true;
+            this.AddAccountButton.Click += new System.EventHandler(this.AddAccountButton_Click);
             // 
             // RemoveAccountButton
             // 
             resources.ApplyResources(this.panel1, "panel1");
             this.panel1.Name = "panel1";
             // 
+            // contextMenuAddAccount
+            // 
+            this.contextMenuAddAccount.Name = "contextMenuAddAccount";
+            resources.ApplyResources(this.contextMenuAddAccount, "contextMenuAddAccount");
+            // 
             // BasedPanel
             // 
             resources.ApplyResources(this, "$this");
         internal System.Windows.Forms.Button RemoveAccountButton;
         internal System.Windows.Forms.Button MakePrimaryButton;
         private System.Windows.Forms.Panel panel1;
+        private System.Windows.Forms.ContextMenuStrip contextMenuAddAccount;
     }
 }
index 7b9370a..042b27b 100644 (file)
@@ -30,6 +30,9 @@ using System;
 using System.ComponentModel;
 using System.Data;
 using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using OpenTween.SocialProtocol;
 
 namespace OpenTween.Setting.Panel
 {
@@ -37,6 +40,12 @@ namespace OpenTween.Setting.Panel
     {
         internal BindingList<AccountListBoxItem> AccountsList { get; } = new();
 
+        internal Action? ApplyNetworkSettings { get; set; }
+
+        internal Func<IWin32Window?, Uri, Task>? OpenInBrowser { get; set; }
+
+        private readonly AccountSetupDispatcher setupDispatcher = new();
+
         internal record AccountListBoxItem(UserAccount AccountSettings, bool IsPrimary)
         {
             public string DisplayText
@@ -61,6 +70,7 @@ namespace OpenTween.Setting.Panel
         {
             this.InitializeComponent();
             this.InitializeBinding();
+            this.InitializeAddAccountDropdown();
         }
 
         private void InitializeBinding()
@@ -69,6 +79,22 @@ namespace OpenTween.Setting.Panel
             this.AccountsListBox.DisplayMember = nameof(AccountListBoxItem.DisplayText);
         }
 
+        private void InitializeAddAccountDropdown()
+        {
+            foreach (var (id, caption) in this.setupDispatcher.GetCaptions())
+            {
+                var menuItem = new ToolStripMenuItem
+                {
+                    Text = caption,
+                    Tag = id,
+                };
+                menuItem.Click += this.AddAccountMenuItem_Click;
+
+                this.contextMenuAddAccount.Items.Add(menuItem);
+                this.components.Add(menuItem);
+            }
+        }
+
         public void LoadConfig(SettingCommon settingCommon)
         {
             using (ControlTransaction.Update(this.AccountsListBox))
@@ -155,6 +181,34 @@ namespace OpenTween.Setting.Panel
                 this.AccountsList[index] with { IsPrimary = true };
         }
 
+        private void AddAccountButton_Click(object sender, EventArgs e)
+        {
+            this.contextMenuAddAccount.Show(
+                this.AddAccountButton,
+                new(x: 0, y: this.AddAccountButton.Height)
+            );
+        }
+
+        private void AddAccountMenuItem_Click(object sender, EventArgs e)
+        {
+            var setupId = (Guid)((ToolStripMenuItem)sender).Tag;
+
+            this.ApplyNetworkSettings?.Invoke();
+
+            var authorizedAccount = this.setupDispatcher.Dispatch(this, setupId, this.OpenInBrowser);
+            if (authorizedAccount == null)
+                return;
+
+            this.AddAccount(authorizedAccount);
+
+            MessageBox.Show(
+                this,
+                Properties.Resources.AuthorizeButton_Click1,
+                "Authenticate",
+                MessageBoxButtons.OK
+            );
+        }
+
         private void RemoveAccountButton_Click(object sender, EventArgs e)
         {
             var selectedIndex = this.AccountsListBox.SelectedIndex;
index d71e0c3..277b059 100644 (file)
@@ -24,6 +24,8 @@
        <data name="&gt;&gt;AddAccountButton.Parent"><value>panel1</value></data>
        <data name="&gt;&gt;AddAccountButton.Type"><value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></data>
        <data name="&gt;&gt;AddAccountButton.ZOrder"><value>2</value></data>
+       <data name="&gt;&gt;contextMenuAddAccount.Name"><value>contextMenuAddAccount</value></data>
+       <data name="&gt;&gt;contextMenuAddAccount.Type"><value>System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></data>
        <data name="&gt;&gt;MakePrimaryButton.Name"><value>MakePrimaryButton</value></data>
        <data name="&gt;&gt;MakePrimaryButton.Parent"><value>panel1</value></data>
        <data name="&gt;&gt;MakePrimaryButton.Type"><value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></data>
@@ -31,7 +33,7 @@
        <data name="&gt;&gt;panel1.Name"><value>panel1</value></data>
        <data name="&gt;&gt;panel1.Parent"><value>$this</value></data>
        <data name="&gt;&gt;panel1.Type"><value>System.Windows.Forms.Panel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></data>
-       <data name="&gt;&gt;panel1.ZOrder"><value>0</value></data>
+       <data name="&gt;&gt;panel1.ZOrder"><value>1</value></data>
        <data name="&gt;&gt;RemoveAccountButton.Name"><value>RemoveAccountButton</value></data>
        <data name="&gt;&gt;RemoveAccountButton.Parent"><value>panel1</value></data>
        <data name="&gt;&gt;RemoveAccountButton.Type"><value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></data>
@@ -57,6 +59,8 @@
        <data name="AddAccountButton.Size" type="System.Drawing.Size, System.Drawing"><value>100, 25</value></data>
        <data name="AddAccountButton.TabIndex" type="System.Int32, mscorlib"><value>2</value></data>
        <data name="AddAccountButton.Text"><value>追加</value></data>
+       <data name="contextMenuAddAccount.Size" type="System.Drawing.Size, System.Drawing"><value>181, 26</value></data>
+       <metadata name="contextMenuAddAccount.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"><value>17, 17</value></metadata>
        <data name="MakePrimaryButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"><value>Top, Right</value></data>
        <data name="MakePrimaryButton.AutoSize" type="System.Boolean, mscorlib"><value>True</value></data>
        <data name="MakePrimaryButton.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms"><value>NoControl</value></data>
diff --git a/OpenTween/SocialProtocol/AccountSetupDispatcher.cs b/OpenTween/SocialProtocol/AccountSetupDispatcher.cs
new file mode 100644 (file)
index 0000000..6d69d37
--- /dev/null
@@ -0,0 +1,65 @@
+// OpenTween - Client of Twitter
+// Copyright (c) 2024 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using OpenTween.SocialProtocol.Twitter;
+
+namespace OpenTween.SocialProtocol
+{
+    public class AccountSetupDispatcher
+    {
+        public record AccountSetupItem(
+            Guid Id,
+            string Caption,
+            Func<IAccountFactory> CreateInstance
+        );
+
+        private readonly List<AccountSetupItem> setupList;
+
+        public AccountSetupDispatcher()
+        {
+            this.setupList = new()
+            {
+                new(Guid.NewGuid(), "Twitter (OAuth)", () => new TwitterOAuthSetupDialog()),
+                new(Guid.NewGuid(), "Twitter (Cookie)", () => new TwitterCookieSetupDialog()),
+            };
+        }
+
+        public (Guid Id, string Caption)[] GetCaptions()
+            => this.setupList.Select(x => (x.Id, x.Caption)).ToArray();
+
+        public UserAccount? Dispatch(IWin32Window? owner, Guid setupId, Func<IWin32Window?, Uri, Task>? openInBrowser)
+        {
+            var setupItem = this.setupList.First(x => x.Id == setupId);
+
+            using var setup = setupItem.CreateInstance();
+            setup.OpenInBrowser = openInBrowser;
+
+            return setup.ShowAccountSetupDialog(owner);
+        }
+    }
+}
diff --git a/OpenTween/SocialProtocol/IAccountFactory.cs b/OpenTween/SocialProtocol/IAccountFactory.cs
new file mode 100644 (file)
index 0000000..35a9173
--- /dev/null
@@ -0,0 +1,36 @@
+// OpenTween - Client of Twitter
+// Copyright (c) 2024 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+#nullable enable
+
+using System;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace OpenTween.SocialProtocol
+{
+    public interface IAccountFactory : IDisposable
+    {
+        public Func<IWin32Window?, Uri, Task>? OpenInBrowser { get; set; }
+
+        public UserAccount? ShowAccountSetupDialog(IWin32Window? owner);
+    }
+}
index 63d7a41..b4ae263 100644 (file)
 #nullable enable
 
 using System;
+using System.Threading.Tasks;
 using System.Windows.Forms;
 using OpenTween.Api;
 
 namespace OpenTween.SocialProtocol.Twitter
 {
-    public partial class TwitterCookieSetupDialog : OTBaseForm
+    public partial class TwitterCookieSetupDialog : OTBaseForm, IAccountFactory
     {
         public TwitterCookieSetup Model { get; } = new();
 
+        public Func<IWin32Window?, Uri, Task>? OpenInBrowser { get; set; }
+
         public TwitterCookieSetupDialog()
         {
             this.InitializeComponent();
@@ -48,6 +51,15 @@ namespace OpenTween.SocialProtocol.Twitter
             );
         }
 
+        public UserAccount? ShowAccountSetupDialog(IWin32Window? owner)
+        {
+            var ret = this.ShowDialog(owner);
+            if (ret != DialogResult.OK)
+                return null;
+
+            return this.Model.AuthorizedAccount!;
+        }
+
         private async void ButtonOK_Click(object sender, EventArgs e)
         {
             if (MyCommon.IsNullOrEmpty(this.Model.TwitterComCookie))
index eafd1d8..3046e1f 100644 (file)
 
 using System;
 using System.Runtime.InteropServices;
+using System.Threading.Tasks;
 using System.Windows.Forms;
 using OpenTween.Api;
 
 namespace OpenTween.SocialProtocol.Twitter
 {
-    public partial class TwitterOAuthSetupDialog : OTBaseForm
+    public partial class TwitterOAuthSetupDialog : OTBaseForm, IAccountFactory
     {
         public TwitterOAuthSetup Model { get; } = new();
 
+        public Func<IWin32Window?, Uri, Task>? OpenInBrowser { get; set; }
+
         public TwitterOAuthSetupDialog()
         {
             this.InitializeComponent();
@@ -96,6 +99,15 @@ namespace OpenTween.SocialProtocol.Twitter
             );
         }
 
+        public UserAccount? ShowAccountSetupDialog(IWin32Window? owner)
+        {
+            var ret = this.ShowDialog(owner);
+            if (ret != DialogResult.OK)
+                return null;
+
+            return this.Model.AuthorizedAccount!;
+        }
+
         private async void ButtonGetAuthorizeUri_Click(object sender, EventArgs e)
         {
             using (ControlTransaction.Disabled(this))
@@ -123,7 +135,10 @@ namespace OpenTween.SocialProtocol.Twitter
             if (e.Button == MouseButtons.Right)
                 return;
 
-            await MyCommon.OpenInBrowserAsync(this, this.Model.AuthorizeUri);
+            if (this.OpenInBrowser == null)
+                throw new InvalidOperationException($"{nameof(this.OpenInBrowser)} is not set");
+
+            await this.OpenInBrowser(this, this.Model.AuthorizeUri);
         }
 
         private void MenuItemCopyLink_Click(object sender, EventArgs e)