OSDN Git Service

C# 8.0 のnull許容参照型を有効化
[opentween/open-tween.git] / OpenTween / ListManage.cs
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.
9 // 
10 // This file is part of OpenTween.
11 // 
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)
15 // any later version.
16 // 
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
20 // for more details. 
21 // 
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.
26
27 #nullable enable
28
29 using System;
30 using System.Collections.Generic;
31 using System.ComponentModel;
32 using System.Data;
33 using System.Drawing;
34 using System.Linq;
35 using System.Text;
36 using System.Threading.Tasks;
37 using System.Windows.Forms;
38 using OpenTween.Connection;
39 using OpenTween.Models;
40
41 namespace OpenTween
42 {
43     public partial class ListManage : OTBaseForm
44     {
45         private readonly Twitter tw;
46
47         public ListManage(Twitter tw)
48         {
49             InitializeComponent();
50
51             this.tw = tw;
52         }
53
54         private void ListManage_KeyDown(object sender, KeyEventArgs e)
55         {
56             if (e.KeyCode == Keys.Enter && this.EditCheckBox.Checked)
57                 this.OKEditButton.PerformClick();
58         }
59
60         private async void ListManage_Load(object sender, EventArgs e)
61         {
62             using (ControlTransaction.Disabled(this))
63             {
64                 try
65                 {
66                     var lists = (IReadOnlyList<ListElement>)TabInformations.GetInstance().SubscribableLists;
67                     if (lists.Count == 0)
68                         lists = await this.FetchListsAsync();
69
70                     this.UpdateListsListBox(lists);
71                 }
72                 catch (OperationCanceledException)
73                 {
74                     this.DialogResult = DialogResult.Cancel;
75                     return;
76                 }
77                 catch (WebApiException)
78                 {
79                     this.DialogResult = DialogResult.Abort;
80                     return;
81                 }
82             }
83         }
84
85         private void ListsList_SelectedIndexChanged(object sender, EventArgs e)
86         {
87             if (this.ListsList.SelectedItem == null) return;
88
89             var list = (ListElement) this.ListsList.SelectedItem;
90             this.UsernameTextBox.Text = list.Username;
91             this.NameTextBox.Text = list.Name;
92             this.PublicRadioButton.Checked = list.IsPublic;
93             this.PrivateRadioButton.Checked = !list.IsPublic;
94             this.MemberCountTextBox.Text = list.MemberCount.ToString();
95             this.SubscriberCountTextBox.Text = list.SubscriberCount.ToString();
96             this.DescriptionText.Text = list.Description;
97
98             this.UserList.Items.Clear();
99             foreach (var user in list.Members)
100                 this.UserList.Items.Add(user);
101
102             this.GetMoreUsersButton.Text = this.UserList.Items.Count > 0 ? Properties.Resources.ListManageGetMoreUsers2 : Properties.Resources.ListManageGetMoreUsers1;
103         }
104
105         private void EditCheckBox_CheckedChanged(object sender, EventArgs e)
106         {
107             this.AddListButton.Enabled = !this.EditCheckBox.Checked;
108             this.EditCheckBox.Enabled = !this.EditCheckBox.Checked;
109             this.DeleteListButton.Enabled = !this.EditCheckBox.Checked;
110
111             this.NameTextBox.ReadOnly = !this.EditCheckBox.Checked;
112             this.PublicRadioButton.Enabled = this.EditCheckBox.Checked;
113             this.PrivateRadioButton.Enabled = this.EditCheckBox.Checked;
114             this.DescriptionText.ReadOnly = !this.EditCheckBox.Checked;
115             this.ListsList.Enabled = !this.EditCheckBox.Checked;
116
117             this.OKEditButton.Enabled = this.EditCheckBox.Checked;
118             this.CancelEditButton.Enabled = this.EditCheckBox.Checked;
119             this.EditCheckBox.AutoCheck = !this.EditCheckBox.Checked;
120
121             this.MemberGroup.Enabled = !this.EditCheckBox.Checked;
122             this.UserGroup.Enabled = !this.EditCheckBox.Checked;
123             this.CloseButton.Enabled = !this.EditCheckBox.Checked;
124
125             this.UsernameTextBox.TabStop = !this.EditCheckBox.Checked;
126             this.MemberCountTextBox.TabStop = !this.EditCheckBox.Checked;
127             this.SubscriberCountTextBox.TabStop = !this.EditCheckBox.Checked;
128             if (this.EditCheckBox.Checked == true) this.NameTextBox.Focus();
129         }
130
131         private async void OKEditButton_Click(object sender, EventArgs e)
132         {
133             if (this.ListsList.SelectedItem == null) return;
134
135             using (ControlTransaction.Disabled(this))
136             {
137                 var listItem = (ListElement)this.ListsList.SelectedItem;
138
139                 if (string.IsNullOrEmpty(this.NameTextBox.Text))
140                 {
141                     MessageBox.Show(Properties.Resources.ListManageOKButton1);
142                     return;
143                 }
144
145                 listItem.Name = this.NameTextBox.Text;
146                 listItem.IsPublic = this.PublicRadioButton.Checked;
147                 listItem.Description = this.DescriptionText.Text;
148
149                 try
150                 {
151                     await listItem.Refresh();
152                 }
153                 catch (WebApiException ex)
154                 {
155                     MessageBox.Show(string.Format(Properties.Resources.ListManageOKButton2, ex.Message));
156                     return;
157                 }
158
159                 this.ListsList.Items.Clear();
160                 this.ListManage_Load(this, EventArgs.Empty);
161
162                 this.EditCheckBox.AutoCheck = true;
163                 this.EditCheckBox.Checked = false;
164             }
165         }
166
167         private void CancelEditButton_Click(object sender, EventArgs e)
168         {
169             this.EditCheckBox.AutoCheck = true;
170             this.EditCheckBox.Checked = false;
171
172             for (var i = this.ListsList.Items.Count - 1; i >= 0; i--)
173                 if (this.ListsList.Items[i] is NewListElement)
174                     this.ListsList.Items.RemoveAt(i);
175
176             this.ListsList_SelectedIndexChanged(this.ListsList, EventArgs.Empty);
177         }
178
179         private async void RefreshUsersButton_Click(object sender, EventArgs e)
180         {
181             using (ControlTransaction.Disabled(this))
182             {
183                 if (this.ListsList.SelectedItem == null) return;
184                 this.UserList.Items.Clear();
185
186                 var list = (ListElement)this.ListsList.SelectedItem;
187                 try
188                 {
189                     await list.RefreshMembers();
190                 }
191                 catch (WebApiException ex)
192                 {
193                     MessageBox.Show(string.Format(Properties.Resources.ListManageGetListMembersCallback1, ex.Message));
194                     return;
195                 }
196
197                 this.ListsList_SelectedIndexChanged(this.ListsList, EventArgs.Empty);
198                 this.GetMoreUsersButton.Text = Properties.Resources.ListManageGetMoreUsers1;
199             }
200         }
201
202         private async void GetMoreUsersButton_Click(object sender, EventArgs e)
203         {
204             using (ControlTransaction.Disabled(this))
205             {
206                 if (this.ListsList.SelectedItem == null) return;
207                 this.UserList.Items.Clear();
208
209                 var list = (ListElement)this.ListsList.SelectedItem;
210                 try
211                 {
212                     await list.GetMoreMembers();
213                 }
214                 catch (WebApiException ex)
215                 {
216                     MessageBox.Show(string.Format(Properties.Resources.ListManageGetListMembersCallback1, ex.Message));
217                     return;
218                 }
219
220                 this.ListsList_SelectedIndexChanged(this.ListsList, EventArgs.Empty);
221                 this.GetMoreUsersButton.Text = Properties.Resources.ListManageGetMoreUsers1;
222             }
223         }
224
225         private async void DeleteUserButton_Click(object sender, EventArgs e)
226         {
227             if (this.ListsList.SelectedItem == null || this.UserList.SelectedItem == null)
228                 return;
229
230             using (ControlTransaction.Disabled(this))
231             {
232                 var list = (ListElement)this.ListsList.SelectedItem;
233                 var user = (UserInfo)this.UserList.SelectedItem;
234                 if (MessageBox.Show(Properties.Resources.ListManageDeleteUser1, ApplicationSettings.ApplicationName, MessageBoxButtons.OKCancel) == DialogResult.OK)
235                 {
236                     try
237                     {
238                         await this.tw.Api.ListsMembersDestroy(list.Id, user.ScreenName)
239                             .IgnoreResponse();
240                     }
241                     catch (WebApiException ex)
242                     {
243                         MessageBox.Show(string.Format(Properties.Resources.ListManageDeleteUser2, ex.Message));
244                         return;
245                     }
246
247                     var idx = ListsList.SelectedIndex;
248                     list.Members.Remove(user);
249                     this.ListsList_SelectedIndexChanged(this.ListsList, EventArgs.Empty);
250                     if (idx < ListsList.Items.Count) ListsList.SelectedIndex = idx;
251                 }
252             }
253         }
254
255         private async void DeleteListButton_Click(object sender, EventArgs e)
256         {
257             if (this.ListsList.SelectedItem == null) return;
258
259             using (ControlTransaction.Disabled(this))
260             {
261                 var list = (ListElement)this.ListsList.SelectedItem;
262
263                 if (MessageBox.Show(Properties.Resources.ListManageDeleteLists1, ApplicationSettings.ApplicationName, MessageBoxButtons.OKCancel) == DialogResult.OK)
264                 {
265                     try
266                     {
267                         await this.tw.DeleteList(list.Id);
268                     }
269                     catch (WebApiException ex)
270                     {
271                         MessageBox.Show(Properties.Resources.ListManageOKButton2, ex.Message);
272                         return;
273                     }
274
275                     try
276                     {
277                         await this.tw.GetListsApi();
278                     }
279                     catch (WebApiException ex)
280                     {
281                         MessageBox.Show(Properties.Resources.ListsDeleteFailed, ex.Message);
282                         return;
283                     }
284
285                     this.ListsList.Items.Clear();
286                     this.ListManage_Load(this, EventArgs.Empty);
287                 }
288             }
289         }
290
291         private void AddListButton_Click(object sender, EventArgs e)
292         {
293             var newList = new NewListElement(this.tw);
294             this.ListsList.Items.Add(newList);
295             this.ListsList.SelectedItem = newList;
296             this.EditCheckBox.Checked = true;
297             this.EditCheckBox_CheckedChanged(this.EditCheckBox, EventArgs.Empty);
298         }
299
300         private async void UserList_SelectedIndexChanged(object sender, EventArgs e)
301         {
302             if (UserList.SelectedItem == null)
303             {
304                 this.UserIcon.Image?.Dispose();
305                 this.UserIcon.Image = null;
306                 this.UserLocation.Text = "";
307                 this.UserWeb.Text = "";
308                 this.UserFollowNum.Text = "0";
309                 this.UserFollowerNum.Text = "0";
310                 this.UserPostsNum.Text = "0";
311                 this.UserProfile.Text = "";
312                 this.UserTweetDateTime.Text = "";
313                 this.UserTweet.Text = "";
314                 this.DeleteUserButton.Enabled = false;
315             }
316             else
317             {
318                 var user = (UserInfo)this.UserList.SelectedItem;
319                 this.UserLocation.Text = user.Location;
320                 this.UserWeb.Text = user.Url;
321                 this.UserFollowNum.Text = user.FriendsCount.ToString("#,###,##0");
322                 this.UserFollowerNum.Text = user.FollowersCount.ToString("#,###,##0");
323                 this.UserPostsNum.Text = user.StatusesCount.ToString("#,###,##0");
324                 this.UserProfile.Text = user.Description;
325                 if (!string.IsNullOrEmpty(user.RecentPost))
326                 {
327                     this.UserTweetDateTime.Text = user.PostCreatedAt.ToLocalTimeString("yy/MM/dd HH:mm");
328                     this.UserTweet.Text = user.RecentPost;
329                 }
330                 else
331                 {
332                     this.UserTweetDateTime.Text = "";
333                     this.UserTweet.Text = "";
334                 }
335                 this.DeleteUserButton.Enabled = true;
336
337                 if (user.ImageUrl != null)
338                     await this.LoadUserIconAsync(user.ImageUrl, user.Id);
339             }
340         }
341
342         private async Task LoadUserIconAsync(Uri imageUri, long userId)
343         {
344             var oldImage = this.UserIcon.Image;
345             this.UserIcon.Image = null;
346             oldImage?.Dispose();
347
348             await this.UserIcon.SetImageFromTask(async () =>
349             {
350                 var uri = imageUri.AbsoluteUri.Replace("_normal", "_bigger");
351
352                 using var imageStream = await Networking.Http.GetStreamAsync(uri);
353                 var image = await MemoryImage.CopyFromStreamAsync(imageStream);
354
355                 // 画像の読み込み中に選択中のユーザーが変化していたらキャンセルとして扱う
356                 var selectedUser = (UserInfo)this.UserList.SelectedItem;
357                 if (selectedUser.Id != userId)
358                 {
359                     image.Dispose();
360                     throw new OperationCanceledException();
361                 }
362
363                 return image;
364             });
365         }
366
367         private async void RefreshListsButton_Click(object sender, EventArgs e)
368         {
369             using (ControlTransaction.Disabled(this))
370             {
371                 try
372                 {
373                     var lists = await this.FetchListsAsync();
374                     this.UpdateListsListBox(lists);
375                 }
376                 catch (OperationCanceledException) { }
377                 catch (WebApiException ex)
378                 {
379                     MessageBox.Show(string.Format(Properties.Resources.ListsDeleteFailed, ex.Message));
380                 }
381             }
382         }
383
384         private async Task<IReadOnlyList<ListElement>> FetchListsAsync()
385         {
386             using var dialog = new WaitingDialog(Properties.Resources.ListsGetting);
387             var cancellationToken = dialog.EnableCancellation();
388
389             var task = this.tw.GetListsApi();
390             await dialog.WaitForAsync(this, task);
391
392             cancellationToken.ThrowIfCancellationRequested();
393
394             return TabInformations.GetInstance().SubscribableLists;
395         }
396
397         private void UpdateListsListBox(IEnumerable<ListElement> lists)
398         {
399             using (ControlTransaction.Update(this.ListsList))
400             {
401                 this.ListsList.Items.Clear();
402                 foreach (var listItem in lists.Where(x => x.UserId == this.tw.UserId))
403                 {
404                     this.ListsList.Items.Add(listItem);
405                 }
406                 if (this.ListsList.Items.Count > 0)
407                     this.ListsList.SelectedIndex = 0;
408                 this.ListsList.Focus();
409             }
410         }
411
412         private async void UserWeb_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
413         {
414             if (this.Owner != null)
415                 await ((TweenMain)this.Owner).OpenUriInBrowserAsync(UserWeb.Text);
416         }
417
418         private class NewListElement : ListElement
419         {
420             public bool IsCreated { get; private set; } = false;
421
422             public NewListElement(Twitter tw)
423                 => this._tw = tw;
424
425             public override async Task Refresh()
426             {
427                 if (this.IsCreated)
428                 {
429                     await base.Refresh().ConfigureAwait(false);
430                 }
431                 else
432                 {
433                     await this._tw.CreateListApi(this.Name, !this.IsPublic, this.Description)
434                         .ConfigureAwait(false);
435
436                     this.IsCreated = true;
437                 }
438             }
439
440             public override string ToString()
441             {
442                 if (IsCreated)
443                     return base.ToString();
444                 else
445                     return "NewList";
446             }
447         }
448
449         private void ListManage_Validating(object sender, CancelEventArgs e)
450         {
451             if (this.EditCheckBox.Checked)
452             {
453                 e.Cancel = true;
454                 this.CancelButton.PerformClick();
455             }
456         }
457     }
458 }