diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 1df31a34d..451e9a19a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -4,6 +4,7 @@ * NEW: Twemoji 15.1.0 に対応しました - Unicode 15.1 で追加された絵文字が表示されるようになります * CHG: 設定画面でのアカウント一覧の表示形式を変更 + * CHG: 新規アカウント追加時のダイアログの構成を変更 * CHG: 新規タブの初回に読み込まれた発言を既読状態にする(起動時の初回の読み込みと同じ動作となる) * CHG: ドメインに x.com が使われている引用ツイートの展開・投稿に対応 * FIX: 発言の削除中にタブを切り替えるとエラーが発生する不具合を修正 (thx @Tan90909090!) diff --git a/OpenTween.Tests/AuthDialogTest.cs b/OpenTween.Tests/SocialProtocol/Twitter/TwitterCookieSetupDialogTest.cs similarity index 77% rename from OpenTween.Tests/AuthDialogTest.cs rename to OpenTween.Tests/SocialProtocol/Twitter/TwitterCookieSetupDialogTest.cs index 58d5ce4f9..ce33b07a1 100644 --- a/OpenTween.Tests/AuthDialogTest.cs +++ b/OpenTween.Tests/SocialProtocol/Twitter/TwitterCookieSetupDialogTest.cs @@ -1,5 +1,5 @@ // OpenTween - Client of Twitter -// Copyright (c) 2023 kim_upsilon (@kim_upsilon) +// Copyright (c) 2024 kim_upsilon (@kim_upsilon) // All rights reserved. // // This file is part of OpenTween. @@ -19,21 +19,16 @@ // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, // Boston, MA 02110-1301, USA. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Xunit; -namespace OpenTween +namespace OpenTween.SocialProtocol.Twitter { - public class AuthDialogTest + public class TwitterCookieSetupDialogTest { [WinFormsFact] public void Initialize_Test() { - using var dialog = new AuthDialog(); + using var dialog = new TwitterCookieSetupDialog(); } } } diff --git a/OpenTween.Tests/AuthTypeSelectDialogTest.cs b/OpenTween.Tests/SocialProtocol/Twitter/TwitterOAuthSetupDialogTest.cs similarity index 76% rename from OpenTween.Tests/AuthTypeSelectDialogTest.cs rename to OpenTween.Tests/SocialProtocol/Twitter/TwitterOAuthSetupDialogTest.cs index 0e897711c..faf79adb8 100644 --- a/OpenTween.Tests/AuthTypeSelectDialogTest.cs +++ b/OpenTween.Tests/SocialProtocol/Twitter/TwitterOAuthSetupDialogTest.cs @@ -1,5 +1,5 @@ // OpenTween - Client of Twitter -// Copyright (c) 2023 kim_upsilon (@kim_upsilon) +// Copyright (c) 2024 kim_upsilon (@kim_upsilon) // All rights reserved. // // This file is part of OpenTween. @@ -19,21 +19,16 @@ // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, // Boston, MA 02110-1301, USA. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Xunit; -namespace OpenTween +namespace OpenTween.SocialProtocol.Twitter { - public class AuthTypeSelectDialogTest + public class TwitterOAuthSetupDialogTest { [WinFormsFact] public void Initialize_Test() { - using var dialog = new AuthTypeSelectDialog(); + using var dialog = new TwitterOAuthSetupDialog(); } } } diff --git a/OpenTween/AppendSettingDialog.cs b/OpenTween/AppendSettingDialog.cs index 9f0939a51..435e76257 100644 --- a/OpenTween/AppendSettingDialog.cs +++ b/OpenTween/AppendSettingDialog.cs @@ -32,7 +32,6 @@ 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 @@ public AppendSettingDialog() { 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 @@ private void UReadMng_CheckedChanged(object sender, EventArgs e) } } - 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); - } - } - } - /// /// 現在設定画面に入力されているネットワーク関係の設定を適用します /// @@ -250,40 +196,10 @@ public void ApplyNetworkSettings() 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 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) diff --git a/OpenTween/AuthDialog.Designer.cs b/OpenTween/AuthDialog.Designer.cs deleted file mode 100644 index d4479fe9e..000000000 --- a/OpenTween/AuthDialog.Designer.cs +++ /dev/null @@ -1,140 +0,0 @@ -namespace OpenTween -{ - partial class AuthDialog - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AuthDialog)); - this.label1 = new System.Windows.Forms.Label(); - this.AuthLinkLabel = new System.Windows.Forms.LinkLabel(); - this.contextMenuLinkLabel = new System.Windows.Forms.ContextMenuStrip(this.components); - this.MenuItemCopyURL = new System.Windows.Forms.ToolStripMenuItem(); - this.label2 = new System.Windows.Forms.Label(); - this.PinTextBox = new System.Windows.Forms.TextBox(); - this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); - this.CancelBtn = new System.Windows.Forms.Button(); - this.OKBtn = new System.Windows.Forms.Button(); - this.contextMenuLinkLabel.SuspendLayout(); - this.tableLayoutPanel1.SuspendLayout(); - this.SuspendLayout(); - // - // label1 - // - resources.ApplyResources(this.label1, "label1"); - this.label1.Name = "label1"; - // - // AuthLinkLabel - // - this.AuthLinkLabel.AutoEllipsis = true; - this.AuthLinkLabel.ContextMenuStrip = this.contextMenuLinkLabel; - resources.ApplyResources(this.AuthLinkLabel, "AuthLinkLabel"); - this.AuthLinkLabel.Name = "AuthLinkLabel"; - this.AuthLinkLabel.TabStop = true; - this.AuthLinkLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.AuthLinkLabel_LinkClicked); - // - // contextMenuLinkLabel - // - this.contextMenuLinkLabel.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.MenuItemCopyURL}); - this.contextMenuLinkLabel.Name = "contextMenuLinkLabel"; - resources.ApplyResources(this.contextMenuLinkLabel, "contextMenuLinkLabel"); - // - // MenuItemCopyURL - // - this.MenuItemCopyURL.Name = "MenuItemCopyURL"; - resources.ApplyResources(this.MenuItemCopyURL, "MenuItemCopyURL"); - this.MenuItemCopyURL.Click += new System.EventHandler(this.MenuItemCopyURL_Click); - // - // label2 - // - resources.ApplyResources(this.label2, "label2"); - this.label2.Name = "label2"; - // - // PinTextBox - // - resources.ApplyResources(this.PinTextBox, "PinTextBox"); - this.PinTextBox.Name = "PinTextBox"; - // - // tableLayoutPanel1 - // - resources.ApplyResources(this.tableLayoutPanel1, "tableLayoutPanel1"); - this.tableLayoutPanel1.Controls.Add(this.CancelBtn, 1, 0); - this.tableLayoutPanel1.Controls.Add(this.OKBtn, 0, 0); - this.tableLayoutPanel1.Name = "tableLayoutPanel1"; - // - // CancelBtn - // - resources.ApplyResources(this.CancelBtn, "CancelBtn"); - this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.CancelBtn.Name = "CancelBtn"; - this.CancelBtn.UseVisualStyleBackColor = true; - // - // OKBtn - // - resources.ApplyResources(this.OKBtn, "OKBtn"); - this.OKBtn.DialogResult = System.Windows.Forms.DialogResult.OK; - this.OKBtn.Name = "OKBtn"; - this.OKBtn.UseVisualStyleBackColor = true; - // - // AuthDialog - // - this.AcceptButton = this.OKBtn; - resources.ApplyResources(this, "$this"); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.CancelButton = this.CancelBtn; - this.Controls.Add(this.tableLayoutPanel1); - this.Controls.Add(this.PinTextBox); - this.Controls.Add(this.label2); - this.Controls.Add(this.AuthLinkLabel); - this.Controls.Add(this.label1); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.Name = "AuthDialog"; - this.ShowIcon = false; - this.ShowInTaskbar = false; - this.contextMenuLinkLabel.ResumeLayout(false); - this.tableLayoutPanel1.ResumeLayout(false); - this.tableLayoutPanel1.PerformLayout(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Label label1; - private System.Windows.Forms.LinkLabel AuthLinkLabel; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.TextBox PinTextBox; - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; - private System.Windows.Forms.Button CancelBtn; - private System.Windows.Forms.Button OKBtn; - private System.Windows.Forms.ContextMenuStrip contextMenuLinkLabel; - private System.Windows.Forms.ToolStripMenuItem MenuItemCopyURL; - } -} \ No newline at end of file diff --git a/OpenTween/AuthDialog.cs b/OpenTween/AuthDialog.cs deleted file mode 100644 index 292656f94..000000000 --- a/OpenTween/AuthDialog.cs +++ /dev/null @@ -1,105 +0,0 @@ -// OpenTween - Client of Twitter -// Copyright (c) 2012 kim_upsilon (@kim_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 , 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.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Windows.Forms; - -namespace OpenTween -{ - /// - /// OAuth認証のPINコードの入力を求めるダイアログ - /// - public partial class AuthDialog : OTBaseForm - { - public AuthDialog() - { - this.InitializeComponent(); - - // PinTextBox のフォントを OTBaseForm.GlobalFont に変更 - this.PinTextBox.Font = this.ReplaceToGlobalFont(this.PinTextBox.Font); - } - - public string AuthUrl - { - get => this.AuthLinkLabel.Text; - set => this.AuthLinkLabel.Text = value; - } - - public string Pin - { - get => this.PinTextBox.Text.Trim(); - set => this.PinTextBox.Text = value; - } - - public string? BrowserPath { get; set; } - - private async void AuthLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - // 右クリックの場合は無視する - if (e.Button == MouseButtons.Right) - return; - - this.AuthLinkLabel.LinkVisited = true; - await MyCommon.OpenInBrowserAsync(this, this.BrowserPath, this.AuthUrl); - } - - private void MenuItemCopyURL_Click(object sender, EventArgs e) - { - try - { - Clipboard.SetText(this.AuthUrl); - } - catch (ExternalException) - { - } - } - - /// - /// 指定されたURLにユーザーがアクセスするように指示してPINを入力させるだけ - /// - /// 親ウィンドウ - /// 認証URL - /// Webブラウザのパス - /// PIN文字列 - public static string? DoAuth(IWin32Window owner, Uri authUri, string? browserPath) - { - using var dialog = new AuthDialog(); - dialog.AuthUrl = authUri.AbsoluteUri; - dialog.BrowserPath = browserPath; - - dialog.ShowDialog(owner); - - if (dialog.DialogResult == DialogResult.OK) - return dialog.Pin; - else - return null; - } - } -} diff --git a/OpenTween/AuthDialog.resx b/OpenTween/AuthDialog.resx deleted file mode 100644 index 9885a533b..000000000 --- a/OpenTween/AuthDialog.resx +++ /dev/null @@ -1,96 +0,0 @@ - - text/microsoft-resx - 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - - 96, 96 - 444, 244 - True - CenterScreen - AuthDialog - AuthDialog - OpenTween.OTBaseForm, OpenTween, Version=2.4.3.1, Culture=neutral, PublicKeyToken=null - AuthLinkLabel - $this - System.Windows.Forms.LinkLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 4 - CancelBtn - tableLayoutPanel1 - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 0 - contextMenuLinkLabel - System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - label1 - $this - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 5 - label2 - $this - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 3 - MenuItemCopyURL - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - OKBtn - tableLayoutPanel1 - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 1 - PinTextBox - $this - System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 2 - tableLayoutPanel1 - $this - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 1 - 24, 69 - 15, 15, 15, 15 - 396, 15 - 1 - linkLabel1 - True - 84, 3 - 86, 25 - 1 - キャンセル (&C) - 148, 26 - 17, 17 - True - 12, 24 - 3, 15, 3, 15 - 352, 12 - 0 - 下記のURLにブラウザでアクセスし、内容を確認の上で認証を行って下さい: - - True - 12, 114 - 3, 15, 3, 15 - 228, 12 - 2 - 認証後に表示されるPINコードを入力して下さい - 147, 22 - URLをコピー (&C) - True - 3, 3 - 75, 25 - 0 - &OK - PINコード - Top, Left, Right - MS UI Gothic, 24pt - 127, 147 - 190, 39 - 3 - Center - Bottom, Right - True - 2 - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="CancelBtn" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="OKBtn" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,AutoSize,0" /><Rows Styles="Percent,100" /></TableLayoutSettings> - 259, 201 - 1 - 173, 31 - 4 - diff --git a/OpenTween/AuthTypeSelectDialog.Designer.cs b/OpenTween/AuthTypeSelectDialog.Designer.cs deleted file mode 100644 index b97c22189..000000000 --- a/OpenTween/AuthTypeSelectDialog.Designer.cs +++ /dev/null @@ -1,150 +0,0 @@ -namespace OpenTween -{ - partial class AuthTypeSelectDialog - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AuthTypeSelectDialog)); - this.label1 = new System.Windows.Forms.Label(); - this.AuthByOAuth2RadioButton = new System.Windows.Forms.RadioButton(); - this.AuthByOAuth1BuiltinKeyRadioButton = new System.Windows.Forms.RadioButton(); - this.AuthByOAuth1RadioButton = new System.Windows.Forms.RadioButton(); - this.label2 = new System.Windows.Forms.Label(); - this.OAuth1ConsumerKeyTextBox = new System.Windows.Forms.TextBox(); - this.label3 = new System.Windows.Forms.Label(); - this.OAuth1ConsumerSecretTextBox = new System.Windows.Forms.TextBox(); - this.UseTwitterComCookieRadioButton = new System.Windows.Forms.RadioButton(); - this.TwitterComCookieTextBox = new System.Windows.Forms.TextBox(); - this.OKButton = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // label1 - // - resources.ApplyResources(this.label1, "label1"); - this.label1.Name = "label1"; - // - // AuthByOAuth2RadioButton - // - resources.ApplyResources(this.AuthByOAuth2RadioButton, "AuthByOAuth2RadioButton"); - this.AuthByOAuth2RadioButton.Name = "AuthByOAuth2RadioButton"; - this.AuthByOAuth2RadioButton.TabStop = true; - this.AuthByOAuth2RadioButton.UseVisualStyleBackColor = true; - // - // AuthByOAuth1BuiltinKeyRadioButton - // - resources.ApplyResources(this.AuthByOAuth1BuiltinKeyRadioButton, "AuthByOAuth1BuiltinKeyRadioButton"); - this.AuthByOAuth1BuiltinKeyRadioButton.Name = "AuthByOAuth1BuiltinKeyRadioButton"; - this.AuthByOAuth1BuiltinKeyRadioButton.TabStop = true; - this.AuthByOAuth1BuiltinKeyRadioButton.UseVisualStyleBackColor = true; - // - // AuthByOAuth1RadioButton - // - resources.ApplyResources(this.AuthByOAuth1RadioButton, "AuthByOAuth1RadioButton"); - this.AuthByOAuth1RadioButton.Name = "AuthByOAuth1RadioButton"; - this.AuthByOAuth1RadioButton.TabStop = true; - this.AuthByOAuth1RadioButton.UseVisualStyleBackColor = true; - // - // label2 - // - resources.ApplyResources(this.label2, "label2"); - this.label2.Name = "label2"; - // - // OAuth1ConsumerKeyTextBox - // - resources.ApplyResources(this.OAuth1ConsumerKeyTextBox, "OAuth1ConsumerKeyTextBox"); - this.OAuth1ConsumerKeyTextBox.Name = "OAuth1ConsumerKeyTextBox"; - // - // label3 - // - resources.ApplyResources(this.label3, "label3"); - this.label3.Name = "label3"; - // - // OAuth1ConsumerSecretTextBox - // - resources.ApplyResources(this.OAuth1ConsumerSecretTextBox, "OAuth1ConsumerSecretTextBox"); - this.OAuth1ConsumerSecretTextBox.Name = "OAuth1ConsumerSecretTextBox"; - // - // UseTwitterComCookieRadioButton - // - resources.ApplyResources(this.UseTwitterComCookieRadioButton, "UseTwitterComCookieRadioButton"); - this.UseTwitterComCookieRadioButton.Name = "UseTwitterComCookieRadioButton"; - this.UseTwitterComCookieRadioButton.TabStop = true; - this.UseTwitterComCookieRadioButton.UseVisualStyleBackColor = true; - // - // TwitterComCookieTextBox - // - resources.ApplyResources(this.TwitterComCookieTextBox, "TwitterComCookieTextBox"); - this.TwitterComCookieTextBox.Name = "TwitterComCookieTextBox"; - // - // OKButton - // - resources.ApplyResources(this.OKButton, "OKButton"); - this.OKButton.Name = "OKButton"; - this.OKButton.UseVisualStyleBackColor = true; - this.OKButton.Click += new System.EventHandler(this.OKButton_Click); - // - // AuthTypeSelectDialog - // - this.AcceptButton = this.OKButton; - resources.ApplyResources(this, "$this"); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.Controls.Add(this.label1); - this.Controls.Add(this.AuthByOAuth2RadioButton); - this.Controls.Add(this.AuthByOAuth1BuiltinKeyRadioButton); - this.Controls.Add(this.AuthByOAuth1RadioButton); - this.Controls.Add(this.label2); - this.Controls.Add(this.OAuth1ConsumerKeyTextBox); - this.Controls.Add(this.label3); - this.Controls.Add(this.OAuth1ConsumerSecretTextBox); - this.Controls.Add(this.UseTwitterComCookieRadioButton); - this.Controls.Add(this.TwitterComCookieTextBox); - this.Controls.Add(this.OKButton); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.Name = "AuthTypeSelectDialog"; - this.ShowIcon = false; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Label label1; - private System.Windows.Forms.RadioButton AuthByOAuth2RadioButton; - private System.Windows.Forms.RadioButton AuthByOAuth1BuiltinKeyRadioButton; - private System.Windows.Forms.RadioButton AuthByOAuth1RadioButton; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.TextBox OAuth1ConsumerKeyTextBox; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.TextBox OAuth1ConsumerSecretTextBox; - private System.Windows.Forms.RadioButton UseTwitterComCookieRadioButton; - private System.Windows.Forms.TextBox TwitterComCookieTextBox; - private System.Windows.Forms.Button OKButton; - } -} \ No newline at end of file diff --git a/OpenTween/AuthTypeSelectDialog.cs b/OpenTween/AuthTypeSelectDialog.cs deleted file mode 100644 index 0961b9803..000000000 --- a/OpenTween/AuthTypeSelectDialog.cs +++ /dev/null @@ -1,78 +0,0 @@ -// OpenTween - Client of Twitter -// Copyright (c) 2023 kim_upsilon (@kim_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 , 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.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; -using OpenTween.Connection; - -namespace OpenTween -{ - public partial class AuthTypeSelectDialog : OTBaseForm - { - public TwitterAppToken? Result { get; private set; } - - public AuthTypeSelectDialog() - => this.InitializeComponent(); - - private void OKButton_Click(object sender, EventArgs e) - { - TwitterAppToken result; - if (this.AuthByOAuth1BuiltinKeyRadioButton.Checked) - { - result = TwitterAppToken.GetDefault(); - } - else if (this.AuthByOAuth1RadioButton.Checked) - { - var consumerKey = this.OAuth1ConsumerKeyTextBox.Text; - var consumerSecret = this.OAuth1ConsumerSecretTextBox.Text; - result = new() - { - AuthType = APIAuthType.OAuth1, - OAuth1CustomConsumerKey = MyCommon.IsNullOrEmpty(consumerKey) ? null : ApiKey.Create(consumerKey), - OAuth1CustomConsumerSecret = MyCommon.IsNullOrEmpty(consumerSecret) ? null : ApiKey.Create(consumerSecret), - }; - } - else if (this.UseTwitterComCookieRadioButton.Checked) - { - result = new() - { - AuthType = APIAuthType.TwitterComCookie, - TwitterComCookie = this.TwitterComCookieTextBox.Text, - }; - } - else - { - return; - } - this.DialogResult = DialogResult.OK; - this.Result = result; - } - } -} diff --git a/OpenTween/AuthTypeSelectDialog.en.resx b/OpenTween/AuthTypeSelectDialog.en.resx deleted file mode 100644 index a8fd37374..000000000 --- a/OpenTween/AuthTypeSelectDialog.en.resx +++ /dev/null @@ -1,18 +0,0 @@ - - text/microsoft-resx - 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 284, 16 - Use OAuth 1.0a (with OpenTween built-in API key) - 103, 16 - Use OAuth 1.0a - 215, 16 - Use OAuth 2.0 (Not implemented yet) - 185, 12 - Choose how to access Twitter API: - 232, 16 - Use cookie of twitter.com (Experimental) - diff --git a/OpenTween/AuthTypeSelectDialog.resx b/OpenTween/AuthTypeSelectDialog.resx deleted file mode 100644 index 35839df3d..000000000 --- a/OpenTween/AuthTypeSelectDialog.resx +++ /dev/null @@ -1,114 +0,0 @@ - - text/microsoft-resx - 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - - 96, 96 - 455, 304 - True - AuthTypeSelectDialog - OpenTween.OTBaseForm, OpenTween, Version=3.4.0.1, Culture=neutral, PublicKeyToken=null - AuthByOAuth1BuiltinKeyRadioButton - $this - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 2 - AuthByOAuth1RadioButton - $this - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 3 - AuthByOAuth2RadioButton - $this - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 1 - label1 - $this - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 0 - label2 - $this - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 4 - label3 - $this - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 6 - OAuth1ConsumerKeyTextBox - $this - System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 5 - OAuth1ConsumerSecretTextBox - $this - System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 7 - OKButton - $this - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 10 - TwitterComCookieTextBox - $this - System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 9 - UseTwitterComCookieRadioButton - $this - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 8 - True - NoControl - 15, 60 - 287, 16 - 2 - OAuth 1.0a を使用する(OpenTweenのAPIキーを使用) - True - 15, 82 - 135, 16 - 3 - OAuth 1.0a を使用する - True - False - 15, 38 - 177, 16 - 1 - OAuth 2.0 を使用する(未実装) - True - 13, 13 - 3, 0, 3, 10 - 238, 12 - 0 - Twitter API にアクセスする方法を選択して下さい: - True - 29, 104 - 20, 3, 3, 3 - 132, 12 - 4 - Consumer Key (API Key) - True - 29, 147 - 3, 3, 3, 3 - 160, 12 - 6 - Consumer Secret (API Secret) - 31, 122 - 400, 19 - 5 - 31, 165 - 400, 19 - 7 - Bottom, Right - 368, 269 - 75, 23 - 10 - OK - 31, 213 - True - 400, 50 - 9 - True - 15, 191 - 236, 16 - 8 - twitter.com の Cookie を使用する(実験的) - diff --git a/OpenTween/OpenTween.csproj b/OpenTween/OpenTween.csproj index f505d8aa3..d1fad48eb 100644 --- a/OpenTween/OpenTween.csproj +++ b/OpenTween/OpenTween.csproj @@ -83,12 +83,6 @@ AppendSettingDialog.cs - - Form - - - AuthDialog.cs - Form @@ -340,12 +334,6 @@ ApiInfoDialog.cs - - AuthDialog.cs - - - AuthDialog.cs - PublicSearchHeaderPanel.cs diff --git a/OpenTween/Setting/Panel/BasedPanel.Designer.cs b/OpenTween/Setting/Panel/BasedPanel.Designer.cs index a111e990f..2aa8e5bb5 100644 --- a/OpenTween/Setting/Panel/BasedPanel.Designer.cs +++ b/OpenTween/Setting/Panel/BasedPanel.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// 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 @@ private void InitializeComponent() 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 @@ private void InitializeComponent() resources.ApplyResources(this.AddAccountButton, "AddAccountButton"); this.AddAccountButton.Name = "AddAccountButton"; this.AddAccountButton.UseVisualStyleBackColor = true; + this.AddAccountButton.Click += new System.EventHandler(this.AddAccountButton_Click); // // RemoveAccountButton // @@ -79,6 +82,11 @@ private void InitializeComponent() resources.ApplyResources(this.panel1, "panel1"); this.panel1.Name = "panel1"; // + // contextMenuAddAccount + // + this.contextMenuAddAccount.Name = "contextMenuAddAccount"; + resources.ApplyResources(this.contextMenuAddAccount, "contextMenuAddAccount"); + // // BasedPanel // resources.ApplyResources(this, "$this"); @@ -98,5 +106,6 @@ private void InitializeComponent() internal System.Windows.Forms.Button RemoveAccountButton; internal System.Windows.Forms.Button MakePrimaryButton; private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.ContextMenuStrip contextMenuAddAccount; } } diff --git a/OpenTween/Setting/Panel/BasedPanel.cs b/OpenTween/Setting/Panel/BasedPanel.cs index 7b9370a69..042b27b66 100644 --- a/OpenTween/Setting/Panel/BasedPanel.cs +++ b/OpenTween/Setting/Panel/BasedPanel.cs @@ -30,6 +30,9 @@ 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 @@ public partial class BasedPanel : SettingPanelBase { internal BindingList AccountsList { get; } = new(); + internal Action? ApplyNetworkSettings { get; set; } + + internal Func? OpenInBrowser { get; set; } + + private readonly AccountSetupDispatcher setupDispatcher = new(); + internal record AccountListBoxItem(UserAccount AccountSettings, bool IsPrimary) { public string DisplayText @@ -61,6 +70,7 @@ public BasedPanel() { this.InitializeComponent(); this.InitializeBinding(); + this.InitializeAddAccountDropdown(); } private void InitializeBinding() @@ -69,6 +79,22 @@ private void InitializeBinding() 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 @@ private void MakeAccountPrimaryAt(int index) 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; diff --git a/OpenTween/Setting/Panel/BasedPanel.resx b/OpenTween/Setting/Panel/BasedPanel.resx index d71e0c3ef..277b059e0 100644 --- a/OpenTween/Setting/Panel/BasedPanel.resx +++ b/OpenTween/Setting/Panel/BasedPanel.resx @@ -24,6 +24,8 @@ panel1 System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 2 + contextMenuAddAccount + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 MakePrimaryButton panel1 System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -31,7 +33,7 @@ panel1 $this System.Windows.Forms.Panel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 0 + 1 RemoveAccountButton panel1 System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -57,6 +59,8 @@ 100, 25 2 追加 + 181, 26 + 17, 17 Top, Right True NoControl diff --git a/OpenTween/SocialProtocol/AccountSetupDispatcher.cs b/OpenTween/SocialProtocol/AccountSetupDispatcher.cs new file mode 100644 index 000000000..6d69d3741 --- /dev/null +++ b/OpenTween/SocialProtocol/AccountSetupDispatcher.cs @@ -0,0 +1,65 @@ +// OpenTween - Client of Twitter +// Copyright (c) 2024 kim_upsilon (@kim_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 , 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 CreateInstance + ); + + private readonly List 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? 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 index 000000000..35a9173c4 --- /dev/null +++ b/OpenTween/SocialProtocol/IAccountFactory.cs @@ -0,0 +1,36 @@ +// OpenTween - Client of Twitter +// Copyright (c) 2024 kim_upsilon (@kim_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 , 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? OpenInBrowser { get; set; } + + public UserAccount? ShowAccountSetupDialog(IWin32Window? owner); + } +} diff --git a/OpenTween/SocialProtocol/Twitter/TwitterCookieSetup.cs b/OpenTween/SocialProtocol/Twitter/TwitterCookieSetup.cs new file mode 100644 index 000000000..c5de15d13 --- /dev/null +++ b/OpenTween/SocialProtocol/Twitter/TwitterCookieSetup.cs @@ -0,0 +1,72 @@ +// OpenTween - Client of Twitter +// Copyright (c) 2024 kim_upsilon (@kim_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 , or write to +// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +// Boston, MA 02110-1301, USA. + +#nullable enable + +using System.Threading.Tasks; +using OpenTween.Api.GraphQL; +using OpenTween.Connection; + +namespace OpenTween.SocialProtocol.Twitter +{ + public class TwitterCookieSetup : NotifyPropertyChangedBase + { + public string TwitterComCookie + { + get => this.twitterComCookie; + set => this.SetProperty(ref this.twitterComCookie, value); + } + + public UserAccount? AuthorizedAccount { get; private set; } + + private string twitterComCookie = ""; + + public async Task DoAuthorize() + { + var credential = new TwitterCredentialCookie(this.GetAppToken()); + using var apiConnection = new TwitterApiConnection(credential, new()); + + var request = new ViewerRequest(); + var graphqlUser = await request.Send(apiConnection) + .ConfigureAwait(false); + + var twitterUser = graphqlUser.ToTwitterUser(); + var authorizedUser = new UserAccount + { + TwitterAuthType = APIAuthType.TwitterComCookie, + TwitterComCookie = this.TwitterComCookie, + UserId = twitterUser.IdStr, + Username = twitterUser.ScreenName, + }; + + this.AuthorizedAccount = authorizedUser; + } + + private TwitterAppToken GetAppToken() + { + return new() + { + AuthType = APIAuthType.TwitterComCookie, + TwitterComCookie = this.TwitterComCookie, + }; + } + } +} diff --git a/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.Designer.cs b/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.Designer.cs new file mode 100644 index 000000000..56417a424 --- /dev/null +++ b/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.Designer.cs @@ -0,0 +1,103 @@ +namespace OpenTween.SocialProtocol.Twitter +{ + partial class TwitterCookieSetupDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TwitterCookieSetupDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.textBoxTwitterComCookie = new System.Windows.Forms.TextBox(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.buttonOK = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.bindingSource = new System.Windows.Forms.BindingSource(this.components); + this.tableLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.bindingSource)).BeginInit(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // textBoxTwitterComCookie + // + resources.ApplyResources(this.textBoxTwitterComCookie, "textBoxTwitterComCookie"); + this.textBoxTwitterComCookie.Name = "textBoxTwitterComCookie"; + // + // tableLayoutPanel1 + // + resources.ApplyResources(this.tableLayoutPanel1, "tableLayoutPanel1"); + this.tableLayoutPanel1.Controls.Add(this.buttonOK, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.buttonCancel, 1, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + // + // buttonOK + // + resources.ApplyResources(this.buttonOK, "buttonOK"); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.ButtonOK_Click); + // + // buttonCancel + // + resources.ApplyResources(this.buttonCancel, "buttonCancel"); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // TwitterCookieSetupDialog + // + this.AcceptButton = this.buttonOK; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.CancelButton = this.buttonCancel; + this.Controls.Add(this.label1); + this.Controls.Add(this.textBoxTwitterComCookie); + this.Controls.Add(this.tableLayoutPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.Name = "TwitterCookieSetupDialog"; + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.bindingSource)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBoxTwitterComCookie; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.BindingSource bindingSource; + } +} \ No newline at end of file diff --git a/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.cs b/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.cs new file mode 100644 index 000000000..b4ae2637e --- /dev/null +++ b/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.cs @@ -0,0 +1,93 @@ +// OpenTween - Client of Twitter +// Copyright (c) 2024 kim_upsilon (@kim_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 , 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; +using OpenTween.Api; + +namespace OpenTween.SocialProtocol.Twitter +{ + public partial class TwitterCookieSetupDialog : OTBaseForm, IAccountFactory + { + public TwitterCookieSetup Model { get; } = new(); + + public Func? OpenInBrowser { get; set; } + + public TwitterCookieSetupDialog() + { + this.InitializeComponent(); + this.InitializeBinding(); + } + + private void InitializeBinding() + { + this.bindingSource.DataSource = this.Model; + + this.textBoxTwitterComCookie.DataBindings.Add( + nameof(TextBox.Text), + this.bindingSource, + nameof(TwitterCookieSetup.TwitterComCookie) + ); + } + + 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)) + return; + + using (ControlTransaction.Disabled(this)) + { + try + { + await this.Model.DoAuthorize(); + + this.DialogResult = DialogResult.OK; + } + catch (WebApiException ex) + { + this.ShowAuthErrorMessage(ex); + } + } + } + + private void ShowAuthErrorMessage(WebApiException ex) + { + var errorBody = ex is TwitterApiException twError + ? string.Join(Environment.NewLine, twError.LongMessages) + : ex.Message; + + var message = Properties.Resources.AuthorizeButton_Click2 + Environment.NewLine + errorBody; + MessageBox.Show(this, message, "Authorize", MessageBoxButtons.OK); + } + } +} diff --git a/OpenTween/AuthDialog.en.resx b/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.en.resx similarity index 51% rename from OpenTween/AuthDialog.en.resx rename to OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.en.resx index 86d01655f..41c27c660 100644 --- a/OpenTween/AuthDialog.en.resx +++ b/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.en.resx @@ -5,13 +5,8 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - &Cancel - 126, 26 - 190, 12 - Access URL bellow in your browser: - 176, 12 - Allow the app and input your PIN: - 125, 22 - &Copy URL - PIN Code + Add Twitter Account + &Cancel + 208, 12 + Paste the cookie of twitter.com (x.com): diff --git a/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.resx b/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.resx new file mode 100644 index 000000000..d1b0ff37b --- /dev/null +++ b/OpenTween/SocialProtocol/Twitter/TwitterCookieSetupDialog.resx @@ -0,0 +1,70 @@ + + text/microsoft-resx + 2.0 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 96, 96 + 500, 149 + True + 10, 10, 10, 10 + Twitterアカウントを追加 + TwitterCookieSetupDialog + OpenTween.OTBaseForm, OpenTween, Version=3.13.0.1, Culture=neutral, PublicKeyToken=null + bindingSource + System.Windows.Forms.BindingSource, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + buttonCancel + tableLayoutPanel1 + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 1 + buttonOK + tableLayoutPanel1 + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 0 + label1 + $this + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 0 + tableLayoutPanel1 + $this + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 2 + textBoxTwitterComCookie + $this + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 1 + 17, 17 + True + NoControl + 84, 3 + 86, 25 + 1 + キャンセル (&C) + True + NoControl + 3, 3 + 75, 25 + 0 + &OK + True + 13, 10 + 194, 12 + 0 + twitter.com (x.com) の Cookie を入力: + Bottom, Right + True + 2 + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="buttonOK" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="buttonCancel" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,AutoSize,0" /><Rows Styles="Percent,100" /></TableLayoutSettings> + 314, 105 + 1 + 173, 31 + 2 + 20, 32 + 10, 10, 10, 10 + True + 460, 60 + 1 + diff --git a/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetup.cs b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetup.cs new file mode 100644 index 000000000..a7920f6d9 --- /dev/null +++ b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetup.cs @@ -0,0 +1,134 @@ +// OpenTween - Client of Twitter +// Copyright (c) 2024 kim_upsilon (@kim_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 , 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 OpenTween.Connection; + +namespace OpenTween.SocialProtocol.Twitter +{ + public class TwitterOAuthSetup : NotifyPropertyChangedBase + { + public bool UseCustomConsumerKey + { + get => this.useCustomConsumerKey; + set => this.SetProperty(ref this.useCustomConsumerKey, value); + } + + public string CustomConsumerKey + { + get => this.customConsumerKey; + set => this.SetProperty(ref this.customConsumerKey, value); + } + + public string CustomConsumerSecret + { + get => this.customConsumerSecret; + set => this.SetProperty(ref this.customConsumerSecret, value); + } + + public Uri? AuthorizeUri + { + get => this.authorizeUri; + private set => this.SetProperty(ref this.authorizeUri, value); + } + + public bool AcquirePinCode + { + get => this.acquirePinCode; + private set => this.SetProperty(ref this.acquirePinCode, value); + } + + public string PinCode + { + get => this.pinCode; + set => this.SetProperty(ref this.pinCode, value); + } + + public UserAccount? AuthorizedAccount { get; private set; } + + private bool useCustomConsumerKey = true; + private string customConsumerKey = ""; + private string customConsumerSecret = ""; + private TwitterCredentialOAuth1? requestToken; + private Uri? authorizeUri = null; + private bool acquirePinCode = false; + private string pinCode = ""; + + public async Task GetAuthorizeUri() + { + var appToken = this.GetAppToken(); + var requestToken = await TwitterApiConnection.GetRequestTokenAsync(appToken); + var authorizeUri = TwitterApiConnection.GetAuthorizeUri(requestToken); + + this.GotoPinCodeStep(requestToken, authorizeUri); + } + + private TwitterAppToken GetAppToken() + { + if (this.UseCustomConsumerKey && + !MyCommon.IsNullOrEmpty(this.CustomConsumerKey) && + !MyCommon.IsNullOrEmpty(this.CustomConsumerSecret)) + { + return new() + { + AuthType = APIAuthType.OAuth1, + OAuth1CustomConsumerKey = ApiKey.Create(this.CustomConsumerKey), + OAuth1CustomConsumerSecret = ApiKey.Create(this.CustomConsumerSecret), + }; + } + + return TwitterAppToken.GetDefault(); + } + + private void GotoPinCodeStep(TwitterCredentialOAuth1 requestToken, Uri authorizeUri) + { + this.requestToken = requestToken; + this.AuthorizeUri = authorizeUri; + this.AcquirePinCode = true; + } + + public async Task DoAuthorize() + { + if (this.requestToken == null) + throw new InvalidOperationException($"{nameof(this.requestToken)} is null"); + + if (MyCommon.IsNullOrEmpty(this.PinCode)) + throw new InvalidOperationException($"{nameof(this.PinCode)} is empty"); + + var accessTokenResponse = await TwitterApiConnection.GetAccessTokenAsync(this.requestToken, this.PinCode); + var authorizedAccount = new UserAccount + { + TwitterAuthType = APIAuthType.OAuth1, + TwitterOAuth1ConsumerKey = this.CustomConsumerKey, + TwitterOAuth1ConsumerSecret = this.CustomConsumerSecret, + Username = accessTokenResponse["screen_name"], + UserId = accessTokenResponse["user_id"], + Token = accessTokenResponse["oauth_token"], + TokenSecret = accessTokenResponse["oauth_token_secret"], + }; + + this.AuthorizedAccount = authorizedAccount; + } + } +} diff --git a/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.Designer.cs b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.Designer.cs new file mode 100644 index 000000000..4e383fcd9 --- /dev/null +++ b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.Designer.cs @@ -0,0 +1,205 @@ +namespace OpenTween.SocialProtocol.Twitter +{ + partial class TwitterOAuthSetupDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TwitterOAuthSetupDialog)); + this.buttonCancel = new System.Windows.Forms.Button(); + this.groupBoxInputConsumerKey = new System.Windows.Forms.GroupBox(); + this.checkBoxUseCustomConsumerKey = new System.Windows.Forms.CheckBox(); + this.label1 = new System.Windows.Forms.Label(); + this.textBoxCustomConsumerKey = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textBoxCustomConsumerSecret = new System.Windows.Forms.TextBox(); + this.buttonGetAuthorizeUri = new System.Windows.Forms.Button(); + this.groupBoxInputPinCode = new System.Windows.Forms.GroupBox(); + this.label3 = new System.Windows.Forms.Label(); + this.linkLabelAuthorize = new System.Windows.Forms.LinkLabel(); + this.contextMenuLinkLabel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.menuItemCopyLink = new System.Windows.Forms.ToolStripMenuItem(); + this.label4 = new System.Windows.Forms.Label(); + this.textBoxPinCode = new System.Windows.Forms.TextBox(); + this.buttonGetAccessToken = new System.Windows.Forms.Button(); + this.bindingSource = new System.Windows.Forms.BindingSource(this.components); + this.groupBoxInputConsumerKey.SuspendLayout(); + this.groupBoxInputPinCode.SuspendLayout(); + this.contextMenuLinkLabel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.bindingSource)).BeginInit(); + this.SuspendLayout(); + // + // buttonCancel + // + resources.ApplyResources(this.buttonCancel, "buttonCancel"); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // groupBoxInputConsumerKey + // + resources.ApplyResources(this.groupBoxInputConsumerKey, "groupBoxInputConsumerKey"); + this.groupBoxInputConsumerKey.Controls.Add(this.checkBoxUseCustomConsumerKey); + this.groupBoxInputConsumerKey.Controls.Add(this.label1); + this.groupBoxInputConsumerKey.Controls.Add(this.textBoxCustomConsumerKey); + this.groupBoxInputConsumerKey.Controls.Add(this.label2); + this.groupBoxInputConsumerKey.Controls.Add(this.textBoxCustomConsumerSecret); + this.groupBoxInputConsumerKey.Controls.Add(this.buttonGetAuthorizeUri); + this.groupBoxInputConsumerKey.Name = "groupBoxInputConsumerKey"; + this.groupBoxInputConsumerKey.TabStop = false; + // + // checkBoxUseCustomConsumerKey + // + resources.ApplyResources(this.checkBoxUseCustomConsumerKey, "checkBoxUseCustomConsumerKey"); + this.checkBoxUseCustomConsumerKey.Name = "checkBoxUseCustomConsumerKey"; + this.checkBoxUseCustomConsumerKey.UseVisualStyleBackColor = true; + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // textBoxCustomConsumerKey + // + resources.ApplyResources(this.textBoxCustomConsumerKey, "textBoxCustomConsumerKey"); + this.textBoxCustomConsumerKey.Name = "textBoxCustomConsumerKey"; + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // textBoxCustomConsumerSecret + // + resources.ApplyResources(this.textBoxCustomConsumerSecret, "textBoxCustomConsumerSecret"); + this.textBoxCustomConsumerSecret.Name = "textBoxCustomConsumerSecret"; + // + // buttonGetAuthorizeUri + // + resources.ApplyResources(this.buttonGetAuthorizeUri, "buttonGetAuthorizeUri"); + this.buttonGetAuthorizeUri.Name = "buttonGetAuthorizeUri"; + this.buttonGetAuthorizeUri.UseVisualStyleBackColor = true; + this.buttonGetAuthorizeUri.Click += new System.EventHandler(this.ButtonGetAuthorizeUri_Click); + // + // groupBoxInputPinCode + // + resources.ApplyResources(this.groupBoxInputPinCode, "groupBoxInputPinCode"); + this.groupBoxInputPinCode.Controls.Add(this.label3); + this.groupBoxInputPinCode.Controls.Add(this.linkLabelAuthorize); + this.groupBoxInputPinCode.Controls.Add(this.label4); + this.groupBoxInputPinCode.Controls.Add(this.textBoxPinCode); + this.groupBoxInputPinCode.Controls.Add(this.buttonGetAccessToken); + this.groupBoxInputPinCode.Name = "groupBoxInputPinCode"; + this.groupBoxInputPinCode.TabStop = false; + // + // label3 + // + resources.ApplyResources(this.label3, "label3"); + this.label3.Name = "label3"; + // + // linkLabelAuthorize + // + resources.ApplyResources(this.linkLabelAuthorize, "linkLabelAuthorize"); + this.linkLabelAuthorize.AutoEllipsis = true; + this.linkLabelAuthorize.ContextMenuStrip = this.contextMenuLinkLabel; + this.linkLabelAuthorize.Name = "linkLabelAuthorize"; + this.linkLabelAuthorize.TabStop = true; + this.linkLabelAuthorize.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelAuthorize_LinkClicked); + // + // contextMenuLinkLabel + // + this.contextMenuLinkLabel.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.menuItemCopyLink}); + this.contextMenuLinkLabel.Name = "contextMenuLinkLabel"; + resources.ApplyResources(this.contextMenuLinkLabel, "contextMenuLinkLabel"); + // + // menuItemCopyLink + // + this.menuItemCopyLink.Name = "menuItemCopyLink"; + resources.ApplyResources(this.menuItemCopyLink, "menuItemCopyLink"); + this.menuItemCopyLink.Click += new System.EventHandler(this.MenuItemCopyLink_Click); + // + // label4 + // + resources.ApplyResources(this.label4, "label4"); + this.label4.Name = "label4"; + // + // textBoxPinCode + // + resources.ApplyResources(this.textBoxPinCode, "textBoxPinCode"); + this.textBoxPinCode.Name = "textBoxPinCode"; + // + // buttonGetAccessToken + // + resources.ApplyResources(this.buttonGetAccessToken, "buttonGetAccessToken"); + this.buttonGetAccessToken.Name = "buttonGetAccessToken"; + this.buttonGetAccessToken.UseVisualStyleBackColor = true; + this.buttonGetAccessToken.Click += new System.EventHandler(this.ButtonGetAccessToken_Click); + // + // TwitterOAuthSetupDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.CancelButton = this.buttonCancel; + this.Controls.Add(this.groupBoxInputConsumerKey); + this.Controls.Add(this.groupBoxInputPinCode); + this.Controls.Add(this.buttonCancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.Name = "TwitterOAuthSetupDialog"; + this.groupBoxInputConsumerKey.ResumeLayout(false); + this.groupBoxInputConsumerKey.PerformLayout(); + this.groupBoxInputPinCode.ResumeLayout(false); + this.groupBoxInputPinCode.PerformLayout(); + this.contextMenuLinkLabel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.bindingSource)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.GroupBox groupBoxInputConsumerKey; + private System.Windows.Forms.CheckBox checkBoxUseCustomConsumerKey; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBoxCustomConsumerKey; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textBoxCustomConsumerSecret; + private System.Windows.Forms.Button buttonGetAuthorizeUri; + private System.Windows.Forms.GroupBox groupBoxInputPinCode; + private System.Windows.Forms.LinkLabel linkLabelAuthorize; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox textBoxPinCode; + private System.Windows.Forms.Button buttonGetAccessToken; + private System.Windows.Forms.ContextMenuStrip contextMenuLinkLabel; + private System.Windows.Forms.ToolStripMenuItem menuItemCopyLink; + private System.Windows.Forms.BindingSource bindingSource; + } +} \ No newline at end of file diff --git a/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.cs b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.cs new file mode 100644 index 000000000..3046e1f25 --- /dev/null +++ b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.cs @@ -0,0 +1,188 @@ +// OpenTween - Client of Twitter +// Copyright (c) 2024 kim_upsilon (@kim_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 , or write to +// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +// Boston, MA 02110-1301, USA. + +#nullable enable + +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, IAccountFactory + { + public TwitterOAuthSetup Model { get; } = new(); + + public Func? OpenInBrowser { get; set; } + + public TwitterOAuthSetupDialog() + { + this.InitializeComponent(); + this.InitializeBinding(); + + // textBoxPinCode のフォントを OTBaseForm.GlobalFont に変更 + this.textBoxPinCode.Font = this.ReplaceToGlobalFont(this.textBoxPinCode.Font); + } + + private void InitializeBinding() + { + this.bindingSource.DataSource = this.Model; + + this.checkBoxUseCustomConsumerKey.DataBindings.Add( + nameof(CheckBox.Checked), + this.bindingSource, + nameof(TwitterOAuthSetup.UseCustomConsumerKey), + formattingEnabled: false, + DataSourceUpdateMode.OnPropertyChanged + ); + + this.textBoxCustomConsumerKey.DataBindings.Add( + nameof(TextBox.Enabled), + this.bindingSource, + nameof(TwitterOAuthSetup.UseCustomConsumerKey) + ); + + this.textBoxCustomConsumerKey.DataBindings.Add( + nameof(TextBox.Text), + this.bindingSource, + nameof(TwitterOAuthSetup.CustomConsumerKey) + ); + + this.textBoxCustomConsumerSecret.DataBindings.Add( + nameof(TextBox.Enabled), + this.bindingSource, + nameof(TwitterOAuthSetup.UseCustomConsumerKey) + ); + + this.textBoxCustomConsumerSecret.DataBindings.Add( + nameof(TextBox.Text), + this.bindingSource, + nameof(TwitterOAuthSetup.CustomConsumerSecret) + ); + + this.groupBoxInputPinCode.DataBindings.Add( + nameof(GroupBox.Enabled), + this.bindingSource, + nameof(TwitterOAuthSetup.AcquirePinCode) + ); + + this.linkLabelAuthorize.DataBindings.Add( + nameof(LinkLabel.Text), + this.bindingSource, + nameof(TwitterOAuthSetup.AuthorizeUri) + ); + + this.textBoxPinCode.DataBindings.Add( + nameof(TextBox.Text), + this.bindingSource, + nameof(TwitterOAuthSetup.PinCode) + ); + } + + 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)) + { + try + { + await this.Model.GetAuthorizeUri(); + } + catch (WebApiException ex) + { + this.ShowAuthErrorMessage(ex); + } + } + + if (this.Model.AcquirePinCode) + this.groupBoxInputPinCode.Focus(); + } + + private async void LinkLabelAuthorize_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (this.Model.AuthorizeUri == null) + return; + + // 右クリックの場合は無視する + if (e.Button == MouseButtons.Right) + return; + + 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) + { + if (this.Model.AuthorizeUri == null) + return; + + try + { + Clipboard.SetText(this.Model.AuthorizeUri.ToString()); + } + catch (ExternalException) + { + } + } + + private async void ButtonGetAccessToken_Click(object sender, EventArgs e) + { + if (MyCommon.IsNullOrEmpty(this.Model.PinCode)) + return; + + using (ControlTransaction.Disabled(this)) + { + try + { + await this.Model.DoAuthorize(); + + this.DialogResult = DialogResult.OK; + } + catch (WebApiException ex) + { + this.ShowAuthErrorMessage(ex); + } + } + } + + private void ShowAuthErrorMessage(WebApiException ex) + { + var errorBody = ex is TwitterApiException twError + ? string.Join(Environment.NewLine, twError.LongMessages) + : ex.Message; + + var message = Properties.Resources.AuthorizeButton_Click2 + Environment.NewLine + errorBody; + MessageBox.Show(this, message, "Authorize", MessageBoxButtons.OK); + } + } +} diff --git a/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.en.resx b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.en.resx new file mode 100644 index 000000000..0038bfdd4 --- /dev/null +++ b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.en.resx @@ -0,0 +1,17 @@ + + text/microsoft-resx + 2.0 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Add Twitter Account + &Cancel + Continue + 160, 16 + Use custom consumer key + 166, 12 + Open below url in your browser: + 268, 12 + Please enter the PIN code displayed after approval: + diff --git a/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.resx b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.resx new file mode 100644 index 000000000..37454618a --- /dev/null +++ b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.resx @@ -0,0 +1,163 @@ + + text/microsoft-resx + 2.0 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 96, 96 + 500, 425 + True + Twitterアカウントを追加 + TwitterOAuthSetupDialog + OpenTween.OTBaseForm, OpenTween, Version=3.13.0.1, Culture=neutral, PublicKeyToken=null + bindingSource + System.Windows.Forms.BindingSource, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + buttonCancel + $this + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 3 + buttonGetAccessToken + groupBoxInputPinCode + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 4 + buttonGetAuthorizeUri + groupBoxInputConsumerKey + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 5 + checkBoxUseCustomConsumerKey + groupBoxInputConsumerKey + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 0 + contextMenuLinkLabel + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + groupBoxInputConsumerKey + $this + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 1 + groupBoxInputPinCode + $this + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 2 + label1 + groupBoxInputConsumerKey + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 1 + label2 + groupBoxInputConsumerKey + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 3 + label3 + groupBoxInputPinCode + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 0 + label4 + groupBoxInputPinCode + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 2 + linkLabelAuthorize + groupBoxInputPinCode + System.Windows.Forms.LinkLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 1 + menuItemCopyLink + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + textBoxCustomConsumerKey + groupBoxInputConsumerKey + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 2 + textBoxCustomConsumerSecret + groupBoxInputConsumerKey + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 4 + textBoxPinCode + groupBoxInputPinCode + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + 3 + 192, 17 + Bottom, Right + True + 398, 390 + 90, 23 + 2 + キャンセル (&C) + Bottom, Right + NoControl + 362, 152 + 100, 23 + 4 + OK + Bottom, Right + 362, 140 + 3, 10, 3, 3 + 100, 23 + 5 + 次へ進む + True + 13, 25 + 188, 16 + 0 + Consumer Key を自分で指定する + 148, 26 + 17, 17 + Top, Left, Right + 13, 13 + 10, 10, 10, 10 + 475, 176 + 0 + Step 1 + Top, Left, Right + 13, 196 + 10, 10, 10, 10 + 475, 188 + 1 + Step 2 + True + NoControl + 30, 47 + 20, 3, 3, 3 + 132, 12 + 1 + Consumer Key (API Key) + True + NoControl + 30, 90 + 3, 3, 3, 3 + 160, 12 + 3 + Consumer Secret (API Secret) + True + 14, 26 + 351, 12 + 0 + 以下のURLにアクセスし、内容を確認してアプリとの連携を許可してください: + True + 13, 83 + 241, 12 + 2 + 認可後に表示される PIN コードを入力してください: + Top, Left, Right + 25, 53 + 15, 15, 15, 15 + 425, 15 + 1 + linkLabel + MiddleLeft + 147, 22 + URLをコピー (&C) + 32, 65 + 430, 19 + 2 + 32, 108 + 430, 19 + 4 + PINコード + Top, Left, Right + MS UI Gothic, 24pt + 142, 105 + 10, 10, 10, 5 + 190, 39 + 3 + Center +