From 08187b0566b2816b6145de0c5a4f638883954dbc Mon Sep 17 00:00:00 2001 From: Kimura Youichi Date: Sun, 19 May 2024 03:13:06 +0900 Subject: [PATCH] =?utf8?q?TwitterOAuthSetupDialog=E3=82=92=E8=BF=BD?= =?utf8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../Twitter/TwitterOAuthSetupDialogTest.cs | 34 ++++ .../SocialProtocol/Twitter/TwitterOAuthSetup.cs | 134 ++++++++++++++ .../Twitter/TwitterOAuthSetupDialog.Designer.cs | 205 +++++++++++++++++++++ .../Twitter/TwitterOAuthSetupDialog.cs | 173 +++++++++++++++++ .../Twitter/TwitterOAuthSetupDialog.en.resx | 17 ++ .../Twitter/TwitterOAuthSetupDialog.resx | 163 ++++++++++++++++ 6 files changed, 726 insertions(+) create mode 100644 OpenTween.Tests/SocialProtocol/Twitter/TwitterOAuthSetupDialogTest.cs create mode 100644 OpenTween/SocialProtocol/Twitter/TwitterOAuthSetup.cs create mode 100644 OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.Designer.cs create mode 100644 OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.cs create mode 100644 OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.en.resx create mode 100644 OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.resx diff --git a/OpenTween.Tests/SocialProtocol/Twitter/TwitterOAuthSetupDialogTest.cs b/OpenTween.Tests/SocialProtocol/Twitter/TwitterOAuthSetupDialogTest.cs new file mode 100644 index 00000000..faf79adb --- /dev/null +++ b/OpenTween.Tests/SocialProtocol/Twitter/TwitterOAuthSetupDialogTest.cs @@ -0,0 +1,34 @@ +// 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. + +using Xunit; + +namespace OpenTween.SocialProtocol.Twitter +{ + public class TwitterOAuthSetupDialogTest + { + [WinFormsFact] + public void Initialize_Test() + { + using var dialog = new TwitterOAuthSetupDialog(); + } + } +} diff --git a/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetup.cs b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetup.cs new file mode 100644 index 00000000..a7920f6d --- /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 00000000..4e383fcd --- /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 00000000..eafd1d80 --- /dev/null +++ b/OpenTween/SocialProtocol/Twitter/TwitterOAuthSetupDialog.cs @@ -0,0 +1,173 @@ +// 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.Windows.Forms; +using OpenTween.Api; + +namespace OpenTween.SocialProtocol.Twitter +{ + public partial class TwitterOAuthSetupDialog : OTBaseForm + { + public TwitterOAuthSetup Model { get; } = new(); + + 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) + ); + } + + 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; + + await MyCommon.OpenInBrowserAsync(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 00000000..0038bfdd --- /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 00000000..37454618 --- /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 + -- 2.11.0