1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 // (c) 2008-2011 Moz (@syo68k)
4 // (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 // (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 // (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 // (c) 2011 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
8 // All rights reserved.
10 // This file is part of OpenTween.
12 // This program is free software; you can redistribute it and/or modify it
13 // under the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 3 of the License, or (at your option)
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
24 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
25 // Boston, MA 02110-1301, USA.
28 using System.Collections.Generic;
29 using System.ComponentModel;
34 using System.Threading.Tasks;
35 using System.Windows.Forms;
36 using System.Text.RegularExpressions;
44 public partial class UserInfoDialog : OTBaseForm
46 private TwitterUser _displayUser;
48 private readonly TweenMain mainForm;
49 private readonly Twitter twitter;
51 public UserInfoDialog(TweenMain mainForm, Twitter twitter)
53 this.mainForm = mainForm;
54 this.twitter = twitter;
56 InitializeComponent();
58 // LabelScreenName のフォントを OTBaseForm.GlobalFont に変更
59 this.LabelScreenName.Font = this.ReplaceToGlobalFont(this.LabelScreenName.Font);
62 public async Task ShowUserAsync(TwitterUser user)
64 if (user == null || user == this._displayUser)
67 this._displayUser = user;
69 this.LabelId.Text = user.IdStr;
70 this.LabelScreenName.Text = user.ScreenName;
71 this.LabelName.Text = WebUtility.HtmlDecode(user.Name);
72 this.LabelLocation.Text = user.Location ?? "";
73 this.LabelCreatedAt.Text = MyCommon.DateTimeParse(user.CreatedAt).ToString();
76 this.LabelIsProtected.Text = Properties.Resources.Yes;
78 this.LabelIsProtected.Text = Properties.Resources.No;
81 this.LabelIsVerified.Text = Properties.Resources.Yes;
83 this.LabelIsVerified.Text = Properties.Resources.No;
85 var followingUrl = "https://twitter.com/" + user.ScreenName + "/following";
86 this.LinkLabelFollowing.Text = user.FriendsCount.ToString();
87 this.LinkLabelFollowing.Tag = followingUrl;
88 this.ToolTip1.SetToolTip(this.LinkLabelFollowing, followingUrl);
90 var followersUrl = "https://twitter.com/" + user.ScreenName + "/followers";
91 this.LinkLabelFollowers.Text = user.FollowersCount.ToString();
92 this.LinkLabelFollowers.Tag = followersUrl;
93 this.ToolTip1.SetToolTip(this.LinkLabelFollowers, followersUrl);
95 var favoritesUrl = "https://twitter.com/" + user.ScreenName + "/favorites";
96 this.LinkLabelFav.Text = user.FavouritesCount.ToString();
97 this.LinkLabelFav.Tag = favoritesUrl;
98 this.ToolTip1.SetToolTip(this.LinkLabelFav, favoritesUrl);
100 var profileUrl = "https://twitter.com/" + user.ScreenName;
101 this.LinkLabelTweet.Text = user.StatusesCount.ToString();
102 this.LinkLabelTweet.Tag = profileUrl;
103 this.ToolTip1.SetToolTip(this.LinkLabelTweet, profileUrl);
105 if (this.twitter.UserId == user.Id)
107 this.ButtonEdit.Enabled = true;
108 this.ChangeIconToolStripMenuItem.Enabled = true;
109 this.ButtonBlock.Enabled = false;
110 this.ButtonReportSpam.Enabled = false;
111 this.ButtonBlockDestroy.Enabled = false;
115 this.ButtonEdit.Enabled = false;
116 this.ChangeIconToolStripMenuItem.Enabled = false;
117 this.ButtonBlock.Enabled = true;
118 this.ButtonReportSpam.Enabled = true;
119 this.ButtonBlockDestroy.Enabled = true;
122 await Task.WhenAll(new[]
124 this.SetDescriptionAsync(user.Description),
125 this.SetRecentStatusAsync(user.Status),
126 this.SetLinkLabelWebAsync(user.Url),
127 this.SetUserImageAsync(user.ProfileImageUrlHttps),
128 this.LoadFriendshipAsync(user.ScreenName),
132 private async Task SetDescriptionAsync(string descriptionText)
134 if (descriptionText != null)
136 var atlist = new List<string>();
138 var html = WebUtility.HtmlEncode(descriptionText);
139 html = await this.twitter.CreateHtmlAnchorAsync(html, atlist, null);
140 html = this.mainForm.createDetailHtml(html);
142 this.DescriptionBrowser.DocumentText = html;
146 this.DescriptionBrowser.DocumentText = "";
150 private async Task SetUserImageAsync(string imageUri)
152 var oldImage = this.UserPicture.Image;
153 if (oldImage != null)
155 this.UserPicture.Image = null;
159 // ProfileImageUrlHttps が null になる場合があるらしい
160 // 参照: https://sourceforge.jp/ticket/browse.php?group_id=6526&tid=33871
161 if (imageUri == null)
164 await this.UserPicture.SetImageFromTask(async () =>
166 using (var http = MyCommon.CreateHttpClient())
168 var imageStream = await http.GetStreamAsync(imageUri.Replace("_normal", "_bigger"))
169 .ConfigureAwait(false);
171 return await MemoryImage.CopyFromStreamAsync(imageStream)
172 .ConfigureAwait(false);
177 private async Task SetLinkLabelWebAsync(string uri)
181 var expandedUrl = await ShortUrl.Instance.ExpandUrlAsync(uri);
183 this.LinkLabelWeb.Text = uri;
184 this.LinkLabelWeb.Tag = expandedUrl;
185 this.ToolTip1.SetToolTip(this.LinkLabelWeb, expandedUrl);
189 this.LinkLabelWeb.Text = "";
190 this.LinkLabelWeb.Tag = null;
191 this.ToolTip1.SetToolTip(this.LinkLabelWeb, null);
195 private async Task SetRecentStatusAsync(TwitterStatus status)
197 var atlist = new List<string>();
201 var html = await this.twitter.CreateHtmlAnchorAsync(status.Text, atlist, status.MergedEntities, null);
202 html = this.mainForm.createDetailHtml(html +
203 " Posted at " + MyCommon.DateTimeParse(status.CreatedAt) +
204 " via " + status.Source);
206 this.RecentPostBrowser.DocumentText = html;
210 this.RecentPostBrowser.DocumentText = Properties.Resources.ShowUserInfo2;
214 private async Task LoadFriendshipAsync(string screenName)
216 this.LabelIsFollowing.Text = "";
217 this.LabelIsFollowed.Text = "";
218 this.ButtonFollow.Enabled = false;
219 this.ButtonUnFollow.Enabled = false;
221 if (this.twitter.Username == screenName)
224 var friendship = await Task.Run(() =>
226 var IsFollowing = false;
227 var IsFollowedBy = false;
229 var ret = this.twitter.GetFriendshipInfo(screenName, ref IsFollowing, ref IsFollowedBy);
230 if (!string.IsNullOrEmpty(ret))
233 return new { IsFollowing, IsFollowedBy };
236 if (friendship == null)
238 LabelIsFollowed.Text = Properties.Resources.GetFriendshipInfo6;
239 LabelIsFollowing.Text = Properties.Resources.GetFriendshipInfo6;
243 this.LabelIsFollowing.Text = friendship.IsFollowing
244 ? Properties.Resources.GetFriendshipInfo1
245 : Properties.Resources.GetFriendshipInfo2;
247 this.LabelIsFollowed.Text = friendship.IsFollowedBy
248 ? Properties.Resources.GetFriendshipInfo3
249 : Properties.Resources.GetFriendshipInfo4;
251 this.ButtonFollow.Enabled = !friendship.IsFollowing;
252 this.ButtonUnFollow.Enabled = friendship.IsFollowing;
255 private void ShowUserInfo_Load(object sender, EventArgs e)
257 this.TextBoxName.Location = this.LabelName.Location;
258 this.TextBoxName.Height = this.LabelName.Height;
259 this.TextBoxName.Width = this.LabelName.Width;
260 this.TextBoxName.BackColor = this.mainForm.InputBackColor;
261 this.TextBoxName.MaxLength = 20;
263 this.TextBoxLocation.Location = this.LabelLocation.Location;
264 this.TextBoxLocation.Height = this.LabelLocation.Height;
265 this.TextBoxLocation.Width = this.LabelLocation.Width;
266 this.TextBoxLocation.BackColor = this.mainForm.InputBackColor;
267 this.TextBoxLocation.MaxLength = 30;
269 this.TextBoxWeb.Location = this.LinkLabelWeb.Location;
270 this.TextBoxWeb.Height = this.LinkLabelWeb.Height;
271 this.TextBoxWeb.Width = this.LinkLabelWeb.Width;
272 this.TextBoxWeb.BackColor = this.mainForm.InputBackColor;
273 this.TextBoxWeb.MaxLength = 100;
275 this.TextBoxDescription.Location = this.DescriptionBrowser.Location;
276 this.TextBoxDescription.Height = this.DescriptionBrowser.Height;
277 this.TextBoxDescription.Width = this.DescriptionBrowser.Width;
278 this.TextBoxDescription.BackColor = this.mainForm.InputBackColor;
279 this.TextBoxDescription.MaxLength = 160;
280 this.TextBoxDescription.Multiline = true;
281 this.TextBoxDescription.ScrollBars = ScrollBars.Vertical;
284 private async void LinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
286 var linkLabel = (LinkLabel)sender;
288 var linkUrl = (string)linkLabel.Tag;
292 await this.mainForm.OpenUriAsync(linkUrl);
295 private void ButtonFollow_Click(object sender, EventArgs e)
297 string ret = this.twitter.PostFollowCommand(this._displayUser.ScreenName);
298 if (!string.IsNullOrEmpty(ret))
300 MessageBox.Show(Properties.Resources.FRMessage2 + ret);
304 MessageBox.Show(Properties.Resources.FRMessage3);
305 LabelIsFollowing.Text = Properties.Resources.GetFriendshipInfo1;
306 ButtonFollow.Enabled = false;
307 ButtonUnFollow.Enabled = true;
311 private void ButtonUnFollow_Click(object sender, EventArgs e)
313 if (MessageBox.Show(this._displayUser.ScreenName + Properties.Resources.ButtonUnFollow_ClickText1,
314 Properties.Resources.ButtonUnFollow_ClickText2,
315 MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
317 string ret = this.twitter.PostRemoveCommand(this._displayUser.ScreenName);
318 if (!string.IsNullOrEmpty(ret))
320 MessageBox.Show(Properties.Resources.FRMessage2 + ret);
324 MessageBox.Show(Properties.Resources.FRMessage3);
325 LabelIsFollowing.Text = Properties.Resources.GetFriendshipInfo2;
326 ButtonFollow.Enabled = true;
327 ButtonUnFollow.Enabled = false;
332 private void ShowUserInfo_Activated(object sender, EventArgs e)
334 //画面が他画面の裏に隠れると、アイコン画像が再描画されない問題の対応
335 if (UserPicture.Image != null)
336 UserPicture.Invalidate(false);
339 private void ShowUserInfo_Shown(object sender, EventArgs e)
344 private void WebBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
346 if (e.Url.AbsoluteUri != "about:blank")
350 if (e.Url.AbsoluteUri.StartsWith("http://twitter.com/search?q=%23") ||
351 e.Url.AbsoluteUri.StartsWith("https://twitter.com/search?q=%23"))
354 string urlStr = Uri.UnescapeDataString(e.Url.AbsoluteUri);
355 string hash = urlStr.Substring(urlStr.IndexOf("#"));
356 this.mainForm.HashSupl.AddItem(hash);
357 this.mainForm.HashMgr.AddHashToHistory(hash.Trim(), false);
358 this.mainForm.AddNewTabForSearch(hash);
363 Match m = Regex.Match(e.Url.AbsoluteUri, @"^https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)$");
364 if (AppendSettingDialog.Instance.OpenUserTimeline && m.Success && this.mainForm.IsTwitterId(m.Result("${ScreenName}")))
366 this.mainForm.AddNewTabForUserTimeline(m.Result("${ScreenName}"));
370 this.mainForm.OpenUriAsync(e.Url.OriginalString);
376 private void SelectAllToolStripMenuItem_Click(object sender, EventArgs e)
378 var browser = (WebBrowser)this.ContextMenuRecentPostBrowser.SourceControl;
379 browser.Document.ExecCommand("SelectAll", false, null);
382 private void SelectionCopyToolStripMenuItem_Click(object sender, EventArgs e)
384 var browser = (WebBrowser)this.ContextMenuRecentPostBrowser.SourceControl;
385 var selectedText = this.mainForm.WebBrowser_GetSelectionText(ref browser);
386 if (selectedText != null)
390 Clipboard.SetDataObject(selectedText, false, 5, 100);
394 MessageBox.Show(ex.Message);
399 private void ContextMenuRecentPostBrowser_Opening(object sender, CancelEventArgs e)
401 var browser = (WebBrowser)this.ContextMenuRecentPostBrowser.SourceControl;
402 var selectedText = this.mainForm.WebBrowser_GetSelectionText(ref browser);
404 this.SelectionCopyToolStripMenuItem.Enabled = selectedText != null;
407 private void LinkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
409 this.mainForm.OpenUriAsync("https://support.twitter.com/groups/31-twitter-basics/topics/111-features/articles/268350-x8a8d-x8a3c-x6e08-x307f-x30a2-x30ab-x30a6-x30f3-x30c8-x306b-x3064-x3044-x3066");
412 private void LinkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
414 this.mainForm.OpenUriAsync("https://support.twitter.com/groups/31-twitter-basics/topics/107-my-profile-account-settings/articles/243055-x516c-x958b-x3001-x975e-x516c-x958b-x30a2-x30ab-x30a6-x30f3-x30c8-x306b-x3064-x3044-x3066");
417 private void ButtonSearchPosts_Click(object sender, EventArgs e)
419 this.mainForm.AddNewTabForUserTimeline(this._displayUser.ScreenName);
422 private async void UserPicture_Click(object sender, EventArgs e)
424 var imageUrl = this._displayUser.ProfileImageUrlHttps;
425 imageUrl = imageUrl.Remove(imageUrl.LastIndexOf("_normal"), 7);
427 await this.mainForm.OpenUriAsync(imageUrl);
430 private bool IsEditing = false;
431 private string ButtonEditText = "";
433 private async void ButtonEdit_Click(object sender, EventArgs e)
435 // 自分以外のプロフィールは変更できない
436 if (this.twitter.UserId != this._displayUser.Id)
439 this.ButtonEdit.Enabled = false;
443 ButtonEditText = ButtonEdit.Text;
444 ButtonEdit.Text = Properties.Resources.UserInfoButtonEdit_ClickText1;
446 TextBoxName.Text = LabelName.Text;
447 TextBoxName.Enabled = true;
448 TextBoxName.Visible = true;
449 LabelName.Visible = false;
451 TextBoxLocation.Text = LabelLocation.Text;
452 TextBoxLocation.Enabled = true;
453 TextBoxLocation.Visible = true;
454 LabelLocation.Visible = false;
456 TextBoxWeb.Text = this._displayUser.Url;
457 TextBoxWeb.Enabled = true;
458 TextBoxWeb.Visible = true;
459 LinkLabelWeb.Visible = false;
461 TextBoxDescription.Text = this._displayUser.Description;
462 TextBoxDescription.Enabled = true;
463 TextBoxDescription.Visible = true;
464 DescriptionBrowser.Visible = false;
467 TextBoxName.Select(TextBoxName.Text.Length, 0);
473 Task showUserTask = null;
475 if (TextBoxName.Modified ||
476 TextBoxLocation.Modified ||
477 TextBoxWeb.Modified ||
478 TextBoxDescription.Modified)
482 var user = await Task.Run(() =>
483 this.twitter.PostUpdateProfile(
484 this.TextBoxName.Text,
485 this.TextBoxWeb.Text,
486 this.TextBoxLocation.Text,
487 this.TextBoxDescription.Text));
489 showUserTask = this.ShowUserAsync(user);
491 catch (WebApiException ex)
493 MessageBox.Show(ex.Message);
498 TextBoxName.Enabled = false;
499 TextBoxName.Visible = false;
500 LabelName.Visible = true;
502 TextBoxLocation.Enabled = false;
503 TextBoxLocation.Visible = false;
504 LabelLocation.Visible = true;
506 TextBoxWeb.Enabled = false;
507 TextBoxWeb.Visible = false;
508 LinkLabelWeb.Visible = true;
510 TextBoxDescription.Enabled = false;
511 TextBoxDescription.Visible = false;
512 DescriptionBrowser.Visible = true;
514 ButtonEdit.Text = ButtonEditText;
518 if (showUserTask != null)
522 this.ButtonEdit.Enabled = true;
525 private async Task DoChangeIcon(string filename)
527 var ret = await Task.Run(() =>
528 this.twitter.PostUpdateProfileImage(filename));
530 if (!string.IsNullOrEmpty(ret))
532 // "Err:"が付いたエラーメッセージが返ってくる
533 MessageBox.Show(ret + Environment.NewLine + Properties.Resources.ChangeIconToolStripMenuItem_ClickText4);
537 MessageBox.Show(Properties.Resources.ChangeIconToolStripMenuItem_ClickText5);
542 var user = await Task.Run(() =>
544 TwitterUser result = null;
546 var err = this.twitter.GetUserInfo(this._displayUser.ScreenName, ref result);
547 if (!string.IsNullOrEmpty(err))
548 throw new WebApiException(err);
554 await this.ShowUserAsync(user);
556 catch (WebApiException ex)
558 MessageBox.Show(ex.Message);
562 private async void ChangeIconToolStripMenuItem_Click(object sender, EventArgs e)
564 OpenFileDialogIcon.Filter = Properties.Resources.ChangeIconToolStripMenuItem_ClickText1;
565 OpenFileDialogIcon.Title = Properties.Resources.ChangeIconToolStripMenuItem_ClickText2;
566 OpenFileDialogIcon.FileName = "";
568 DialogResult rslt = OpenFileDialogIcon.ShowDialog();
570 if (rslt != DialogResult.OK)
575 string fn = OpenFileDialogIcon.FileName;
576 if (this.IsValidIconFile(new FileInfo(fn)))
578 await this.DoChangeIcon(fn);
582 MessageBox.Show(Properties.Resources.ChangeIconToolStripMenuItem_ClickText6);
586 private void ButtonBlock_Click(object sender, EventArgs e)
588 if (MessageBox.Show(this._displayUser.ScreenName + Properties.Resources.ButtonBlock_ClickText1,
589 Properties.Resources.ButtonBlock_ClickText2,
590 MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
592 string res = this.twitter.PostCreateBlock(this._displayUser.ScreenName);
593 if (!string.IsNullOrEmpty(res))
595 MessageBox.Show(res + Environment.NewLine + Properties.Resources.ButtonBlock_ClickText3);
599 MessageBox.Show(Properties.Resources.ButtonBlock_ClickText4);
604 private void ButtonReportSpam_Click(object sender, EventArgs e)
606 if (MessageBox.Show(this._displayUser.ScreenName + Properties.Resources.ButtonReportSpam_ClickText1,
607 Properties.Resources.ButtonReportSpam_ClickText2,
608 MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
610 string res = this.twitter.PostReportSpam(this._displayUser.ScreenName);
611 if (!string.IsNullOrEmpty(res))
613 MessageBox.Show(res + Environment.NewLine + Properties.Resources.ButtonReportSpam_ClickText3);
617 MessageBox.Show(Properties.Resources.ButtonReportSpam_ClickText4);
622 private void ButtonBlockDestroy_Click(object sender, EventArgs e)
624 if (MessageBox.Show(this._displayUser.ScreenName + Properties.Resources.ButtonBlockDestroy_ClickText1,
625 Properties.Resources.ButtonBlockDestroy_ClickText2,
626 MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
628 string res = this.twitter.PostDestroyBlock(this._displayUser.ScreenName);
629 if (!string.IsNullOrEmpty(res))
631 MessageBox.Show(res + Environment.NewLine + Properties.Resources.ButtonBlockDestroy_ClickText3);
635 MessageBox.Show(Properties.Resources.ButtonBlockDestroy_ClickText4);
640 private bool IsValidExtension(string ext)
644 return ext.Equals(".jpg", StringComparison.Ordinal) ||
645 ext.Equals(".jpeg", StringComparison.Ordinal) ||
646 ext.Equals(".png", StringComparison.Ordinal) ||
647 ext.Equals(".gif", StringComparison.Ordinal);
650 private bool IsValidIconFile(FileInfo info)
652 return this.IsValidExtension(info.Extension) &&
653 info.Length < 700 * 1024 &&
654 !MyCommon.IsAnimatedGif(info.FullName);
657 private void ShowUserInfo_DragOver(object sender, DragEventArgs e)
659 if (e.Data.GetDataPresent(DataFormats.FileDrop))
661 var files = (string[])e.Data.GetData(DataFormats.FileDrop, false);
662 if (files.Length != 1)
665 var finfo = new FileInfo(files[0]);
666 if (this.IsValidIconFile(finfo))
668 e.Effect = DragDropEffects.Copy;
673 private async void ShowUserInfo_DragDrop(object sender, DragEventArgs e)
675 if (e.Data.GetDataPresent(DataFormats.FileDrop))
677 string filename = ((string[])e.Data.GetData(DataFormats.FileDrop, false))[0];
678 await this.DoChangeIcon(filename);
682 protected override void Dispose(bool disposing)
686 var oldImage = this.UserPicture.Image;
687 if (oldImage != null)
689 this.UserPicture.Image = null;
693 if (this.components != null)
694 this.components.Dispose();
697 base.Dispose(disposing);