OSDN Git Service

現在表示中のタブをTabPageではなくタブ名で管理, TweenMain._curTab フィールドを廃止
[opentween/open-tween.git] / OpenTween / Tween.cs
index a6dcda4..702e156 100644 (file)
@@ -117,7 +117,7 @@ namespace OpenTween
         private Twitter tw;
 
         //Growl呼び出し部
-        private GrowlHelper gh = new GrowlHelper(Application.ProductName);
+        private GrowlHelper gh = new GrowlHelper(ApplicationSettings.ApplicationName);
 
         //サブ画面インスタンス
         internal SearchWordDialog SearchDialog = new SearchWordDialog();     //検索画面インスタンス
@@ -169,7 +169,7 @@ namespace OpenTween
         private int _hisIdx;                  //発言履歴カレントインデックス
 
         //発言投稿時のAPI引数(発言編集時に設定。手書きreplyでは設定されない)
-        private Tuple<long, string> inReplyTo = null; // リプライ先のステータスID・スクリーン名
+        private (long StatusId, string ScreenName)? inReplyTo = null; // リプライ先のステータスID・スクリーン名
 
         //時速表示用
         private List<DateTimeUtc> _postTimestamps = new List<DateTimeUtc>();
@@ -250,7 +250,6 @@ namespace OpenTween
             }
         }
 
-        private TabPage _curTab;
         private int _curItemIndex;
         private DetailsListView _curList;
         private PostClass _curPost;
@@ -274,6 +273,7 @@ namespace OpenTween
         private bool _colorize = false;
 
         private System.Timers.Timer TimerTimeline = new System.Timers.Timer();
+        private ThrottlingTimer RefreshThrottlingTimer;
 
         private string recommendedStatusFooter;
         private bool urlMultibyteSplit = false;
@@ -303,7 +303,16 @@ namespace OpenTween
         }
 
         private Stack<ReplyChain> replyChains; //[, ]でのリプライ移動の履歴
-        private Stack<ValueTuple<TabPage, PostClass>> selectPostChains = new Stack<ValueTuple<TabPage, PostClass>>(); //ポスト選択履歴
+        private Stack<(TabPage, PostClass)> selectPostChains = new Stack<(TabPage, PostClass)>(); //ポスト選択履歴
+
+        public TabModel CurrentTab
+            => this._statuses.SelectedTab;
+
+        public string CurrentTabName
+            => this._statuses.SelectedTabName;
+
+        public TabPage CurrentTabPage
+            => this.ListTab.TabPages.Cast<TabPage>().First(x => x.Text == this.CurrentTabName);
 
         //検索処理タイプ
         internal enum SEARCHTYPE
@@ -316,18 +325,16 @@ namespace OpenTween
         private class StatusTextHistory
         {
             public string status = "";
-            public long? inReplyToId = null;
-            public string inReplyToName = null;
+            public (long StatusId, string ScreenName)? inReplyTo = null;
             public string imageService = "";      //画像投稿サービス名
             public IMediaItem[] mediaItems = null;
             public StatusTextHistory()
             {
             }
-            public StatusTextHistory(string status, long? replyToId, string replyToName)
+            public StatusTextHistory(string status, (long StatusId, string ScreenName)? inReplyTo)
             {
                 this.status = status;
-                this.inReplyToId = replyToId;
-                this.inReplyToName = replyToName;
+                this.inReplyTo = inReplyTo;
             }
         }
 
@@ -695,7 +702,6 @@ namespace OpenTween
 
             //Win32Api.SetProxy(HttpConnection.ProxyType.Specified, "127.0.0.1", 8080, "user", "pass")
 
-            MyCommon.TwitterApiInfo.AccessLimitUpdated += TwitterApiStatus_AccessLimitUpdated;
             Microsoft.Win32.SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
             Microsoft.Win32.SystemEvents.TimeChanged += SystemEvents_TimeChanged;
 
@@ -828,7 +834,7 @@ namespace OpenTween
             catch (WebApiException ex)
             {
                 MessageBox.Show(this, string.Format(Properties.Resources.StartupAuthError_Text, ex.Message),
-                    Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
+                    ApplicationSettings.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
             }
 
             //サムネイル関連の初期化
@@ -1062,9 +1068,11 @@ namespace OpenTween
                     throw new TabException(Properties.Resources.TweenMain_LoadText1);
             }
 
-            _curTab = ListTab.SelectedTab;
+            this._statuses.SelectTab(this.ListTab.SelectedTab.Text);
             _curItemIndex = -1;
-            _curList = (DetailsListView)_curTab.Tag;
+            _curList = (DetailsListView)this.CurrentTabPage.Tag;
+
+            MyCommon.TwitterApiInfo.AccessLimitUpdated += TwitterApiStatus_AccessLimitUpdated;
 
             if (SettingManager.Common.TabIconDisp)
             {
@@ -1107,6 +1115,11 @@ namespace OpenTween
             }
 
             //タイマー設定
+
+            var streamingRefreshInterval = TimeSpan.FromSeconds(SettingManager.Common.UserstreamPeriod);
+            this.RefreshThrottlingTimer = new ThrottlingTimer(streamingRefreshInterval,
+                () => this.InvokeAsync(() => this.RefreshTimeline()));
+
             TimerTimeline.AutoReset = true;
             TimerTimeline.SynchronizingObject = this;
             //Recent取得間隔
@@ -1122,7 +1135,7 @@ namespace OpenTween
 
             foreach (var ua in SettingManager.Common.UserAccounts)
             {
-                if (ua.UserId == 0 && ua.Username.ToLowerInvariant() == tw.Username.ToLowerInvariant())
+                if (ua.UserId == 0 && ua.Username.Equals(tw.Username, StringComparison.InvariantCultureIgnoreCase))
                 {
                     ua.UserId = tw.UserId;
                     break;
@@ -1268,6 +1281,15 @@ namespace OpenTween
         private void TimerInterval_Changed(object sender, IntervalChangedEventArgs e) //Handles SettingDialog.IntervalChanged
         {
             if (!TimerTimeline.Enabled) return;
+
+            if (e.UserStream)
+            {
+                var interval = TimeSpan.FromSeconds(SettingManager.Common.UserstreamPeriod);
+                var newTimer = new ThrottlingTimer(interval, () => this.InvokeAsync(() => this.RefreshTimeline()));
+                var oldTimer = Interlocked.Exchange(ref this.RefreshThrottlingTimer, newTimer);
+                oldTimer.Dispose();
+            }
+
             ResetTimers = e;
         }
 
@@ -1279,7 +1301,6 @@ namespace OpenTween
         private static int pubSearchCounter = 0;
         private static int userTimelineCounter = 0;
         private static int listsCounter = 0;
-        private static int usCounter = 0;
         private static int ResumeWait = 0;
         private static int refreshFollowers = 0;
 
@@ -1291,7 +1312,6 @@ namespace OpenTween
             if (pubSearchCounter > 0) Interlocked.Decrement(ref pubSearchCounter);
             if (userTimelineCounter > 0) Interlocked.Decrement(ref userTimelineCounter);
             if (listsCounter > 0) Interlocked.Decrement(ref listsCounter);
-            if (usCounter > 0) Interlocked.Decrement(ref usCounter);
             Interlocked.Increment(ref refreshFollowers);
 
             var refreshTasks = new List<Task>();
@@ -1301,51 +1321,44 @@ namespace OpenTween
             {
                 Interlocked.Exchange(ref homeCounter, SettingManager.Common.TimelinePeriod);
                 if (!tw.IsUserstreamDataReceived && !ResetTimers.Timeline)
-                    refreshTasks.Add(this.GetHomeTimelineAsync());
+                    refreshTasks.Add(this.RefreshTabAsync<HomeTabModel>());
                 ResetTimers.Timeline = false;
             }
             if (ResetTimers.Reply || mentionCounter <= 0 && SettingManager.Common.ReplyPeriod > 0)
             {
                 Interlocked.Exchange(ref mentionCounter, SettingManager.Common.ReplyPeriod);
                 if (!tw.IsUserstreamDataReceived && !ResetTimers.Reply)
-                    refreshTasks.Add(this.GetReplyAsync());
+                    refreshTasks.Add(this.RefreshTabAsync<MentionsTabModel>());
                 ResetTimers.Reply = false;
             }
             if (ResetTimers.DirectMessage || dmCounter <= 0 && SettingManager.Common.DMPeriod > 0)
             {
                 Interlocked.Exchange(ref dmCounter, SettingManager.Common.DMPeriod);
                 if (!tw.IsUserstreamDataReceived && !ResetTimers.DirectMessage)
-                    refreshTasks.Add(this.GetDirectMessagesAsync());
+                    refreshTasks.Add(this.RefreshTabAsync<DirectMessagesTabModel>());
                 ResetTimers.DirectMessage = false;
             }
             if (ResetTimers.PublicSearch || pubSearchCounter <= 0 && SettingManager.Common.PubSearchPeriod > 0)
             {
                 Interlocked.Exchange(ref pubSearchCounter, SettingManager.Common.PubSearchPeriod);
                 if (!ResetTimers.PublicSearch)
-                    refreshTasks.Add(this.GetPublicSearchAllAsync());
+                    refreshTasks.Add(this.RefreshTabAsync<PublicSearchTabModel>());
                 ResetTimers.PublicSearch = false;
             }
             if (ResetTimers.UserTimeline || userTimelineCounter <= 0 && SettingManager.Common.UserTimelinePeriod > 0)
             {
                 Interlocked.Exchange(ref userTimelineCounter, SettingManager.Common.UserTimelinePeriod);
                 if (!ResetTimers.UserTimeline)
-                    refreshTasks.Add(this.GetUserTimelineAllAsync());
+                    refreshTasks.Add(this.RefreshTabAsync<UserTimelineTabModel>());
                 ResetTimers.UserTimeline = false;
             }
             if (ResetTimers.Lists || listsCounter <= 0 && SettingManager.Common.ListsPeriod > 0)
             {
                 Interlocked.Exchange(ref listsCounter, SettingManager.Common.ListsPeriod);
                 if (!ResetTimers.Lists)
-                    refreshTasks.Add(this.GetListTimelineAllAsync());
+                    refreshTasks.Add(this.RefreshTabAsync<ListTimelineTabModel>());
                 ResetTimers.Lists = false;
             }
-            if (ResetTimers.UserStream || usCounter <= 0 && SettingManager.Common.UserstreamPeriod > 0)
-            {
-                Interlocked.Exchange(ref usCounter, SettingManager.Common.UserstreamPeriod);
-                if (this.tw.UserStreamActive)
-                    this.RefreshTimeline();
-                ResetTimers.UserStream = false;
-            }
             if (refreshFollowers > 6 * 3600)
             {
                 Interlocked.Exchange(ref refreshFollowers, 0);
@@ -1365,12 +1378,12 @@ namespace OpenTween
                     Interlocked.Exchange(ref ResumeWait, 0);
                     refreshTasks.AddRange(new[]
                     {
-                        this.GetHomeTimelineAsync(),
-                        this.GetReplyAsync(),
-                        this.GetDirectMessagesAsync(),
-                        this.GetPublicSearchAllAsync(),
-                        this.GetUserTimelineAllAsync(),
-                        this.GetListTimelineAllAsync(),
+                        this.RefreshTabAsync<HomeTabModel>(),
+                        this.RefreshTabAsync<MentionsTabModel>(),
+                        this.RefreshTabAsync<DirectMessagesTabModel>(),
+                        this.RefreshTabAsync<PublicSearchTabModel>(),
+                        this.RefreshTabAsync<UserTimelineTabModel>(),
+                        this.RefreshTabAsync<ListTimelineTabModel>(),
                         this.doGetFollowersMenu(),
                         this.RefreshTwitterConfigurationAsync(),
                     });
@@ -1382,7 +1395,7 @@ namespace OpenTween
 
         private void RefreshTimeline()
         {
-            var curTabModel = this._statuses.Tabs[this._curTab.Text];
+            var curTabModel = this.CurrentTab;
 
             // 現在表示中のタブのスクロール位置を退避
             var curListScroll = this.SaveListViewScroll(this._curList, curTabModel);
@@ -1572,7 +1585,7 @@ namespace OpenTween
             {
                 return new ListViewSelection
                 {
-                    SelectedStatusIds = new long[0],
+                    SelectedStatusIds = Array.Empty<long>(),
                     SelectionMarkStatusId = null,
                     FocusedStatusId = null,
                 };
@@ -1670,8 +1683,10 @@ namespace OpenTween
 
         private bool BalloonRequired()
         {
-            Twitter.FormattedEvent ev = new Twitter.FormattedEvent();
-            ev.Eventtype = MyCommon.EVENTTYPE.None;
+            var ev = new Twitter.FormattedEvent
+            {
+                Eventtype = MyCommon.EVENTTYPE.None,
+            };
 
             return BalloonRequired(ev);
         }
@@ -1782,7 +1797,7 @@ namespace OpenTween
                             {
                                 //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
                                 //NotifyIcon1.BalloonTipTitle += Application.ProductName + " [DM] " + Properties.Resources.RefreshDirectMessageText1 + " " + addCount.ToString() + Properties.Resources.RefreshDirectMessageText2;
-                                title.Append(Application.ProductName);
+                                title.Append(ApplicationSettings.ApplicationName);
                                 title.Append(" [DM] ");
                                 title.AppendFormat(Properties.Resources.RefreshTimeline_NotifyText, addCount);
                                 nt = GrowlHelper.NotifyType.DirectMessage;
@@ -1791,7 +1806,7 @@ namespace OpenTween
                             {
                                 //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
                                 //NotifyIcon1.BalloonTipTitle += Application.ProductName + " [Reply!] " + Properties.Resources.RefreshTimelineText1 + " " + addCount.ToString() + Properties.Resources.RefreshTimelineText2;
-                                title.Append(Application.ProductName);
+                                title.Append(ApplicationSettings.ApplicationName);
                                 title.Append(" [Reply!] ");
                                 title.AppendFormat(Properties.Resources.RefreshTimeline_NotifyText, addCount);
                                 nt = GrowlHelper.NotifyType.Reply;
@@ -1800,7 +1815,7 @@ namespace OpenTween
                             {
                                 //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
                                 //NotifyIcon1.BalloonTipTitle += Application.ProductName + " " + Properties.Resources.RefreshTimelineText1 + " " + addCount.ToString() + Properties.Resources.RefreshTimelineText2;
-                                title.Append(Application.ProductName);
+                                title.Append(ApplicationSettings.ApplicationName);
                                 title.Append(" ");
                                 title.AppendFormat(Properties.Resources.RefreshTimeline_NotifyText, addCount);
                                 nt = GrowlHelper.NotifyType.Notify;
@@ -1809,7 +1824,7 @@ namespace OpenTween
                             if (string.IsNullOrEmpty(bText)) return;
 
                             var image = this.IconCache.TryGetFromCache(post.ImageUrl);
-                            gh.Notify(nt, post.StatusId.ToString(), title.ToString(), bText, image == null ? null : image.Image, post.ImageUrl);
+                            gh.Notify(nt, post.StatusId.ToString(), title.ToString(), bText, image?.Image, post.ImageUrl);
                         }
                     }
                     else
@@ -1851,7 +1866,7 @@ namespace OpenTween
                             //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
                             //NotifyIcon1.BalloonTipTitle += Application.ProductName + " [DM] " + Properties.Resources.RefreshDirectMessageText1 + " " + addCount.ToString() + Properties.Resources.RefreshDirectMessageText2;
                             ntIcon = ToolTipIcon.Warning;
-                            title.Append(Application.ProductName);
+                            title.Append(ApplicationSettings.ApplicationName);
                             title.Append(" [DM] ");
                             title.AppendFormat(Properties.Resources.RefreshTimeline_NotifyText, addCount);
                         }
@@ -1860,7 +1875,7 @@ namespace OpenTween
                             //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
                             //NotifyIcon1.BalloonTipTitle += Application.ProductName + " [Reply!] " + Properties.Resources.RefreshTimelineText1 + " " + addCount.ToString() + Properties.Resources.RefreshTimelineText2;
                             ntIcon = ToolTipIcon.Warning;
-                            title.Append(Application.ProductName);
+                            title.Append(ApplicationSettings.ApplicationName);
                             title.Append(" [Reply!] ");
                             title.AppendFormat(Properties.Resources.RefreshTimeline_NotifyText, addCount);
                         }
@@ -1869,7 +1884,7 @@ namespace OpenTween
                             //NotifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
                             //NotifyIcon1.BalloonTipTitle += Application.ProductName + " " + Properties.Resources.RefreshTimelineText1 + " " + addCount.ToString() + Properties.Resources.RefreshTimelineText2;
                             ntIcon = ToolTipIcon.Info;
-                            title.Append(Application.ProductName);
+                            title.Append(ApplicationSettings.ApplicationName);
                             title.Append(" ");
                             title.AppendFormat(Properties.Resources.RefreshTimeline_NotifyText, addCount);
                         }
@@ -1940,7 +1955,7 @@ namespace OpenTween
 
         private void ChangeCacheStyleRead(bool Read, int Index)
         {
-            var tabInfo = _statuses.Tabs[_curTab.Text];
+            var tabInfo = this.CurrentTab;
             //Read:true=既読 false=未読
             //未読管理していなかったら既読として扱う
             if (!tabInfo.UnreadManage ||
@@ -1954,7 +1969,7 @@ namespace OpenTween
             if (!listCache.TryGetValue(Index, out var itm, out var post))
                 return;
 
-            ChangeItemStyleRead(Read, itm, post, ((DetailsListView)_curTab.Tag));
+            ChangeItemStyleRead(Read, itm, post, this._curList);
         }
 
         private void ChangeItemStyleRead(bool Read, ListViewItem Item, PostClass Post, DetailsListView DList)
@@ -2057,10 +2072,10 @@ namespace OpenTween
             else if (TargetPost.IsReply)
                 //自分宛返信
                 cl = _clAtSelf;
-            else if (BasePost.ReplyToList.Any(x => x.Item1 == TargetPost.UserId))
+            else if (BasePost.ReplyToList.Any(x => x.UserId == TargetPost.UserId))
                 //返信先
                 cl = _clAtFromTarget;
-            else if (TargetPost.ReplyToList.Any(x => x.Item1 == BasePost.UserId))
+            else if (TargetPost.ReplyToList.Any(x => x.UserId == BasePost.UserId))
                 //その人への返信
                 cl = _clAtTarget;
             else if (TargetPost.ScreenName.Equals(BasePost.ScreenName, StringComparison.OrdinalIgnoreCase))
@@ -2073,6 +2088,36 @@ namespace OpenTween
             return cl;
         }
 
+        private void StatusTextHistoryBack()
+        {
+            if (!string.IsNullOrWhiteSpace(this.StatusText.Text))
+                this._history[_hisIdx] = new StatusTextHistory(this.StatusText.Text, this.inReplyTo);
+
+            this._hisIdx -= 1;
+            if (this._hisIdx < 0)
+                this._hisIdx = 0;
+
+            var historyItem = this._history[this._hisIdx];
+            this.inReplyTo = historyItem.inReplyTo;
+            this.StatusText.Text = historyItem.status;
+            this.StatusText.SelectionStart = this.StatusText.Text.Length;
+        }
+
+        private void StatusTextHistoryForward()
+        {
+            if (!string.IsNullOrWhiteSpace(this.StatusText.Text))
+                this._history[this._hisIdx] = new StatusTextHistory(this.StatusText.Text, this.inReplyTo);
+
+            this._hisIdx += 1;
+            if (this._hisIdx > this._history.Count - 1)
+                this._hisIdx = this._history.Count - 1;
+
+            var historyItem = this._history[this._hisIdx];
+            this.inReplyTo = historyItem.inReplyTo;
+            this.StatusText.Text = historyItem.status;
+            this.StatusText.SelectionStart = this.StatusText.Text.Length;
+        }
+
         private async void PostButton_Click(object sender, EventArgs e)
         {
             if (StatusText.Text.Trim().Length == 0)
@@ -2101,9 +2146,16 @@ namespace OpenTween
                 }
             }
 
-            var inReplyToStatusId = this.inReplyTo?.Item1;
-            var inReplyToScreenName = this.inReplyTo?.Item2;
-            _history[_history.Count - 1] = new StatusTextHistory(StatusText.Text, inReplyToStatusId, inReplyToScreenName);
+            if (TextContainsOnlyMentions(this.StatusText.Text))
+            {
+                var message = string.Format(Properties.Resources.PostConfirmText, this.StatusText.Text);
+                var ret = MessageBox.Show(message, ApplicationSettings.ApplicationName, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2);
+
+                if (ret != DialogResult.OK)
+                    return;
+            }
+
+            _history[_history.Count - 1] = new StatusTextHistory(StatusText.Text, this.inReplyTo);
 
             if (SettingManager.Common.Nicoms)
             {
@@ -2131,26 +2183,24 @@ namespace OpenTween
                 // auto_populate_reply_metadata や attachment_url を使用しなくても 140 字以内に
                 // 収まる場合はこれらのオプションを使用せずに投稿する
                 status.Text = statusTextCompat;
-                status.InReplyToStatusId = this.inReplyTo?.Item1;
+                status.InReplyToStatusId = this.inReplyTo?.StatusId;
             }
             else
             {
-                long[] autoPopulatedUserIds;
-                string attachmentUrl;
-                status.Text = this.FormatStatusTextExtended(this.StatusText.Text, out autoPopulatedUserIds, out attachmentUrl);
-                status.InReplyToStatusId = this.inReplyTo?.Item1;
+                status.Text = this.FormatStatusTextExtended(this.StatusText.Text, out var autoPopulatedUserIds, out var attachmentUrl);
+                status.InReplyToStatusId = this.inReplyTo?.StatusId;
 
                 status.AttachmentUrl = attachmentUrl;
 
                 // リプライ先がセットされていても autoPopulatedUserIds が空の場合は auto_populate_reply_metadata を有効にしない
                 //  (非公式 RT の場合など)
-                var replyToPost = this.inReplyTo != null ? this._statuses[this.inReplyTo.Item1] : null;
+                var replyToPost = this.inReplyTo != null ? this._statuses[this.inReplyTo.Value.StatusId] : null;
                 if (replyToPost != null && autoPopulatedUserIds.Length != 0)
                 {
                     status.AutoPopulateReplyMetadata = true;
 
                     // ReplyToList のうち autoPopulatedUserIds に含まれていないユーザー ID を抽出
-                    status.ExcludeReplyUserIds = replyToPost.ReplyToList.Select(x => x.Item1).Except(autoPopulatedUserIds)
+                    status.ExcludeReplyUserIds = replyToPost.ReplyToList.Select(x => x.UserId).Except(autoPopulatedUserIds)
                         .ToArray();
                 }
             }
@@ -2167,9 +2217,8 @@ namespace OpenTween
             IMediaItem[] uploadItems = null;
             if (ImageSelector.Visible)
             {
-                string serviceName;
                 //画像投稿
-                if (!ImageSelector.TryGetSelectedMedia(out serviceName, out uploadItems))
+                if (!ImageSelector.TryGetSelectedMedia(out var serviceName, out uploadItems))
                     return;
 
                 uploadService = this.ImageSelector.GetService(serviceName);
@@ -2248,260 +2297,71 @@ namespace OpenTween
             return true;
         }
 
-        private Task GetHomeTimelineAsync()
-        {
-            return this.GetHomeTimelineAsync(loadMore: false);
-        }
-
-        private async Task GetHomeTimelineAsync(bool loadMore)
-        {
-            await this.workerSemaphore.WaitAsync();
-
-            try
-            {
-                var homeTab = this._statuses.GetTabByType<HomeTabModel>();
-                await homeTab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
-
-                this.RefreshTimeline();
-            }
-            catch (WebApiException ex)
-            {
-                this._myStatusError = true;
-                this.StatusLabel.Text = $"Err:{ex.Message}(GetTimeline)";
-            }
-            finally
-            {
-                this.workerSemaphore.Release();
-            }
-        }
-
-        private Task GetReplyAsync()
-        {
-            return this.GetReplyAsync(loadMore: false);
-        }
+        /// <summary>指定された型 <typeparamref name="T"/> に合致する全てのタブを更新します</summary>
+        private Task RefreshTabAsync<T>() where T : TabModel
+            => this.RefreshTabAsync<T>(backward: false);
 
-        private async Task GetReplyAsync(bool loadMore)
+        /// <summary>指定された型 <typeparamref name="T"/> に合致する全てのタブを更新します</summary>
+        private Task RefreshTabAsync<T>(bool backward) where T : TabModel
         {
-            await this.workerSemaphore.WaitAsync();
-
-            try
-            {
-                var replyTab = this._statuses.GetTabByType<MentionsTabModel>();
-                await replyTab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
+            var loadTasks =
+                from tab in this._statuses.GetTabsByType<T>()
+                select this.RefreshTabAsync(tab, backward);
 
-                this.RefreshTimeline();
-            }
-            catch (WebApiException ex)
-            {
-                this._myStatusError = true;
-                this.StatusLabel.Text = $"Err:{ex.Message}(GetTimeline)";
-            }
-            finally
-            {
-                this.workerSemaphore.Release();
-            }
+            return Task.WhenAll(loadTasks);
         }
 
-        private Task GetDirectMessagesAsync()
-        {
-            return this.GetDirectMessagesAsync(loadMore: false);
-        }
+        /// <summary>指定されたタブ <paramref name="tab"/> を更新します</summary>
+        private Task RefreshTabAsync(TabModel tab)
+            => this.RefreshTabAsync(tab, backward: false);
 
-        private async Task GetDirectMessagesAsync(bool loadMore)
+        /// <summary>指定されたタブ <paramref name="tab"/> を更新します</summary>
+        private async Task RefreshTabAsync(TabModel tab, bool backward)
         {
             await this.workerSemaphore.WaitAsync();
 
             try
             {
-                var dmTab = this._statuses.GetTabByType<DirectMessagesTabModel>();
-                await dmTab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
-
+                await Task.Run(() => tab.RefreshAsync(this.tw, backward, this._initial, this.workerProgress));
                 this.RefreshTimeline();
             }
             catch (WebApiException ex)
             {
                 this._myStatusError = true;
-                this.StatusLabel.Text = $"Err:{ex.Message}(GetDirectMessage)";
-            }
-            finally
-            {
-                this.workerSemaphore.Release();
-            }
-        }
-
-        private Task GetFavoritesAsync()
-        {
-            return this.GetFavoritesAsync(loadMore: false);
-        }
-
-        private async Task GetFavoritesAsync(bool loadMore)
-        {
-            await this.workerSemaphore.WaitAsync();
-
-            try
-            {
-                var favTab = this._statuses.GetTabByType<FavoritesTabModel>();
-                await favTab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
-
-                this.RefreshTimeline();
-            }
-            catch (WebApiException ex)
-            {
-                this._myStatusError = true;
-                this.StatusLabel.Text = ex.Message;
-            }
-            finally
-            {
-                this.workerSemaphore.Release();
-            }
-        }
-
-        private Task GetPublicSearchAllAsync()
-        {
-            var tabs = this._statuses.GetTabsByType<PublicSearchTabModel>();
 
-            return this.GetPublicSearchAsync(tabs, loadMore: false);
-        }
-
-        private Task GetPublicSearchAsync(PublicSearchTabModel tab)
-        {
-            return this.GetPublicSearchAsync(tab, loadMore: false);
-        }
-
-        private Task GetPublicSearchAsync(PublicSearchTabModel tab, bool loadMore)
-        {
-            return this.GetPublicSearchAsync(new[] { tab }, loadMore);
-        }
-
-        private async Task GetPublicSearchAsync(IEnumerable<PublicSearchTabModel> tabs, bool loadMore)
-        {
-            await this.workerSemaphore.WaitAsync();
-
-            try
-            {
-                foreach (var tab in tabs)
-                {
-                    try
-                    {
-                        await tab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
-                    }
-                    catch (WebApiException ex)
-                    {
-                        this._myStatusError = true;
-                        this.StatusLabel.Text = $"Err:{ex.Message}(GetSearch)";
-                    }
-                }
-
-                this.RefreshTimeline();
-            }
-            finally
-            {
-                this.workerSemaphore.Release();
-            }
-        }
-
-        private Task GetUserTimelineAllAsync()
-        {
-            var tabs = this._statuses.GetTabsByType<UserTimelineTabModel>();
-
-            return this.GetUserTimelineAsync(tabs, loadMore: false);
-        }
-
-        private Task GetUserTimelineAsync(UserTimelineTabModel tab)
-        {
-            return this.GetUserTimelineAsync(tab, loadMore: false);
-        }
-
-        private Task GetUserTimelineAsync(UserTimelineTabModel tab, bool loadMore)
-        {
-            return this.GetUserTimelineAsync(new[] { tab }, loadMore);
-        }
-
-        private async Task GetUserTimelineAsync(IEnumerable<UserTimelineTabModel> tabs, bool loadMore)
-        {
-            await this.workerSemaphore.WaitAsync();
-
-            try
-            {
-                foreach (var tab in tabs)
+                string tabType;
+                switch (tab)
                 {
-                    try
-                    {
-                        await tab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
-                    }
-                    catch (WebApiException ex)
-                    {
-                        this._myStatusError = true;
-                        this.StatusLabel.Text = $"Err:{ex.Message}(GetUserTimeline)";
-                    }
+                    case HomeTabModel _:
+                        tabType = "GetTimeline";
+                        break;
+                    case MentionsTabModel _:
+                        tabType = "GetTimeline";
+                        break;
+                    case DirectMessagesTabModel _:
+                        tabType = "GetDirectMessage";
+                        break;
+                    case FavoritesTabModel _:
+                        tabType = "GetFavorites";
+                        break;
+                    case PublicSearchTabModel _:
+                        tabType = "GetSearch";
+                        break;
+                    case UserTimelineTabModel _:
+                        tabType = "GetUserTimeline";
+                        break;
+                    case ListTimelineTabModel _:
+                        tabType = "GetListStatus";
+                        break;
+                    case RelatedPostsTabModel _:
+                        tabType = "GetRelatedTweets";
+                        break;
+                    default:
+                        tabType = tab.GetType().Name.Replace("Model", "");
+                        break;
                 }
 
-                this.RefreshTimeline();
-            }
-            finally
-            {
-                this.workerSemaphore.Release();
-            }
-        }
-
-        private Task GetListTimelineAllAsync()
-        {
-            var tabs = this._statuses.GetTabsByType<ListTimelineTabModel>();
-
-            return this.GetListTimelineAsync(tabs, loadMore: false);
-        }
-
-        private Task GetListTimelineAsync(ListTimelineTabModel tab)
-        {
-            return this.GetListTimelineAsync(tab, loadMore: false);
-        }
-
-        private Task GetListTimelineAsync(ListTimelineTabModel tab, bool loadMore)
-        {
-            return this.GetListTimelineAsync(new[] { tab }, loadMore);
-        }
-
-        private async Task GetListTimelineAsync(IEnumerable<ListTimelineTabModel> tabs, bool loadMore)
-        {
-            await this.workerSemaphore.WaitAsync();
-
-            try
-            {
-                foreach (var tab in tabs)
-                {
-                    try
-                    {
-                        await tab.RefreshAsync(this.tw, loadMore, this._initial, this.workerProgress);
-                    }
-                    catch (WebApiException ex)
-                    {
-                        this._myStatusError = true;
-                        this.StatusLabel.Text = $"Err:{ex.Message}(GetListStatus)";
-                    }
-                }
-
-                this.RefreshTimeline();
-            }
-            finally
-            {
-                this.workerSemaphore.Release();
-            }
-        }
-
-        private async Task GetRelatedTweetsAsync(RelatedPostsTabModel tab)
-        {
-            await this.workerSemaphore.WaitAsync();
-
-            try
-            {
-                await tab.RefreshAsync(this.tw, this._initial, this.workerProgress);
-
-                this.RefreshTimeline();
-            }
-            catch (WebApiException ex)
-            {
-                this._myStatusError = true;
-                this.StatusLabel.Text = $"Err:{ex.Message}(GetRelatedTweets)";
+                this.StatusLabel.Text = $"Err:{ex.Message}({tabType})";
             }
             finally
             {
@@ -2614,7 +2474,7 @@ namespace OpenTween
 
             this.RefreshTimeline();
 
-            if (this._curList != null && this._curTab != null && this._curTab.Text == tab.TabName)
+            if (this._curList != null && this.CurrentTabName == tab.TabName)
             {
                 using (ControlTransaction.Update(this._curList))
                 {
@@ -2716,7 +2576,7 @@ namespace OpenTween
 
             this.RefreshTimeline();
 
-            if (this._curList != null && this._curTab != null && this._curTab.Text == tab.TabName)
+            if (this._curList != null && this.CurrentTabName == tab.TabName)
             {
                 if (tab.TabType == MyCommon.TabUsageType.Favorites)
                 {
@@ -2775,6 +2635,7 @@ namespace OpenTween
 
             p.Report("Posting...");
 
+            PostClass post = null;
             var errMsg = "";
 
             try
@@ -2789,7 +2650,7 @@ namespace OpenTween
                             .ConfigureAwait(false);
                     }
 
-                    await this.tw.PostStatus(postParamsWithMedia)
+                    post = await this.tw.PostStatus(postParamsWithMedia)
                         .ConfigureAwait(false);
                 });
 
@@ -2842,6 +2703,9 @@ namespace OpenTween
                 }
                 else
                 {
+                    this.StatusTextHistoryBack();
+                    this.StatusText.Focus();
+
                     // 連投モードのときだけEnterイベントが起きないので強制的に背景色を戻す
                     if (SettingManager.Common.FocusLockToStatusText)
                         this.StatusText_Enter(this.StatusText, EventArgs.Empty);
@@ -2868,12 +2732,20 @@ namespace OpenTween
 
             this.SetMainWindowTitle();
 
-            if (SettingManager.Common.PostAndGet)
+            // TLに反映
+            if (!this.tw.UserStreamActive)
             {
-                if (this.tw.UserStreamActive)
-                    this.RefreshTimeline();
+                if (SettingManager.Common.PostAndGet)
+                    await this.RefreshTabAsync<HomeTabModel>();
                 else
-                    await this.GetHomeTimelineAsync();
+                {
+                    if (post != null)
+                    {
+                        this._statuses.AddPost(post);
+                        this._statuses.DistributePosts();
+                        this.RefreshTimeline();
+                    }
+                }
             }
         }
 
@@ -2886,9 +2758,6 @@ namespace OpenTween
                 var progress = new Progress<string>(x => this.StatusLabel.Text = x);
 
                 await this.RetweetAsyncInternal(progress, this.workerCts.Token, statusIds);
-
-                if (SettingManager.Common.PostAndGet && !this.tw.UserStreamActive)
-                    await this.GetHomeTimelineAsync();
             }
             catch (WebApiException ex)
             {
@@ -2917,10 +2786,16 @@ namespace OpenTween
 
             p.Report("Posting...");
 
-            foreach (var statusId in statusIds)
+            var posts = new List<PostClass>();
+
+            await Task.Run(async () =>
             {
-                await this.tw.PostRetweet(statusId, read).ConfigureAwait(false);
-            }
+                foreach (var statusId in statusIds)
+                {
+                    var post = await this.tw.PostRetweet(statusId, read).ConfigureAwait(false);
+                    if (post != null) posts.Add(post);
+                }
+            });
 
             if (ct.IsCancellationRequested)
                 return;
@@ -2935,6 +2810,22 @@ namespace OpenTween
                 if (this._postTimestamps[i] < oneHour)
                     this._postTimestamps.RemoveAt(i);
             }
+
+            // TLに反映
+            if (!this.tw.UserStreamActive)
+            {
+                // 自分のRTはTLの更新では取得できない場合があるので、
+                // 投稿時取得の有無に関わらず追加しておく
+                posts.ForEach(post => this._statuses.AddPost(post));
+
+                if (SettingManager.Common.PostAndGet)
+                    await this.RefreshTabAsync<HomeTabModel>();
+                else
+                {
+                    this._statuses.DistributePosts();
+                    this.RefreshTimeline();
+                }
+            }
         }
 
         private async Task RefreshFollowerIdsAsync()
@@ -3077,7 +2968,7 @@ namespace OpenTween
                         await this.ShowUserStatus(_curPost.ScreenName, false);
                     break;
                 case 3:
-                    ShowUserTimeline();
+                    await ShowUserTimeline();
                     break;
                 case 4:
                     ShowRelatedStatusesMenuItem_Click(null, null);
@@ -3095,30 +2986,21 @@ namespace OpenTween
         }
 
         private async void FavAddToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.FavoriteChange(true);
-        }
+            => await this.FavoriteChange(true);
 
         private async void FavRemoveToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.FavoriteChange(false);
-        }
+            => await this.FavoriteChange(false);
 
 
         private async void FavoriteRetweetMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.FavoritesRetweetOfficial();
-        }
+            => await this.FavoritesRetweetOfficial();
 
         private async void FavoriteRetweetUnofficialMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.FavoritesRetweetUnofficial();
-        }
+            => await this.FavoritesRetweetUnofficial();
 
         private async Task FavoriteChange(bool FavAdd, bool multiFavoriteChangeDialogEnable = true)
         {
-            if (!this._statuses.Tabs.TryGetValue(this._curTab.Text, out var tab))
-                return;
+            var tab = this.CurrentTab;
 
             //trueでFavAdd,falseでFavRemove
             if (tab.TabType == MyCommon.TabUsageType.DirectMessage || _curList.SelectedIndices.Count == 0
@@ -3185,7 +3067,7 @@ namespace OpenTween
                     return post;
             }
 
-            return _statuses.Tabs[_curTab.Text][Index];
+            return this.CurrentTab[Index];
         }
 
         private async void MoveToHomeToolStripMenuItem_Click(object sender, EventArgs e)
@@ -3318,7 +3200,7 @@ namespace OpenTween
 
             this.PurgeListViewItemCache();
 
-            var tab = this._statuses.Tabs[this._curTab.Text];
+            var tab = this.CurrentTab;
             if (tab.AllCount > 0 && this._curPost != null)
             {
                 var idx = tab.IndexOf(this._curPost.StatusId);
@@ -3344,8 +3226,6 @@ namespace OpenTween
 
         private void ContextMenuOperate_Opening(object sender, CancelEventArgs e)
         {
-            if (ListTab.SelectedTab == null) return;
-            if (_statuses == null || _statuses.Tabs == null || !_statuses.Tabs.ContainsKey(ListTab.SelectedTab.Text)) return;
             if (!this.ExistCurrentPost)
             {
                 ReplyStripMenuItem.Enabled = false;
@@ -3376,12 +3256,12 @@ namespace OpenTween
                 ReadedStripMenuItem.Enabled = true;
                 UnreadStripMenuItem.Enabled = true;
             }
-            if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.DirectMessage || !this.ExistCurrentPost || _curPost.IsDm)
+            var tab = this.CurrentTab;
+            if (tab.TabType == MyCommon.TabUsageType.DirectMessage || !this.ExistCurrentPost || _curPost.IsDm)
             {
                 FavAddToolStripMenuItem.Enabled = false;
                 FavRemoveToolStripMenuItem.Enabled = false;
                 StatusOpenMenuItem.Enabled = false;
-                FavorareMenuItem.Enabled = false;
                 ShowRelatedStatusesMenuItem.Enabled = false;
 
                 ReTweetStripMenuItem.Enabled = false;
@@ -3395,7 +3275,6 @@ namespace OpenTween
                 FavAddToolStripMenuItem.Enabled = true;
                 FavRemoveToolStripMenuItem.Enabled = true;
                 StatusOpenMenuItem.Enabled = true;
-                FavorareMenuItem.Enabled = true;
                 ShowRelatedStatusesMenuItem.Enabled = true;  //PublicSearchの時問題出るかも
 
                 if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
@@ -3452,18 +3331,14 @@ namespace OpenTween
         }
 
         private void ReplyStripMenuItem_Click(object sender, EventArgs e)
-        {
-            MakeReplyOrDirectStatus(false, true);
-        }
+            => this.MakeReplyOrDirectStatus(false, true);
 
         private void DMStripMenuItem_Click(object sender, EventArgs e)
-        {
-            MakeReplyOrDirectStatus(false, false);
-        }
+            => this.MakeReplyOrDirectStatus(false, false);
 
         private async Task doStatusDelete()
         {
-            if (this._curTab == null || this._curList == null)
+            if (this._curList == null)
                 return;
 
             if (this._curList.SelectedIndices.Count == 0)
@@ -3499,8 +3374,7 @@ namespace OpenTween
                     {
                         if (post.IsDm)
                         {
-                            await this.twitterApi.DirectMessagesDestroy(post.StatusId)
-                                .IgnoreResponse();
+                            await this.twitterApi.DirectMessagesEventsDestroy(post.StatusId.ToString(CultureInfo.InvariantCulture));
                         }
                         else
                         {
@@ -3556,7 +3430,7 @@ namespace OpenTween
                     {
                         listView.VirtualListSize = tab.AllCount;
 
-                        if (tabPage == this._curTab)
+                        if (tabPage == this.CurrentTabPage)
                         {
                             listView.SelectedIndices.Clear();
 
@@ -3588,17 +3462,16 @@ namespace OpenTween
         }
 
         private async void DeleteStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.doStatusDelete();
-        }
+            => await this.doStatusDelete();
 
         private void ReadedStripMenuItem_Click(object sender, EventArgs e)
         {
             using (ControlTransaction.Update(this._curList))
             {
+                var tab = this.CurrentTab;
                 foreach (int idx in _curList.SelectedIndices)
                 {
-                    var post = this._statuses.Tabs[this._curTab.Text][idx];
+                    var post = tab[idx];
                     this._statuses.SetReadAllTab(post.StatusId, read: true);
                     ChangeCacheStyleRead(true, idx);
                 }
@@ -3621,9 +3494,10 @@ namespace OpenTween
         {
             using (ControlTransaction.Update(this._curList))
             {
+                var tab = this.CurrentTab;
                 foreach (int idx in _curList.SelectedIndices)
                 {
-                    var post = this._statuses.Tabs[this._curTab.Text][idx];
+                    var post = tab[idx];
                     this._statuses.SetReadAllTab(post.StatusId, read: false);
                     ChangeCacheStyleRead(false, idx);
                 }
@@ -3643,90 +3517,13 @@ namespace OpenTween
         }
 
         private async void RefreshStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.DoRefresh();
-        }
+            => await this.DoRefresh();
 
         private async Task DoRefresh()
-        {
-            if (_curTab != null)
-            {
-                if (!this._statuses.Tabs.TryGetValue(this._curTab.Text, out var tab))
-                    return;
-
-                switch (tab)
-                {
-                    case MentionsTabModel replyTab:
-                        await this.GetReplyAsync();
-                        break;
-                    case DirectMessagesTabModel dmTab:
-                        await this.GetDirectMessagesAsync();
-                        break;
-                    case FavoritesTabModel favTab:
-                        await this.GetFavoritesAsync();
-                        break;
-                    case PublicSearchTabModel searchTab:
-                        if (string.IsNullOrEmpty(searchTab.SearchWords)) return;
-                        await this.GetPublicSearchAsync(searchTab);
-                        break;
-                    case UserTimelineTabModel userTab:
-                        await this.GetUserTimelineAsync(userTab);
-                        break;
-                    case ListTimelineTabModel listTab:
-                        if (listTab.ListInfo == null || listTab.ListInfo.Id == 0) return;
-                        await this.GetListTimelineAsync(listTab);
-                        break;
-                    default:
-                        await this.GetHomeTimelineAsync();
-                        break;
-                }
-            }
-            else
-            {
-                await this.GetHomeTimelineAsync();
-            }
-        }
+            => await this.RefreshTabAsync(this.CurrentTab);
 
         private async Task DoRefreshMore()
-        {
-            //ページ指定をマイナス1に
-            if (_curTab != null)
-            {
-                if (!this._statuses.Tabs.TryGetValue(this._curTab.Text, out var tab))
-                    return;
-
-                switch (tab)
-                {
-                    case MentionsTabModel replyTab:
-                        await this.GetReplyAsync(loadMore: true);
-                        break;
-                    case DirectMessagesTabModel dmTab:
-                        await this.GetDirectMessagesAsync(loadMore: true);
-                        break;
-                    case FavoritesTabModel favTab:
-                        await this.GetFavoritesAsync(loadMore: true);
-                        break;
-                    case PublicSearchTabModel searchTab:
-                        if (string.IsNullOrEmpty(searchTab.SearchWords)) return;
-                        await this.GetPublicSearchAsync(searchTab, loadMore: true);
-                        break;
-                    case UserTimelineTabModel userTab:
-                        await this.GetUserTimelineAsync(userTab, loadMore: true);
-                        break;
-                    case ListTimelineTabModel listTab:
-                        if (listTab.ListInfo == null || listTab.ListInfo.Id == 0) return;
-                        await this.GetListTimelineAsync(listTab, loadMore: true);
-                        break;
-                    default:
-                        await this.GetHomeTimelineAsync(loadMore: true);
-                        break;
-                }
-            }
-            else
-            {
-                await this.GetHomeTimelineAsync(loadMore: true);
-            }
-        }
+            => await this.RefreshTabAsync(this.CurrentTab, backward: true);
 
         private DialogResult ShowSettingDialog(bool showTaskbarIcon = false)
         {
@@ -4006,7 +3803,7 @@ namespace OpenTween
             this.TopMost = SettingManager.Common.AlwaysTop;
             SaveConfigsAll(false);
 
-            if (tw.Username != oldUser.Username)
+            if (tw.UserId != oldUser.UserId)
                 await this.doGetFollowersMenu();
         }
 
@@ -4138,24 +3935,24 @@ namespace OpenTween
             this.SearchButton_Click(ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"], null);
         }
 
-        private void ShowUserTimeline()
+        private async Task ShowUserTimeline()
         {
             if (!this.ExistCurrentPost) return;
-            AddNewTabForUserTimeline(_curPost.ScreenName);
+            await this.AddNewTabForUserTimeline(_curPost.ScreenName);
         }
 
         private void SearchComboBox_KeyDown(object sender, KeyEventArgs e)
         {
             if (e.KeyCode == Keys.Escape)
             {
-                TabPage relTp = ListTab.SelectedTab;
+                var relTp = this.CurrentTabPage;
                 RemoveSpecifiedTab(relTp.Text, false);
                 SaveConfigsTabs();
                 e.SuppressKeyPress = true;
             }
         }
 
-        public void AddNewTabForUserTimeline(string user)
+        public async Task AddNewTabForUserTimeline(string user)
         {
             //同一検索条件のタブが既に存在すれば、そのタブアクティブにして終了
             foreach (var tb in _statuses.GetTabsByType<UserTimelineTabModel>())
@@ -4186,7 +3983,7 @@ namespace OpenTween
             ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
             SaveConfigsTabs();
             //検索実行
-            this.GetUserTimelineAsync(tab);
+            await this.RefreshTabAsync(tab);
         }
 
         public bool AddNewTab(TabModel tab, bool startup)
@@ -4224,10 +4021,12 @@ namespace OpenTween
 
                 if (userTab != null || listTab != null)
                 {
-                    var label = new Label();
-                    label.Dock = DockStyle.Top;
-                    label.Name = "labelUser";
-                    label.TabIndex = 0;
+                    var label = new Label
+                    {
+                        Dock = DockStyle.Top,
+                        Name = "labelUser",
+                        TabIndex = 0,
+                    };
 
                     if (listTab != null)
                     {
@@ -4494,9 +4293,8 @@ namespace OpenTween
                 _listCustom.ListViewItemSorter = null;
 
                 //キャッシュのクリア
-                if (_curTab.Equals(_tabPage))
+                if (this.CurrentTabPage.Equals(_tabPage))
                 {
-                    _curTab = null;
                     _curItemIndex = -1;
                     _curList = null;
                     _curPost = null;
@@ -4598,10 +4396,12 @@ namespace OpenTween
                 }
             }
 
+            var currentTabPage = this.CurrentTabPage;
+
             //列幅、列並びを他のタブに設定
             foreach (TabPage tb in ListTab.TabPages)
             {
-                if (!tb.Equals(_curTab))
+                if (!tb.Equals(currentTabPage))
                 {
                     if (tb.Tag != null && tb.Controls.Count > 0)
                     {
@@ -4638,14 +4438,10 @@ namespace OpenTween
         }
 
         public void ShowSuplDialog(TextBox owner, AtIdSupplement dialog)
-        {
-            ShowSuplDialog(owner, dialog, 0, "");
-        }
+            => this.ShowSuplDialog(owner, dialog, 0, "");
 
         public void ShowSuplDialog(TextBox owner, AtIdSupplement dialog, int offset)
-        {
-            ShowSuplDialog(owner, dialog, offset, "");
-        }
+            => this.ShowSuplDialog(owner, dialog, offset, "");
 
         public void ShowSuplDialog(TextBox owner, AtIdSupplement dialog, int offset, string startswith)
         {
@@ -4751,13 +4547,39 @@ namespace OpenTween
         }
 
         /// <summary>
+        /// メンション以外の文字列が含まれていないテキストであるか判定します
+        /// </summary>
+        internal static bool TextContainsOnlyMentions(string text)
+        {
+            var mentions = TweetExtractor.ExtractMentionEntities(text).OrderBy(x => x.Indices[0]);
+            var startIndex = 0;
+
+            foreach (var mention in mentions)
+            {
+                var textPart = text.Substring(startIndex, mention.Indices[0] - startIndex);
+
+                if (!string.IsNullOrWhiteSpace(textPart))
+                    return false;
+
+                startIndex = mention.Indices[1];
+            }
+
+            var textPartLast = text.Substring(startIndex);
+
+            if (!string.IsNullOrWhiteSpace(textPartLast))
+                return false;
+
+            return true;
+        }
+
+        /// <summary>
         /// 投稿時に auto_populate_reply_metadata オプションによって自動で追加されるメンションを除去します
         /// </summary>
         private string RemoveAutoPopuratedMentions(string statusText, out long[] autoPopulatedUserIds)
         {
             List<long> _autoPopulatedUserIds = new List<long>();
 
-            var replyToPost = this.inReplyTo != null ? this._statuses[this.inReplyTo.Item1] : null;
+            var replyToPost = this.inReplyTo != null ? this._statuses[this.inReplyTo.Value.StatusId] : null;
             if (replyToPost != null)
             {
                 if (statusText.StartsWith($"@{replyToPost.ScreenName} ", StringComparison.Ordinal))
@@ -4765,12 +4587,12 @@ namespace OpenTween
                     statusText = statusText.Substring(replyToPost.ScreenName.Length + 2);
                     _autoPopulatedUserIds.Add(replyToPost.UserId);
 
-                    foreach (var reply in replyToPost.ReplyToList)
+                    foreach (var (userId, screenName) in replyToPost.ReplyToList)
                     {
-                        if (statusText.StartsWith($"@{reply.Item2} ", StringComparison.Ordinal))
+                        if (statusText.StartsWith($"@{screenName} ", StringComparison.Ordinal))
                         {
-                            statusText = statusText.Substring(reply.Item2.Length + 2);
-                            _autoPopulatedUserIds.Add(reply.Item1);
+                            statusText = statusText.Substring(screenName.Length + 2);
+                            _autoPopulatedUserIds.Add(userId);
                         }
                     }
                 }
@@ -4806,12 +4628,7 @@ namespace OpenTween
         }
 
         private string FormatStatusTextExtended(string statusText)
-        {
-            long[] autoPopulatedUserIds;
-            string attachmentUrl;
-
-            return this.FormatStatusTextExtended(statusText, out autoPopulatedUserIds, out attachmentUrl);
-        }
+            => this.FormatStatusTextExtended(statusText, out var autoPopulatedUserIds, out var attachmentUrl);
 
         /// <summary>
         /// <see cref="FormatStatusText"/> に加えて、拡張モードで140字にカウントされない文字列の除去を行います
@@ -4865,7 +4682,7 @@ namespace OpenTween
                 disableFooter = true;
 
             // 自分宛のリプライの場合は先頭の「@screen_name 」の部分を除去する (in_reply_to_status_id は維持される)
-            if (this.inReplyTo != null && this.inReplyTo.Item2 == this.tw.Username)
+            if (this.inReplyTo != null && this.inReplyTo.Value.ScreenName == this.tw.Username)
             {
                 var mentionSelf = $"@{this.tw.Username} ";
                 if (statusText.StartsWith(mentionSelf, StringComparison.OrdinalIgnoreCase))
@@ -4984,7 +4801,7 @@ namespace OpenTween
 
         private void CreateCache(int startIndex, int endIndex)
         {
-            var tabInfo = this._statuses.Tabs[this._curTab.Text];
+            var tabInfo = this.CurrentTab;
 
             if (tabInfo.AllCount == 0)
                 return;
@@ -4999,9 +4816,10 @@ namespace OpenTween
 
             var cacheLength = endIndex - startIndex + 1;
 
+            var tabPage = this.CurrentTabPage;
             var posts = tabInfo[startIndex, endIndex]; //配列で取得
             var listItems = Enumerable.Range(0, cacheLength)
-                .Select(x => this.CreateItem(this._curTab, posts[x], startIndex + x))
+                .Select(x => this.CreateItem(tabPage, posts[x], startIndex + x))
                 .ToArray();
 
             var listCache = new ListViewItemCache
@@ -5020,9 +4838,7 @@ namespace OpenTween
         /// DetailsListView のための ListViewItem のキャッシュを消去する
         /// </summary>
         private void PurgeListViewItemCache()
-        {
-            Interlocked.Exchange(ref this._listItemCache, null);
-        }
+            => Interlocked.Exchange(ref this._listItemCache, null);
 
         private ListViewItem CreateItem(TabPage Tab, PostClass Post, int Index)
         {
@@ -5064,7 +4880,7 @@ namespace OpenTween
             //未読管理していなかったら既読として扱う
             if (!_statuses.Tabs[Tab.Text].UnreadManage || !SettingManager.Common.UnreadManage) read = true;
             ChangeItemStyleRead(read, itm, Post, null);
-            if (Tab.Equals(_curTab)) ColorizeList(itm, Index);
+            if (Tab.Equals(this.CurrentTabPage)) ColorizeList(itm, Index);
             return itm;
         }
 
@@ -5108,15 +4924,10 @@ namespace OpenTween
         }
 
         private void MyList_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
-        {
-            e.DrawDefault = true;
-        }
+            => e.DrawDefault = true;
 
         private void MyList_HScrolled(object sender, EventArgs e)
-        {
-            DetailsListView listView = (DetailsListView)sender;
-            listView.Refresh();
-        }
+            => ((DetailsListView)sender).Refresh();
 
         private void MyList_DrawItem(object sender, DrawListViewItemEventArgs e)
         {
@@ -5388,7 +5199,7 @@ namespace OpenTween
 
         internal void DoTabSearch(string searchWord, bool caseSensitive, bool useRegex, SEARCHTYPE searchType)
         {
-            var tab = this._statuses.Tabs[this._curTab.Text];
+            var tab = this.CurrentTab;
 
             if (tab.AllCount == 0)
             {
@@ -5448,10 +5259,7 @@ namespace OpenTween
         }
 
         private void MenuItemSubSearch_Click(object sender, EventArgs e)
-        {
-            // 検索メニュー
-            this.ShowSearchDialog();
-        }
+            => this.ShowSearchDialog(); // 検索メニュー
 
         private void MenuItemSearchNext_Click(object sender, EventArgs e)
         {
@@ -5514,14 +5322,14 @@ namespace OpenTween
                     }
                     catch (TabException ex)
                     {
-                        MessageBox.Show(this, ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
+                        MessageBox.Show(this, ex.Message, ApplicationSettings.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                     }
 
                     var resultTab = new LocalSearchTabModel(tabName);
                     this.AddNewTab(resultTab, startup: false);
                     this._statuses.AddTab(resultTab);
 
-                    var targetTab = this._statuses.Tabs[this._curTab.Text];
+                    var targetTab = this.CurrentTab;
 
                     Func<string, bool> stringComparer;
                     try
@@ -5602,7 +5410,7 @@ namespace OpenTween
 
         private void JumpUnreadMenuItem_Click(object sender, EventArgs e)
         {
-            int bgnIdx = ListTab.TabPages.IndexOf(_curTab);
+            int bgnIdx = ListTab.TabPages.IndexOf(this.CurrentTabPage);
 
             if (ImageSelector.Enabled)
                 return;
@@ -5691,34 +5499,27 @@ namespace OpenTween
 
         private async void StatusOpenMenuItem_Click(object sender, EventArgs e)
         {
-            if (_curList.SelectedIndices.Count > 0 && _statuses.Tabs[_curTab.Text].TabType != MyCommon.TabUsageType.DirectMessage)
+            var tab = this.CurrentTab;
+            if (_curList.SelectedIndices.Count > 0 && tab.TabType != MyCommon.TabUsageType.DirectMessage)
             {
-                var post = _statuses.Tabs[_curTab.Text][_curList.SelectedIndices[0]];
+                var post = tab[_curList.SelectedIndices[0]];
                 await this.OpenUriInBrowserAsync(MyCommon.GetStatusUrl(post));
             }
         }
 
-        private async void FavorareMenuItem_Click(object sender, EventArgs e)
-        {
-            if (_curList.SelectedIndices.Count > 0)
-            {
-                PostClass post = _statuses.Tabs[_curTab.Text][_curList.SelectedIndices[0]];
-                await this.OpenUriInBrowserAsync(Properties.Resources.FavstarUrl + "users/" + post.ScreenName + "/recent");
-            }
-        }
-
         private async void VerUpMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.CheckNewVersion(false);
-        }
+            => await this.CheckNewVersion(false);
 
         private void RunTweenUp()
         {
-            ProcessStartInfo pinfo = new ProcessStartInfo();
-            pinfo.UseShellExecute = true;
-            pinfo.WorkingDirectory = MyCommon.settingPath;
-            pinfo.FileName = Path.Combine(MyCommon.settingPath, "TweenUp3.exe");
-            pinfo.Arguments = "\"" + Application.StartupPath + "\"";
+            var pinfo = new ProcessStartInfo
+            {
+                UseShellExecute = true,
+                WorkingDirectory = MyCommon.settingPath,
+                FileName = Path.Combine(MyCommon.settingPath, "TweenUp3.exe"),
+                Arguments = "\"" + Application.StartupPath + "\"",
+            };
+
             try
             {
                 Process.Start(pinfo);
@@ -5788,6 +5589,9 @@ namespace OpenTween
                     return;
                 }
 
+                if (startup && versionInfo.Version <= SettingManager.Common.SkipUpdateVersion)
+                    return;
+
                 using (var dialog = new UpdateDialog())
                 {
                     dialog.SummaryText = string.Format(Properties.Resources.CheckNewVersionText3,
@@ -5798,6 +5602,11 @@ namespace OpenTween
                     {
                         await this.OpenUriInBrowserAsync(versionInfo.DownloadUri.OriginalString);
                     }
+                    else if (dialog.SkipButtonPressed)
+                    {
+                        SettingManager.Common.SkipUpdateVersion = versionInfo.Version;
+                        this.ModifySettingCommon = true;
+                    }
                 }
             }
             catch (Exception)
@@ -5840,17 +5649,10 @@ namespace OpenTween
         }
 
         public string createDetailHtml(string orgdata)
-        {
-            if (SettingManager.Local.UseTwemoji)
-                orgdata = EmojiFormatter.ReplaceEmojiToImg(orgdata);
-
-            return detailHtmlFormatHeader + orgdata + detailHtmlFormatFooter;
-        }
+            => detailHtmlFormatHeader + orgdata + detailHtmlFormatFooter;
 
         private Task DispSelectedPost()
-        {
-            return this.DispSelectedPost(false);
-        }
+            => this.DispSelectedPost(false);
 
         private PostClass displayPost = new PostClass();
 
@@ -5894,47 +5696,39 @@ namespace OpenTween
         }
 
         private async void MatomeMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.OpenApplicationWebsite();
-        }
+            => await this.OpenApplicationWebsite();
 
         private async Task OpenApplicationWebsite()
-        {
-            await this.OpenUriInBrowserAsync(ApplicationSettings.WebsiteUrl);
-        }
+            => await this.OpenUriInBrowserAsync(ApplicationSettings.WebsiteUrl);
 
         private async void ShortcutKeyListMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.OpenUriInBrowserAsync(ApplicationSettings.ShortcutKeyUrl);
-        }
+            => await this.OpenUriInBrowserAsync(ApplicationSettings.ShortcutKeyUrl);
 
         private async void ListTab_KeyDown(object sender, KeyEventArgs e)
         {
-            if (ListTab.SelectedTab != null)
+            var tab = this.CurrentTab;
+            if (tab.TabType == MyCommon.TabUsageType.PublicSearch)
             {
-                if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.PublicSearch)
-                {
-                    Control pnl = ListTab.SelectedTab.Controls["panelSearch"];
-                    if (pnl.Controls["comboSearch"].Focused ||
-                        pnl.Controls["comboLang"].Focused ||
-                        pnl.Controls["buttonSearch"].Focused) return;
-                }
-
-                if (e.Control || e.Shift || e.Alt)
-                    this._anchorFlag = false;
+                Control pnl = ListTab.SelectedTab.Controls["panelSearch"];
+                if (pnl.Controls["comboSearch"].Focused ||
+                    pnl.Controls["comboLang"].Focused ||
+                    pnl.Controls["buttonSearch"].Focused) return;
+            }
 
-                if (CommonKeyDown(e.KeyData, FocusedControl.ListTab, out var asyncTask))
-                {
-                    e.Handled = true;
-                    e.SuppressKeyPress = true;
-                }
+            if (e.Control || e.Shift || e.Alt)
+                this._anchorFlag = false;
 
-                if (asyncTask != null)
-                    await asyncTask;
+            if (CommonKeyDown(e.KeyData, FocusedControl.ListTab, out var asyncTask))
+            {
+                e.Handled = true;
+                e.SuppressKeyPress = true;
             }
+
+            if (asyncTask != null)
+                await asyncTask;
         }
 
-        private ShortcutCommand[] shortcutCommands = new ShortcutCommand[0];
+        private ShortcutCommand[] shortcutCommands = Array.Empty<ShortcutCommand>();
 
         private void InitializeShortcuts()
         {
@@ -5967,10 +5761,10 @@ namespace OpenTween
                     .Do(() => this.DoRefresh()),
 
                 ShortcutCommand.Create(Keys.F6)
-                    .Do(() => this.GetReplyAsync()),
+                    .Do(() => this.RefreshTabAsync<MentionsTabModel>()),
 
                 ShortcutCommand.Create(Keys.F7)
-                    .Do(() => this.GetDirectMessagesAsync()),
+                    .Do(() => this.RefreshTabAsync<DirectMessagesTabModel>()),
 
                 ShortcutCommand.Create(Keys.Space, Keys.ProcessKey)
                     .NotFocusedOn(FocusedControl.StatusText)
@@ -6039,15 +5833,12 @@ namespace OpenTween
                     .FocusedOn(FocusedControl.ListTab)
                     .Do(() => {
                         this._anchorFlag = false;
-                        if (ListTab.SelectedTab != null)
+                        var tab = this.CurrentTab;
+                        var tabtype = tab.TabType;
+                        if (tabtype == MyCommon.TabUsageType.Related || tabtype == MyCommon.TabUsageType.UserTimeline || tabtype == MyCommon.TabUsageType.PublicSearch || tabtype == MyCommon.TabUsageType.SearchResults)
                         {
-                            var tabtype = _statuses.Tabs[ListTab.SelectedTab.Text].TabType;
-                            if (tabtype == MyCommon.TabUsageType.Related || tabtype == MyCommon.TabUsageType.UserTimeline || tabtype == MyCommon.TabUsageType.PublicSearch || tabtype == MyCommon.TabUsageType.SearchResults)
-                            {
-                                var relTp = ListTab.SelectedTab;
-                                RemoveSpecifiedTab(relTp.Text, false);
-                                SaveConfigsTabs();
-                            }
+                            RemoveSpecifiedTab(tab.TabName, false);
+                            SaveConfigsTabs();
                         }
                     }),
 
@@ -6181,45 +5972,11 @@ namespace OpenTween
 
                 ShortcutCommand.Create(Keys.Control | Keys.Up)
                     .FocusedOn(FocusedControl.StatusText)
-                    .Do(() => {
-                        if (!string.IsNullOrWhiteSpace(StatusText.Text))
-                        {
-                            var inReplyToStatusId = this.inReplyTo?.Item1;
-                            var inReplyToScreenName = this.inReplyTo?.Item2;
-                            _history[_hisIdx] = new StatusTextHistory(StatusText.Text, inReplyToStatusId, inReplyToScreenName);
-                        }
-                        _hisIdx -= 1;
-                        if (_hisIdx < 0) _hisIdx = 0;
-
-                        var historyItem = this._history[this._hisIdx];
-                        if (historyItem.inReplyToId != null)
-                            this.inReplyTo = Tuple.Create(historyItem.inReplyToId.Value, historyItem.inReplyToName);
-                        else
-                            this.inReplyTo = null;
-                        StatusText.Text = historyItem.status;
-                        StatusText.SelectionStart = StatusText.Text.Length;
-                    }),
+                    .Do(() => this.StatusTextHistoryBack()),
 
                 ShortcutCommand.Create(Keys.Control | Keys.Down)
                     .FocusedOn(FocusedControl.StatusText)
-                    .Do(() => {
-                        if (!string.IsNullOrWhiteSpace(StatusText.Text))
-                        {
-                            var inReplyToStatusId = this.inReplyTo?.Item1;
-                            var inReplyToScreenName = this.inReplyTo?.Item2;
-                            _history[_hisIdx] = new StatusTextHistory(StatusText.Text, inReplyToStatusId, inReplyToScreenName);
-                        }
-                        _hisIdx += 1;
-                        if (_hisIdx > _history.Count - 1) _hisIdx = _history.Count - 1;
-
-                        var historyItem = this._history[this._hisIdx];
-                        if (historyItem.inReplyToId != null)
-                            this.inReplyTo = Tuple.Create(historyItem.inReplyToId.Value, historyItem.inReplyToName);
-                        else
-                            this.inReplyTo = null;
-                        StatusText.Text = historyItem.status;
-                        StatusText.SelectionStart = StatusText.Text.Length;
-                    }),
+                    .Do(() => this.StatusTextHistoryForward()),
 
                 ShortcutCommand.Create(Keys.Control | Keys.PageUp, Keys.Control | Keys.P)
                     .FocusedOn(FocusedControl.StatusText)
@@ -6265,10 +6022,10 @@ namespace OpenTween
                     .Do(() => this.DoRefreshMore()),
 
                 ShortcutCommand.Create(Keys.Shift | Keys.F6)
-                    .Do(() => this.GetReplyAsync(loadMore: true)),
+                    .Do(() => this.RefreshTabAsync<MentionsTabModel>(backward: true)),
 
                 ShortcutCommand.Create(Keys.Shift | Keys.F7)
-                    .Do(() => this.GetDirectMessagesAsync(loadMore: true)),
+                    .Do(() => this.RefreshTabAsync<DirectMessagesTabModel>(backward: true)),
 
                 ShortcutCommand.Create(Keys.Shift | Keys.R)
                     .NotFocusedOn(FocusedControl.StatusText)
@@ -6351,9 +6108,8 @@ namespace OpenTween
                     .Do(() => this.CopyIdUri()),
 
                 ShortcutCommand.Create(Keys.Control | Keys.Shift | Keys.F)
-                    .OnlyWhen(() => this.ListTab.SelectedTab != null &&
-                        this._statuses.Tabs[this.ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.PublicSearch)
-                    .Do(() => this.ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"].Focus()),
+                    .OnlyWhen(() => this.CurrentTab.TabType == MyCommon.TabUsageType.PublicSearch)
+                    .Do(() => this.CurrentTabPage.Controls["panelSearch"].Controls["comboSearch"].Focus()),
 
                 ShortcutCommand.Create(Keys.Control | Keys.Shift | Keys.S)
                     .Do(() => this.FavoriteChange(FavAdd: false)),
@@ -6370,9 +6126,6 @@ namespace OpenTween
                 ShortcutCommand.Create(Keys.Control | Keys.Shift | Keys.H)
                     .Do(() => this.doMoveToRTHome()),
 
-                ShortcutCommand.Create(Keys.Control | Keys.Shift | Keys.O)
-                    .Do(() => this.FavorareMenuItem_Click(null, null)),
-
                 ShortcutCommand.Create(Keys.Control | Keys.Shift | Keys.Up)
                     .FocusedOn(FocusedControl.StatusText)
                     .Do(() => {
@@ -6469,12 +6222,15 @@ namespace OpenTween
                     .Do(() => this.SetSortLastColumn()),
 
                 ShortcutCommand.Create(Keys.Control | Keys.Alt | Keys.S)
+                    .FocusedOn(FocusedControl.ListTab)
                     .Do(() => this.FavoritesRetweetOfficial()),
 
                 ShortcutCommand.Create(Keys.Control | Keys.Alt | Keys.R)
+                    .FocusedOn(FocusedControl.ListTab)
                     .Do(() => this.FavoritesRetweetUnofficial()),
 
                 ShortcutCommand.Create(Keys.Control | Keys.Alt | Keys.H)
+                    .FocusedOn(FocusedControl.ListTab)
                     .Do(() => this.OpenUserAppointUrl()),
 
                 ShortcutCommand.Create(Keys.Alt | Keys.Shift | Keys.R)
@@ -6542,12 +6298,12 @@ namespace OpenTween
         {
             string clstr = "";
             StringBuilder sb = new StringBuilder();
+            var tab = this.CurrentTab;
             bool IsProtected = false;
-            bool isDm = false;
-            if (this._curTab != null && this._statuses.GetTabByName(this._curTab.Text) != null) isDm = this._statuses.GetTabByName(this._curTab.Text).TabType == MyCommon.TabUsageType.DirectMessage;
+            var isDm = tab.TabType == MyCommon.TabUsageType.DirectMessage;
             foreach (int idx in _curList.SelectedIndices)
             {
-                PostClass post = _statuses.Tabs[_curTab.Text][idx];
+                var post = tab[idx];
                 if (post.IsDeleted) continue;
                 if (!isDm)
                 {
@@ -6581,10 +6337,7 @@ namespace OpenTween
 
         private void CopyIdUri()
         {
-            if (this._curTab == null)
-                return;
-
-            var tab = this._statuses.GetTabByName(this._curTab.Text);
+            var tab = this.CurrentTab;
             if (tab == null || tab is DirectMessagesTabModel)
                 return;
 
@@ -6644,9 +6397,10 @@ namespace OpenTween
                 stp = -1;
             }
 
+            var tab = this.CurrentTab;
             for (int idx = fIdx; idx != toIdx; idx += stp)
             {
-                if (_statuses.Tabs[_curTab.Text][idx].IsFav)
+                if (tab[idx].IsFav)
                 {
                     SelectListItem(_curList, idx);
                     _curList.EnsureVisible(idx);
@@ -6660,7 +6414,7 @@ namespace OpenTween
             if (this._curList.SelectedIndices.Count == 0)
                 return;
 
-            var tab = this._statuses.Tabs[this._curTab.Text];
+            var tab = this.CurrentTab;
 
             // Directタブは対象外(見つかるはずがない)
             if (tab.TabType == MyCommon.TabUsageType.DirectMessage)
@@ -6724,7 +6478,7 @@ namespace OpenTween
             if (_curList.SelectedIndices.Count == 0 || _curPost == null)
                 return;
 
-            var tab = this._statuses.Tabs[this._curTab.Text];
+            var tab = this.CurrentTab;
             var selectedIndex = this._curList.SelectedIndices[0];
 
             int fIdx, toIdx, stp;
@@ -6782,7 +6536,7 @@ namespace OpenTween
             if (this._curList.SelectedIndices.Count == 0)
                 return;
 
-            var tab = this._statuses.Tabs[this._curTab.Text];
+            var tab = this.CurrentTab;
             var selectedIndex = this._curList.SelectedIndices[0];
 
             int fIdx, toIdx, stp;
@@ -6820,10 +6574,10 @@ namespace OpenTween
                     post.RetweetedBy == _anchorPost.ScreenName ||
                     post.ScreenName == _anchorPost.RetweetedBy ||
                     (!string.IsNullOrEmpty(post.RetweetedBy) && post.RetweetedBy == _anchorPost.RetweetedBy) ||
-                    _anchorPost.ReplyToList.Any(x => x.Item1 == post.UserId) ||
-                    _anchorPost.ReplyToList.Any(x => x.Item1 == post.RetweetedByUserId) ||
-                    post.ReplyToList.Any(x => x.Item1 == _anchorPost.UserId) ||
-                    post.ReplyToList.Any(x => x.Item1 == _anchorPost.RetweetedByUserId))
+                    _anchorPost.ReplyToList.Any(x => x.UserId == post.UserId) ||
+                    _anchorPost.ReplyToList.Any(x => x.UserId == post.RetweetedByUserId) ||
+                    post.ReplyToList.Any(x => x.UserId == _anchorPost.UserId) ||
+                    post.ReplyToList.Any(x => x.UserId == _anchorPost.RetweetedByUserId))
                 {
                     SelectListItem(_curList, idx);
                     _curList.EnsureVisible(idx);
@@ -6835,7 +6589,7 @@ namespace OpenTween
         private void GoAnchor()
         {
             if (_anchorPost == null) return;
-            int idx = _statuses.Tabs[_curTab.Text].IndexOf(_anchorPost.StatusId);
+            int idx = this.CurrentTab.IndexOf(_anchorPost.StatusId);
             if (idx == -1) return;
 
             SelectListItem(_curList, idx);
@@ -6938,7 +6692,7 @@ namespace OpenTween
         {
             if (_curPost == null) return;
 
-            TabModel curTabClass = _statuses.Tabs[_curTab.Text];
+            var curTabClass = this.CurrentTab;
 
             if (curTabClass.TabType == MyCommon.TabUsageType.PublicSearch && _curPost.InReplyToStatusId == null && _curPost.TextFromApi.Contains("@"))
             {
@@ -6964,7 +6718,7 @@ namespace OpenTween
             {
                 replyChains = new Stack<ReplyChain>();
             }
-            replyChains.Push(new ReplyChain(_curPost.StatusId, _curPost.InReplyToStatusId.Value, _curTab));
+            replyChains.Push(new ReplyChain(_curPost.StatusId, _curPost.InReplyToStatusId.Value, this.CurrentTabPage));
 
             int inReplyToIndex;
             string inReplyToTabName;
@@ -7017,7 +6771,7 @@ namespace OpenTween
             TabPage tabPage = this.ListTab.TabPages.Cast<TabPage>().First((tp) => { return tp.Text == inReplyToTabName; });
             DetailsListView listView = (DetailsListView)tabPage.Tag;
 
-            if (_curTab != tabPage)
+            if (this.CurrentTabPage != tabPage)
             {
                 this.ListTab.SelectTab(tabPage);
             }
@@ -7030,7 +6784,7 @@ namespace OpenTween
         {
             if (_curPost == null) return;
 
-            TabModel curTabClass = _statuses.Tabs[_curTab.Text];
+            var curTabClass = this.CurrentTab;
             //Dictionary<long, PostClass> curTabPosts = curTabClass.Posts;
 
             if (parallel)
@@ -7184,24 +6938,25 @@ namespace OpenTween
 
         private void PushSelectPostChain()
         {
+            var currentTabPage = this.CurrentTabPage;
             int count = this.selectPostChains.Count;
             if (count > 0)
             {
                 var (tabPage, post) = this.selectPostChains.Peek();
-                if (tabPage == this._curTab)
+                if (tabPage == currentTabPage)
                 {
                     if (post == this._curPost) return;  //最新の履歴と同一
                     if (post == null) this.selectPostChains.Pop();  //置き換えるため削除
                 }
             }
             if (count >= 2500) TrimPostChain();
-            this.selectPostChains.Push((this._curTab, this._curPost));
+            this.selectPostChains.Push((currentTabPage, this._curPost));
         }
 
         private void TrimPostChain()
         {
             if (this.selectPostChains.Count <= 2000) return;
-            var p = new Stack<ValueTuple<TabPage, PostClass>>(2000);
+            var p = new Stack<(TabPage, PostClass)>(2000);
             for (int i = 0; i < 2000; i++)
             {
                 p.Push(this.selectPostChains.Pop());
@@ -7248,9 +7003,7 @@ namespace OpenTween
         }
 
         private void MyList_MouseClick(object sender, MouseEventArgs e)
-        {
-            _anchorFlag = false;
-        }
+            => this._anchorFlag = false;
 
         private void StatusText_Enter(object sender, EventArgs e)
         {
@@ -7411,7 +7164,7 @@ namespace OpenTween
 
             var tabs = this.ListTab.TabPages.Cast<TabPage>()
                 .Select(x => this._statuses.Tabs[x.Text])
-                .Concat(new[] { this._statuses.GetTabByType(MyCommon.TabUsageType.Mute) });
+                .Append(this._statuses.GetTabByType(MyCommon.TabUsageType.Mute));
 
             foreach (var tab in tabs)
             {
@@ -7473,18 +7226,20 @@ namespace OpenTween
             }
             catch (TabException ex)
             {
-                MessageBox.Show(this, ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
+                MessageBox.Show(this, ex.Message, ApplicationSettings.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error);
             }
         }
 
         private void SaveLogMenuItem_Click(object sender, EventArgs e)
         {
+            var tab = this.CurrentTab;
+
             DialogResult rslt = MessageBox.Show(string.Format(Properties.Resources.SaveLogMenuItem_ClickText1, Environment.NewLine),
                     Properties.Resources.SaveLogMenuItem_ClickText2,
                     MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
             if (rslt == DialogResult.Cancel) return;
 
-            SaveFileDialog1.FileName = $"{MyCommon.GetAssemblyName()}Posts{DateTimeUtc.Now.ToLocalTime():yyMMdd-HHmmss}.tsv";
+            SaveFileDialog1.FileName = $"{ApplicationSettings.AssemblyName}Posts{DateTimeUtc.Now.ToLocalTime():yyMMdd-HHmmss}.tsv";
             SaveFileDialog1.InitialDirectory = Application.ExecutablePath;
             SaveFileDialog1.Filter = Properties.Resources.SaveLogMenuItem_ClickText3;
             SaveFileDialog1.FilterIndex = 0;
@@ -7501,7 +7256,7 @@ namespace OpenTween
                         //All
                         for (int idx = 0; idx < _curList.VirtualListSize; idx++)
                         {
-                            PostClass post = _statuses.Tabs[_curTab.Text][idx];
+                            var post = tab[idx];
                             string protect = "";
                             if (post.IsProtect) protect = "Protect";
                             sw.WriteLine(post.Nickname + "\t" +
@@ -7518,7 +7273,7 @@ namespace OpenTween
                     {
                         foreach (int idx in _curList.SelectedIndices)
                         {
-                            PostClass post = _statuses.Tabs[_curTab.Text][idx];
+                            var post = tab[idx];
                             string protect = "";
                             if (post.IsProtect) protect = "Protect";
                             sw.WriteLine(post.Nickname + "\t" +
@@ -7598,9 +7353,7 @@ namespace OpenTween
         }
 
         private void ListTab_DoubleClick(object sender, MouseEventArgs e)
-        {
-            TabRename(this.ListTab.SelectedTab.Text, out var _);
-        }
+            => this.TabRename(this.CurrentTabName, out var _);
 
         private void ListTab_MouseDown(object sender, MouseEventArgs e)
         {
@@ -7704,9 +7457,10 @@ namespace OpenTween
             //isReply:true=@,false=DM
             if (!StatusText.Enabled) return;
             if (_curList == null) return;
-            if (_curTab == null) return;
             if (!this.ExistCurrentPost) return;
 
+            var tab = this.CurrentTab;
+
             // 複数あてリプライはReplyではなく通常ポスト
             //↑仕様変更で全部リプライ扱いでOK(先頭ドット付加しない)
             //090403暫定でドットを付加しないようにだけ修正。単独と複数の処理は統合できると思われる。
@@ -7718,7 +7472,7 @@ namespace OpenTween
                 if (_curList.SelectedIndices.Count == 1 && !isAll && this.ExistCurrentPost)
                 {
                     // 単独ユーザー宛リプライまたはDM
-                    if ((_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.DirectMessage && isAuto) || (!isAuto && !isReply))
+                    if ((tab.TabType == MyCommon.TabUsageType.DirectMessage && isAuto) || (!isAuto && !isReply))
                     {
                         // ダイレクトメッセージ
                         this.inReplyTo = null;
@@ -7732,7 +7486,7 @@ namespace OpenTween
                         //空の場合
                         var inReplyToStatusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
                         var inReplyToScreenName = this._curPost.ScreenName;
-                        this.inReplyTo = Tuple.Create(inReplyToStatusId, inReplyToScreenName);
+                        this.inReplyTo = (inReplyToStatusId, inReplyToScreenName);
 
                         // ステータステキストが入力されていない場合先頭に@ユーザー名を追加する
                         StatusText.Text = "@" + _curPost.ScreenName + " ";
@@ -7746,12 +7500,12 @@ namespace OpenTween
                             //1件選んでEnter or DoubleClick
                             if (StatusText.Text.Contains("@" + _curPost.ScreenName + " "))
                             {
-                                if (this.inReplyTo?.Item2 == _curPost.ScreenName)
+                                if (this.inReplyTo?.ScreenName == _curPost.ScreenName)
                                 {
                                     //返信先書き換え
                                     var inReplyToStatusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
                                     var inReplyToScreenName = this._curPost.ScreenName;
-                                    this.inReplyTo = Tuple.Create(inReplyToStatusId, inReplyToScreenName);
+                                    this.inReplyTo = (inReplyToStatusId, inReplyToScreenName);
                                 }
                                 return;
                             }
@@ -7769,7 +7523,7 @@ namespace OpenTween
                                     // 単独リプライ
                                     var inReplyToStatusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
                                     var inReplyToScreenName = this._curPost.ScreenName;
-                                    this.inReplyTo = Tuple.Create(inReplyToStatusId, inReplyToScreenName);
+                                    this.inReplyTo = (inReplyToStatusId, inReplyToScreenName);
                                     StatusText.Text = "@" + _curPost.ScreenName + " " + StatusText.Text;
                                 }
                             }
@@ -7835,7 +7589,7 @@ namespace OpenTween
                         }
                         for (int cnt = 0; cnt < _curList.SelectedIndices.Count; cnt++)
                         {
-                            PostClass post = _statuses.Tabs[_curTab.Text][_curList.SelectedIndices[cnt]];
+                            PostClass post = tab[_curList.SelectedIndices[cnt]];
                             if (!sTxt.Contains("@" + post.ScreenName + " "))
                             {
                                 sTxt = sTxt.Insert(2, "@" + post.ScreenName + " ");
@@ -7855,24 +7609,23 @@ namespace OpenTween
                             int sidx = StatusText.SelectionStart;
                             for (int cnt = 0; cnt < _curList.SelectedIndices.Count; cnt++)
                             {
-                                PostClass post = _statuses.Tabs[_curTab.Text][_curList.SelectedIndices[cnt]];
-                                if (!ids.Contains("@" + post.ScreenName + " ") &&
-                                    !post.ScreenName.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
+                                PostClass post = tab[_curList.SelectedIndices[cnt]];
+                                if (!ids.Contains("@" + post.ScreenName + " ") && post.UserId != tw.UserId)
                                 {
                                     ids += "@" + post.ScreenName + " ";
                                 }
                                 if (isAll)
                                 {
-                                    foreach (string nm in post.ReplyToList.Select(x => x.Item2))
+                                    foreach (var (_, screenName) in post.ReplyToList)
                                     {
-                                        if (!ids.Contains("@" + nm + " ") &&
-                                            !nm.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
+                                        if (!ids.Contains("@" + screenName + " ") &&
+                                            !screenName.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
                                         {
-                                            Match m = Regex.Match(post.TextFromApi, "[@@](?<id>" + nm + ")([^a-zA-Z0-9]|$)", RegexOptions.IgnoreCase);
+                                            Match m = Regex.Match(post.TextFromApi, "[@@](?<id>" + screenName + ")([^a-zA-Z0-9]|$)", RegexOptions.IgnoreCase);
                                             if (m.Success)
                                                 ids += "@" + m.Result("${id}") + " ";
                                             else
-                                                ids += "@" + nm + " ";
+                                                ids += "@" + screenName + " ";
                                         }
                                     }
                                 }
@@ -7914,27 +7667,25 @@ namespace OpenTween
                             string ids = "";
                             int sidx = StatusText.SelectionStart;
                             PostClass post = _curPost;
-                            if (!ids.Contains("@" + post.ScreenName + " ") &&
-                                !post.ScreenName.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
+                            if (!ids.Contains("@" + post.ScreenName + " ") && post.UserId != tw.UserId)
                             {
                                 ids += "@" + post.ScreenName + " ";
                             }
-                            foreach (string nm in post.ReplyToList.Select(x => x.Item2))
+                            foreach (var (_, screenName) in post.ReplyToList)
                             {
-                                if (!ids.Contains("@" + nm + " ") &&
-                                    !nm.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
+                                if (!ids.Contains("@" + screenName + " ") &&
+                                    !screenName.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
                                 {
-                                    Match m = Regex.Match(post.TextFromApi, "[@@](?<id>" + nm + ")([^a-zA-Z0-9]|$)", RegexOptions.IgnoreCase);
+                                    Match m = Regex.Match(post.TextFromApi, "[@@](?<id>" + screenName + ")([^a-zA-Z0-9]|$)", RegexOptions.IgnoreCase);
                                     if (m.Success)
                                         ids += "@" + m.Result("${id}") + " ";
                                     else
-                                        ids += "@" + nm + " ";
+                                        ids += "@" + screenName + " ";
                                 }
                             }
                             if (!string.IsNullOrEmpty(post.RetweetedBy))
                             {
-                                if (!ids.Contains("@" + post.RetweetedBy + " ") &&
-                                   !post.RetweetedBy.Equals(tw.Username, StringComparison.CurrentCultureIgnoreCase))
+                                if (!ids.Contains("@" + post.RetweetedBy + " ") && post.RetweetedByUserId != tw.UserId)
                                 {
                                     ids += "@" + post.RetweetedBy + " ";
                                 }
@@ -7945,7 +7696,7 @@ namespace OpenTween
                                 //未入力の場合のみ返信先付加
                                 var inReplyToStatusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
                                 var inReplyToScreenName = this._curPost.ScreenName;
-                                this.inReplyTo = Tuple.Create(inReplyToStatusId, inReplyToScreenName);
+                                this.inReplyTo = (inReplyToStatusId, inReplyToScreenName);
 
                                 StatusText.Text = ids;
                                 StatusText.SelectionStart = ids.Length;
@@ -7974,9 +7725,7 @@ namespace OpenTween
         }
 
         private void ListTab_MouseUp(object sender, MouseEventArgs e)
-        {
-            _tabDrag = false;
-        }
+            => this._tabDrag = false;
 
         private static int iconCnt = 0;
         private static int blinkCnt = 0;
@@ -8072,21 +7821,13 @@ namespace OpenTween
         }
 
         private async void TimerRefreshIcon_Tick(object sender, EventArgs e)
-        {
-            //200ms
-            await this.RefreshTasktrayIcon();
-        }
+            => await this.RefreshTasktrayIcon(); // 200ms
 
         private void ContextMenuTabProperty_Opening(object sender, CancelEventArgs e)
         {
             //右クリックの場合はタブ名が設定済。アプリケーションキーの場合は現在のタブを対象とする
             if (string.IsNullOrEmpty(_rclickTabName) || sender != ContextMenuTabProperty)
-            {
-                if (ListTab != null && ListTab.SelectedTab != null)
-                    _rclickTabName = ListTab.SelectedTab.Text;
-                else
-                    return;
-            }
+                _rclickTabName = this.CurrentTabName;
 
             if (_statuses == null) return;
             if (_statuses.Tabs == null) return;
@@ -8201,7 +7942,7 @@ namespace OpenTween
                     ListTab.TabPages[idx].ImageIndex = -1;
             }
 
-            if (_curTab.Text == tabName)
+            if (this.CurrentTabName == tabName)
             {
                 this.PurgeListViewItemCache();
                 _curList.Refresh();
@@ -8235,7 +7976,8 @@ namespace OpenTween
 
         private void DeleteTabMenuItem_Click(object sender, EventArgs e)
         {
-            if (string.IsNullOrEmpty(_rclickTabName) || sender == this.DeleteTbMenuItem) _rclickTabName = ListTab.SelectedTab.Text;
+            if (string.IsNullOrEmpty(_rclickTabName) || sender == this.DeleteTbMenuItem)
+                _rclickTabName = this.CurrentTabName;
 
             RemoveSpecifiedTab(_rclickTabName, true);
             SaveConfigsTabs();
@@ -8257,7 +7999,7 @@ namespace OpenTween
             SaveConfigsTabs();
         }
 
-        private void AddTabMenuItem_Click(object sender, EventArgs e)
+        private async void AddTabMenuItem_Click(object sender, EventArgs e)
         {
             string tabName = null;
             MyCommon.TabUsageType tabUsage;
@@ -8318,8 +8060,7 @@ namespace OpenTween
                     if (tabUsage == MyCommon.TabUsageType.Lists)
                     {
                         ListTab.SelectedIndex = ListTab.TabPages.Count - 1;
-                        var listTab = (ListTimelineTabModel)this._statuses.Tabs[this._curTab.Text];
-                        this.GetListTimelineAsync(listTab);
+                        await this.RefreshTabAsync(this.CurrentTab);
                     }
                 }
             }
@@ -8338,13 +8079,14 @@ namespace OpenTween
                     if (!SelectTab(out var tabName)) return;
 
                     fltDialog.SetCurrent(tabName);
-                    if (_statuses.Tabs[_curTab.Text][idx].RetweetedId == null)
+                    var post = this.CurrentTab[idx];
+                    if (post.RetweetedId == null)
                     {
-                        fltDialog.AddNewFilter(_statuses.Tabs[_curTab.Text][idx].ScreenName, _statuses.Tabs[_curTab.Text][idx].TextFromApi);
+                        fltDialog.AddNewFilter(post.ScreenName, post.TextFromApi);
                     }
                     else
                     {
-                        fltDialog.AddNewFilter(_statuses.Tabs[_curTab.Text][idx].RetweetedBy, _statuses.Tabs[_curTab.Text][idx].TextFromApi);
+                        fltDialog.AddNewFilter(post.RetweetedBy, post.TextFromApi);
                     }
                     fltDialog.ShowDialog(this);
                     this.TopMost = SettingManager.Common.AlwaysTop;
@@ -8353,11 +8095,9 @@ namespace OpenTween
 
             this.ApplyPostFilters();
             SaveConfigsTabs();
-            if (this.ListTab.SelectedTab != null &&
-                ((DetailsListView)this.ListTab.SelectedTab.Tag).SelectedIndices.Count > 0)
-            {
-                _curPost = _statuses.Tabs[this.ListTab.SelectedTab.Text][((DetailsListView)this.ListTab.SelectedTab.Tag).SelectedIndices[0]];
-            }
+
+            if (_curList.SelectedIndices.Count > 0)
+                _curPost = this.CurrentTab[_curList.SelectedIndices[0]];
         }
 
         protected override bool ProcessDialogKey(Keys keyData)
@@ -8432,12 +8172,19 @@ namespace OpenTween
                         return true;
                     }
                 }
-                else if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.PublicSearch &&
-                         (ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"].Focused ||
-                         ListTab.SelectedTab.Controls["panelSearch"].Controls["comboLang"].Focused))
+                else
                 {
-                    this.SearchButton_Click(ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"], null);
-                    return true;
+                    var tab = this.CurrentTab;
+                    if (tab.TabType == MyCommon.TabUsageType.PublicSearch)
+                    {
+                        var tabPage = this.CurrentTabPage;
+                        if (tabPage.Controls["panelSearch"].Controls["comboSearch"].Focused ||
+                            tabPage.Controls["panelSearch"].Controls["comboLang"].Focused)
+                        {
+                            this.SearchButton_Click(tabPage.Controls["panelSearch"].Controls["comboSearch"], null);
+                            return true;
+                        }
+                    }
                 }
             }
 
@@ -8445,16 +8192,14 @@ namespace OpenTween
         }
 
         private void ReplyAllStripMenuItem_Click(object sender, EventArgs e)
-        {
-            MakeReplyOrDirectStatus(false, true, true);
-        }
+            => this.MakeReplyOrDirectStatus(false, true, true);
 
         private void IDRuleMenuItem_Click(object sender, EventArgs e)
         {
             //未選択なら処理終了
             if (_curList.SelectedIndices.Count == 0) return;
 
-            var tab = this._statuses.Tabs[this._curTab.Text];
+            var tab = this.CurrentTab;
             var screenNameArray = this._curList.SelectedIndices.Cast<int>()
                 .Select(x => tab[x])
                 .Select(x => x.RetweetedId != null ? x.RetweetedBy : x.ScreenName)
@@ -8480,7 +8225,7 @@ namespace OpenTween
             if (this._curList.SelectedIndices.Count == 0)
                 return;
 
-            var tab = this._statuses.Tabs[this._curTab.Text];
+            var tab = this.CurrentTab;
             var sourceArray = this._curList.SelectedIndices.Cast<int>()
                 .Select(x => tab[x].Source).ToArray();
 
@@ -8574,8 +8319,7 @@ namespace OpenTween
                 {
                     if (dialog.ShowDialog(this) == DialogResult.Cancel) return false;
 
-                    var selectedTab = dialog.SelectedTab;
-                    tabName = selectedTab == null ? null : selectedTab.TabName;
+                    tabName = dialog.SelectedTab?.TabName;
                 }
 
                 ListTab.SelectedTab.Focus();
@@ -8638,15 +8382,12 @@ namespace OpenTween
                 mark = false;
             }
         }
+
         private void CopySTOTMenuItem_Click(object sender, EventArgs e)
-        {
-            this.CopyStot();
-        }
+            => this.CopyStot();
 
         private void CopyURLMenuItem_Click(object sender, EventArgs e)
-        {
-            this.CopyIdUri();
-        }
+            => this.CopyIdUri();
 
         private void SelectAllMenuItem_Click(object sender, EventArgs e)
         {
@@ -8792,7 +8533,7 @@ namespace OpenTween
             }
 
             _statuses.ClearTabIds(tabName);
-            if (ListTab.SelectedTab.Text == tabName)
+            if (this.CurrentTabName == tabName)
             {
                 _anchorPost = null;
                 _anchorFlag = false;
@@ -8836,7 +8577,7 @@ namespace OpenTween
             }
 
             if (SettingManager.Common.DispUsername) ttl.Append(tw.Username).Append(" - ");
-            ttl.Append(Application.ProductName);
+            ttl.Append(ApplicationSettings.ApplicationName);
             ttl.Append("  ");
             switch (SettingManager.Common.DispLatestPost)
             {
@@ -8895,7 +8636,7 @@ namespace OpenTween
                 {
                     ur += tab.UnreadCount;
                     al += tab.AllCount;
-                    if (_curTab != null && tab.TabName.Equals(_curTab.Text))
+                    if (tab.TabName == this.CurrentTabName)
                     {
                         tur = tab.UnreadCount;
                         tal = tab.AllCount;
@@ -8950,119 +8691,108 @@ namespace OpenTween
 
         private void SetApiStatusLabel(string endpointName = null)
         {
-            if (_curTab == null)
-            {
-                this.toolStripApiGauge.ApiEndpoint = null;
-            }
-            else
-            {
-                var tabType = _statuses.Tabs[_curTab.Text].TabType;
+            var tabType = this.CurrentTab.TabType;
 
-                if (endpointName == null)
+            if (endpointName == null)
+            {
+                // 表示中のタブに応じて更新
+                switch (tabType)
                 {
-                    // 表示中のタブに応じて更新
-                    switch (tabType)
-                    {
-                        case MyCommon.TabUsageType.Home:
-                        case MyCommon.TabUsageType.UserDefined:
-                            endpointName = "/statuses/home_timeline";
-                            break;
-
-                        case MyCommon.TabUsageType.Mentions:
-                            endpointName = "/statuses/mentions_timeline";
-                            break;
+                    case MyCommon.TabUsageType.Home:
+                    case MyCommon.TabUsageType.UserDefined:
+                        endpointName = "/statuses/home_timeline";
+                        break;
 
-                        case MyCommon.TabUsageType.Favorites:
-                            endpointName = "/favorites/list";
-                            break;
+                    case MyCommon.TabUsageType.Mentions:
+                        endpointName = "/statuses/mentions_timeline";
+                        break;
 
-                        case MyCommon.TabUsageType.DirectMessage:
-                            endpointName = "/direct_messages";
-                            break;
+                    case MyCommon.TabUsageType.Favorites:
+                        endpointName = "/favorites/list";
+                        break;
 
-                        case MyCommon.TabUsageType.UserTimeline:
-                            endpointName = "/statuses/user_timeline";
-                            break;
+                    case MyCommon.TabUsageType.DirectMessage:
+                        endpointName = "/direct_messages/events/list";
+                        break;
 
-                        case MyCommon.TabUsageType.Lists:
-                            endpointName = "/lists/statuses";
-                            break;
+                    case MyCommon.TabUsageType.UserTimeline:
+                        endpointName = "/statuses/user_timeline";
+                        break;
 
-                        case MyCommon.TabUsageType.PublicSearch:
-                            endpointName = "/search/tweets";
-                            break;
+                    case MyCommon.TabUsageType.Lists:
+                        endpointName = "/lists/statuses";
+                        break;
 
-                        case MyCommon.TabUsageType.Related:
-                            endpointName = "/statuses/show/:id";
-                            break;
+                    case MyCommon.TabUsageType.PublicSearch:
+                        endpointName = "/search/tweets";
+                        break;
 
-                        default:
-                            break;
-                    }
+                    case MyCommon.TabUsageType.Related:
+                        endpointName = "/statuses/show/:id";
+                        break;
 
-                    this.toolStripApiGauge.ApiEndpoint = endpointName;
+                    default:
+                        break;
                 }
-                else
-                {
-                    // 表示中のタブに関連する endpoint であれば更新
-                    var update = false;
 
-                    switch (endpointName)
-                    {
-                        case "/statuses/home_timeline":
-                            update = tabType == MyCommon.TabUsageType.Home ||
-                                     tabType == MyCommon.TabUsageType.UserDefined;
-                            break;
+                this.toolStripApiGauge.ApiEndpoint = endpointName;
+            }
+            else
+            {
+                // 表示中のタブに関連する endpoint であれば更新
+                var update = false;
 
-                        case "/statuses/mentions_timeline":
-                            update = tabType == MyCommon.TabUsageType.Mentions;
-                            break;
+                switch (endpointName)
+                {
+                    case "/statuses/home_timeline":
+                        update = tabType == MyCommon.TabUsageType.Home ||
+                                 tabType == MyCommon.TabUsageType.UserDefined;
+                        break;
 
-                        case "/favorites/list":
-                            update = tabType == MyCommon.TabUsageType.Favorites;
-                            break;
+                    case "/statuses/mentions_timeline":
+                        update = tabType == MyCommon.TabUsageType.Mentions;
+                        break;
 
-                        case "/direct_messages:":
-                            update = tabType == MyCommon.TabUsageType.DirectMessage;
-                            break;
+                    case "/favorites/list":
+                        update = tabType == MyCommon.TabUsageType.Favorites;
+                        break;
 
-                        case "/statuses/user_timeline":
-                            update = tabType == MyCommon.TabUsageType.UserTimeline;
-                            break;
+                    case "/direct_messages/events/list":
+                        update = tabType == MyCommon.TabUsageType.DirectMessage;
+                        break;
 
-                        case "/lists/statuses":
-                            update = tabType == MyCommon.TabUsageType.Lists;
-                            break;
+                    case "/statuses/user_timeline":
+                        update = tabType == MyCommon.TabUsageType.UserTimeline;
+                        break;
 
-                        case "/search/tweets":
-                            update = tabType == MyCommon.TabUsageType.PublicSearch;
-                            break;
+                    case "/lists/statuses":
+                        update = tabType == MyCommon.TabUsageType.Lists;
+                        break;
 
-                        case "/statuses/show/:id":
-                            update = tabType == MyCommon.TabUsageType.Related;
-                            break;
+                    case "/search/tweets":
+                        update = tabType == MyCommon.TabUsageType.PublicSearch;
+                        break;
 
-                        default:
-                            break;
-                    }
+                    case "/statuses/show/:id":
+                        update = tabType == MyCommon.TabUsageType.Related;
+                        break;
 
-                    if (update)
-                    {
-                        this.toolStripApiGauge.ApiEndpoint = endpointName;
-                    }
+                    default:
+                        break;
+                }
+
+                if (update)
+                {
+                    this.toolStripApiGauge.ApiEndpoint = endpointName;
                 }
             }
         }
 
         private void SetStatusLabelUrl()
-        {
-            StatusLabelUrl.Text = GetStatusLabelText();
-        }
+            => this.StatusLabelUrl.Text = this.GetStatusLabelText();
 
         public void SetStatusLabel(string text)
-        {
-            StatusLabel.Text = text;
-        }
+            => this.StatusLabel.Text = text;
 
         private void SetNotifyIconText()
         {
@@ -9076,7 +8806,7 @@ namespace OpenTween
                 ur.Append(tw.Username);
                 ur.Append(" - ");
             }
-            ur.Append(Application.ProductName);
+            ur.Append(ApplicationSettings.ApplicationName);
 #if DEBUG
             ur.Append("(Debug Build)");
 #endif
@@ -9136,7 +8866,7 @@ namespace OpenTween
 
             if (m != null)
             {
-                var inReplyToScreenName = this.inReplyTo.Item2;
+                var inReplyToScreenName = this.inReplyTo.Value.ScreenName;
                 if (StatusText.StartsWith("@", StringComparison.Ordinal))
                 {
                     if (StatusText.StartsWith("@" + inReplyToScreenName, StringComparison.Ordinal)) return;
@@ -9280,9 +9010,7 @@ namespace OpenTween
         }
 
         private async void RepliedStatusOpenMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.doRepliedStatusOpen();
-        }
+            => await this.doRepliedStatusOpen();
 
         private void SplitContainer2_Panel2_Resize(object sender, EventArgs e)
         {
@@ -9336,7 +9064,7 @@ namespace OpenTween
                 if (string.IsNullOrEmpty(SettingManager.Common.BitlyAccessToken) &&
                     (string.IsNullOrEmpty(SettingManager.Common.BilyUser) || string.IsNullOrEmpty(SettingManager.Common.BitlyPwd)))
                 {
-                    MessageBox.Show(this, Properties.Resources.UrlConvert_BitlyAuthRequired, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
+                    MessageBox.Show(this, Properties.Resources.UrlConvert_BitlyAuthRequired, ApplicationSettings.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                     return false;
                 }
             }
@@ -9519,24 +9247,13 @@ namespace OpenTween
         }
 
         private async void TinyURLToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await UrlConvertAsync(MyCommon.UrlConverter.TinyUrl);
-        }
+            => await this.UrlConvertAsync(MyCommon.UrlConverter.TinyUrl);
 
         private async void IsgdToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await UrlConvertAsync(MyCommon.UrlConverter.Isgd);
-        }
-
-        private async void TwurlnlToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await UrlConvertAsync(MyCommon.UrlConverter.Twurl);
-        }
+            => await this.UrlConvertAsync(MyCommon.UrlConverter.Isgd);
 
         private async void UxnuMenuItem_Click(object sender, EventArgs e)
-        {
-            await UrlConvertAsync(MyCommon.UrlConverter.Uxnu);
-        }
+            => await this.UrlConvertAsync(MyCommon.UrlConverter.Uxnu);
 
         private async void UrlConvertAutoToolStripMenuItem_Click(object sender, EventArgs e)
         {
@@ -9555,9 +9272,7 @@ namespace OpenTween
         }
 
         private void UrlUndoToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            doUrlUndo();
-        }
+            => this.doUrlUndo();
 
         private void NewPostPopMenuItem_CheckStateChanged(object sender, EventArgs e)
         {
@@ -9915,7 +9630,7 @@ namespace OpenTween
                     var screenName = userUriMatch.Groups["ScreenName"].Value;
                     if (this.IsTwitterId(screenName))
                     {
-                        this.AddNewTabForUserTimeline(screenName);
+                        await this.AddNewTabForUserTimeline(screenName);
                         return;
                     }
                 }
@@ -9986,7 +9701,7 @@ namespace OpenTween
 
             this.PurgeListViewItemCache();
 
-            _curTab = _tab;
+            this._statuses.SelectTab(_tab.Text);
             _curList = (DetailsListView)_tab.Tag;
 
             if (_curList.SelectedIndices.Count > 0)
@@ -10017,9 +9732,7 @@ namespace OpenTween
         }
 
         private void ListTab_Selecting(object sender, TabControlCancelEventArgs e)
-        {
-            ListTabSelect(e.TabPage);
-        }
+            => this.ListTabSelect(e.TabPage);
 
         private void SelectListItem(DetailsListView LView, int Index)
         {
@@ -10110,19 +9823,19 @@ namespace OpenTween
                     this.RefreshBlockIdsAsync(),
                     this.RefreshNoRetweetIdsAsync(),
                     this.RefreshTwitterConfigurationAsync(),
-                    this.GetHomeTimelineAsync(),
-                    this.GetReplyAsync(),
-                    this.GetDirectMessagesAsync(),
-                    this.GetPublicSearchAllAsync(),
-                    this.GetUserTimelineAllAsync(),
-                    this.GetListTimelineAllAsync(),
+                    this.RefreshTabAsync<HomeTabModel>(),
+                    this.RefreshTabAsync<MentionsTabModel>(),
+                    this.RefreshTabAsync<DirectMessagesTabModel>(),
+                    this.RefreshTabAsync<PublicSearchTabModel>(),
+                    this.RefreshTabAsync<UserTimelineTabModel>(),
+                    this.RefreshTabAsync<ListTimelineTabModel>(),
                 };
 
                 if (SettingManager.Common.StartupFollowers)
                     loadTasks.Add(this.RefreshFollowerIdsAsync());
 
                 if (SettingManager.Common.GetFav)
-                    loadTasks.Add(this.GetFavoritesAsync());
+                    loadTasks.Add(this.RefreshTabAsync<FavoritesTabModel>());
 
                 var allTasks = Task.WhenAll(loadTasks);
 
@@ -10190,14 +9903,10 @@ namespace OpenTween
         }
 
         private async void GetFollowersAllToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.doGetFollowersMenu();
-        }
+            => await this.doGetFollowersMenu();
 
         private void ReTweetUnofficialStripMenuItem_Click(object sender, EventArgs e)
-        {
-            doReTweetUnofficial();
-        }
+            => this.doReTweetUnofficial();
 
         private async Task doReTweetOfficial(bool isConfirm)
         {
@@ -10257,9 +9966,7 @@ namespace OpenTween
         }
 
         private async void ReTweetStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.doReTweetOfficial(true);
-        }
+            => await this.doReTweetOfficial(true);
 
         private async Task FavoritesRetweetOfficial()
         {
@@ -10311,6 +10018,8 @@ namespace OpenTween
             statusHtml = Regex.Replace(statusHtml, "<a class=\"mention\" href=\"(?<href>.+?)\">(?<text>.+?)</a>", "${text}");
             // ハッシュタグ
             statusHtml = Regex.Replace(statusHtml, "<a class=\"hashtag\" href=\"(?<href>.+?)\">(?<text>.+?)</a>", "${text}");
+            // 絵文字
+            statusHtml = Regex.Replace(statusHtml, "<img class=\"emoji\" src=\".+?\" alt=\"(?<text>.+?)\" />", "${text}");
 
             // <br> 除去
             if (multiline)
@@ -10342,19 +10051,13 @@ namespace OpenTween
         }
 
         private void UrlMultibyteSplitMenuItem_CheckedChanged(object sender, EventArgs e)
-        {
-            this.urlMultibyteSplit = ((ToolStripMenuItem)sender).Checked;
-        }
+            => this.urlMultibyteSplit = ((ToolStripMenuItem)sender).Checked;
 
         private void PreventSmsCommandMenuItem_CheckedChanged(object sender, EventArgs e)
-        {
-            this.preventSmsCommand = ((ToolStripMenuItem)sender).Checked;
-        }
+            => this.preventSmsCommand = ((ToolStripMenuItem)sender).Checked;
 
         private void UrlAutoShortenMenuItem_CheckedChanged(object sender, EventArgs e)
-        {
-            SettingManager.Common.UrlConvertAuto = ((ToolStripMenuItem)sender).Checked;
-        }
+            => SettingManager.Common.UrlConvertAuto = ((ToolStripMenuItem)sender).Checked;
 
         private void IdeographicSpaceToSpaceMenuItem_Click(object sender, EventArgs e)
         {
@@ -10397,10 +10100,7 @@ namespace OpenTween
         }
 
         private void TweenMain_Deactivate(object sender, EventArgs e)
-        {
-            //画面が非アクティブになったら、発言欄の背景色をデフォルトへ
-            this.StatusText_Leave(StatusText, System.EventArgs.Empty);
-        }
+            => this.StatusText_Leave(StatusText, EventArgs.Empty); // 画面が非アクティブになったら、発言欄の背景色をデフォルトへ
 
         private void TabRenameMenuItem_Click(object sender, EventArgs e)
         {
@@ -10410,14 +10110,10 @@ namespace OpenTween
         }
 
         private async void BitlyToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await UrlConvertAsync(MyCommon.UrlConverter.Bitly);
-        }
+            => await this.UrlConvertAsync(MyCommon.UrlConverter.Bitly);
 
         private async void JmpToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await UrlConvertAsync(MyCommon.UrlConverter.Jmp);
-        }
+            => await this.UrlConvertAsync(MyCommon.UrlConverter.Jmp);
 
         private async void ApiUsageInfoMenuItem_Click(object sender, EventArgs e)
         {
@@ -10676,18 +10372,7 @@ namespace OpenTween
         }
 
         private async void OwnStatusMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.doShowUserStatus(tw.Username, false);
-            //if (!string.IsNullOrEmpty(tw.UserInfoXml))
-            //{
-            //    doShowUserStatus(tw.Username, false);
-            //}
-            //else
-            //{
-            //    MessageBox.Show(Properties.Resources.ShowYourProfileText1, "Your status", MessageBoxButtons.OK, MessageBoxIcon.Information);
-            //    return;
-            //}
-        }
+            => await this.doShowUserStatus(tw.Username, false);
 
         // TwitterIDでない固定文字列を調べる(文字列検証のみ 実際に取得はしない)
         // URLから切り出した文字列を渡す
@@ -10697,7 +10382,7 @@ namespace OpenTween
             if (this.tw.Configuration.NonUsernamePaths == null || this.tw.Configuration.NonUsernamePaths.Length == 0)
                 return !Regex.Match(name, @"^(about|jobs|tos|privacy|who_to_follow|download|messages)$", RegexOptions.IgnoreCase).Success;
             else
-                return !this.tw.Configuration.NonUsernamePaths.Contains(name.ToLowerInvariant());
+                return !this.tw.Configuration.NonUsernamePaths.Contains(name, StringComparer.InvariantCultureIgnoreCase);
         }
 
         private void doQuoteOfficial()
@@ -10745,7 +10430,7 @@ namespace OpenTween
                 // 投稿時に in_reply_to_status_id を付加する
                 var inReplyToStatusId = this._curPost.RetweetedId ?? this._curPost.StatusId;
                 var inReplyToScreenName = this._curPost.ScreenName;
-                this.inReplyTo = Tuple.Create(inReplyToStatusId, inReplyToScreenName);
+                this.inReplyTo = (inReplyToStatusId, inReplyToScreenName);
 
                 StatusText.Text += " RT @" + _curPost.ScreenName + ": " + rtdata;
 
@@ -10754,12 +10439,10 @@ namespace OpenTween
             }
         }
 
-        private void QuoteStripMenuItem_Click(object sender, EventArgs e) // Handles QuoteStripMenuItem.Click, QtOpMenuItem.Click
-        {
-            doQuoteOfficial();
-        }
+        private void QuoteStripMenuItem_Click(object sender, EventArgs e)
+            => this.doQuoteOfficial();
 
-        private void SearchButton_Click(object sender, EventArgs e)
+        private async void SearchButton_Click(object sender, EventArgs e)
         {
             //公式検索
             Control pnl = ((Control)sender).Parent;
@@ -10822,15 +10505,12 @@ namespace OpenTween
                 SaveConfigsTabs();   //検索条件の保存
             }
 
-            this.GetPublicSearchAsync(tb);
             listView.Focus();
+            await this.RefreshTabAsync(tb);
         }
 
         private async void RefreshMoreStripMenuItem_Click(object sender, EventArgs e)
-        {
-            //もっと前を取得
-            await this.DoRefreshMore();
-        }
+            => await this.DoRefreshMore(); // もっと前を取得
 
         /// <summary>
         /// 指定されたタブのListTabにおける位置を返します
@@ -10946,9 +10626,7 @@ namespace OpenTween
         }
 
         private async void MoveToRTHomeMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.doMoveToRTHome();
-        }
+            => await this.doMoveToRTHome();
 
         private void ListManageUserContextToolStripMenuItem_Click(object sender, EventArgs e)
         {
@@ -10985,17 +10663,13 @@ namespace OpenTween
 
         private void PublicSearchQueryMenuItem_Click(object sender, EventArgs e)
         {
-            if (ListTab.SelectedTab != null)
-            {
-                if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType != MyCommon.TabUsageType.PublicSearch) return;
-                ListTab.SelectedTab.Controls["panelSearch"].Controls["comboSearch"].Focus();
-            }
+            var tab = this.CurrentTab;
+            if (tab.TabType != MyCommon.TabUsageType.PublicSearch) return;
+            this.CurrentTabPage.Controls["panelSearch"].Controls["comboSearch"].Focus();
         }
 
         private void StatusLabel_DoubleClick(object sender, EventArgs e)
-        {
-            MessageBox.Show(StatusLabel.TextHistory, "Logs", MessageBoxButtons.OK, MessageBoxIcon.None);
-        }
+            => MessageBox.Show(StatusLabel.TextHistory, "Logs", MessageBoxButtons.OK, MessageBoxIcon.None);
 
         private void HashManageMenuItem_Click(object sender, EventArgs e)
         {
@@ -11060,9 +10734,7 @@ namespace OpenTween
         }
 
         private void HashStripSplitButton_ButtonClick(object sender, EventArgs e)
-        {
-            HashToggleMenuItem_Click(null, null);
-        }
+            => this.HashToggleMenuItem_Click(null, null);
 
         public void SetPermanentHashtag(string hashtag)
         {
@@ -11076,8 +10748,6 @@ namespace OpenTween
 
         private void MenuItemOperate_DropDownOpening(object sender, EventArgs e)
         {
-            if (ListTab.SelectedTab == null) return;
-            if (_statuses == null || _statuses.Tabs == null || !_statuses.Tabs.ContainsKey(ListTab.SelectedTab.Text)) return;
             if (!this.ExistCurrentPost)
             {
                 this.ReplyOpMenuItem.Enabled = false;
@@ -11109,12 +10779,12 @@ namespace OpenTween
                 this.UnreadOpMenuItem.Enabled = true;
             }
 
-            if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.DirectMessage || !this.ExistCurrentPost || _curPost.IsDm)
+            var tab = this.CurrentTab;
+            if (tab.TabType == MyCommon.TabUsageType.DirectMessage || !this.ExistCurrentPost || _curPost.IsDm)
             {
                 this.FavOpMenuItem.Enabled = false;
                 this.UnFavOpMenuItem.Enabled = false;
                 this.OpenStatusOpMenuItem.Enabled = false;
-                this.OpenFavotterOpMenuItem.Enabled = false;
                 this.ShowRelatedStatusesMenuItem2.Enabled = false;
                 this.RtOpMenuItem.Enabled = false;
                 this.RtUnOpMenuItem.Enabled = false;
@@ -11127,7 +10797,6 @@ namespace OpenTween
                 this.FavOpMenuItem.Enabled = true;
                 this.UnFavOpMenuItem.Enabled = true;
                 this.OpenStatusOpMenuItem.Enabled = true;
-                this.OpenFavotterOpMenuItem.Enabled = true;
                 this.ShowRelatedStatusesMenuItem2.Enabled = true;  //PublicSearchの時問題出るかも
 
                 if (!_curPost.CanRetweetBy(this.twitterApi.CurrentUserId))
@@ -11148,7 +10817,7 @@ namespace OpenTween
                 }
             }
 
-            if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType != MyCommon.TabUsageType.Favorites)
+            if (tab.TabType != MyCommon.TabUsageType.Favorites)
             {
                 this.RefreshPrevOpMenuItem.Enabled = true;
             }
@@ -11181,14 +10850,10 @@ namespace OpenTween
         }
 
         private void MenuItemTab_DropDownOpening(object sender, EventArgs e)
-        {
-            ContextMenuTabProperty_Opening(sender, null);
-        }
+            => this.ContextMenuTabProperty_Opening(sender, null);
 
         public Twitter TwitterInstance
-        {
-            get { return tw; }
-        }
+            => this.tw;
 
         private void SplitContainer3_SplitterMoved(object sender, SplitterEventArgs e)
         {
@@ -11225,17 +10890,12 @@ namespace OpenTween
             {
                 UndoRemoveTabMenuItem.Enabled = true;
             }
-            if (ListTab.SelectedTab != null)
-            {
-                if (_statuses.Tabs[ListTab.SelectedTab.Text].TabType == MyCommon.TabUsageType.PublicSearch)
-                    PublicSearchQueryMenuItem.Enabled = true;
-                else
-                    PublicSearchQueryMenuItem.Enabled = false;
-            }
+
+            if (this.CurrentTab.TabType == MyCommon.TabUsageType.PublicSearch)
+                PublicSearchQueryMenuItem.Enabled = true;
             else
-            {
                 PublicSearchQueryMenuItem.Enabled = false;
-            }
+
             if (!this.ExistCurrentPost)
             {
                 this.CopySTOTMenuItem.Enabled = false;
@@ -11253,16 +10913,10 @@ namespace OpenTween
         }
 
         private void NotifyIcon1_MouseMove(object sender, MouseEventArgs e)
-        {
-            SetNotifyIconText();
-        }
+            => this.SetNotifyIconText();
 
         private async void UserStatusToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            var id = _curPost?.ScreenName ?? "";
-
-            await this.ShowUserStatus(id);
-        }
+            => await this.ShowUserStatus(this._curPost?.ScreenName ?? "");
 
         private async Task doShowUserStatus(string id, bool ShowInputDialog)
         {
@@ -11324,14 +10978,10 @@ namespace OpenTween
         }
 
         internal Task ShowUserStatus(string id, bool ShowInputDialog)
-        {
-            return this.doShowUserStatus(id, ShowInputDialog);
-        }
+            => this.doShowUserStatus(id, ShowInputDialog);
 
         internal Task ShowUserStatus(string id)
-        {
-            return this.doShowUserStatus(id, true);
-        }
+            => this.doShowUserStatus(id, true);
 
         private async void ShowProfileMenuItem_Click(object sender, EventArgs e)
         {
@@ -11425,14 +11075,10 @@ namespace OpenTween
         }
 
         private void SplitContainer2_MouseDoubleClick(object sender, MouseEventArgs e)
-        {
-            this.MultiLinePullDownMenuItem.PerformClick();
-        }
+            => this.MultiLinePullDownMenuItem.PerformClick();
 
         public PostClass CurPost
-        {
-            get { return _curPost; }
-        }
+            => this._curPost;
 
 #region "画像投稿"
         private void ImageSelectMenuItem_Click(object sender, EventArgs e)
@@ -11475,14 +11121,10 @@ namespace OpenTween
         }
 
         private void ImageSelector_FilePickDialogOpening(object sender, EventArgs e)
-        {
-            this.AllowDrop = false;
-        }
+            => this.AllowDrop = false;
 
         private void ImageSelector_FilePickDialogClosed(object sender, EventArgs e)
-        {
-            this.AllowDrop = true;
-        }
+            => this.AllowDrop = true;
 
         private void ImageSelector_SelectedServiceChanged(object sender, EventArgs e)
         {
@@ -11496,9 +11138,7 @@ namespace OpenTween
         }
 
         private void ImageSelector_VisibleChanged(object sender, EventArgs e)
-        {
-            this.StatusText_TextChanged(null, null);
-        }
+            => this.StatusText_TextChanged(null, null);
 
         /// <summary>
         /// StatusTextでCtrl+Vが押下された時の処理
@@ -11563,9 +11203,7 @@ namespace OpenTween
         }
 
         private void CopyUserIdStripMenuItem_Click(object sender, EventArgs e)
-        {
-            CopyUserId();
-        }
+            => this.CopyUserId();
 
         private void CopyUserId()
         {
@@ -11591,7 +11229,7 @@ namespace OpenTween
                 }
                 catch (TabException ex)
                 {
-                    MessageBox.Show(this, ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
+                    MessageBox.Show(this, ex.Message, ApplicationSettings.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                 }
             }
         }
@@ -11635,9 +11273,11 @@ namespace OpenTween
 
             var tabName = this._statuses.MakeTabName("Related Tweets");
 
-            tabRelated = new RelatedPostsTabModel(tabName, post);
-            tabRelated.UnreadManage = false;
-            tabRelated.Notify = false;
+            tabRelated = new RelatedPostsTabModel(tabName, post)
+            {
+                UnreadManage = false,
+                Notify = false,
+            };
 
             this._statuses.AddTab(tabRelated);
             this.AddNewTab(tabRelated, startup: false);
@@ -11653,7 +11293,7 @@ namespace OpenTween
                 }
             }
 
-            await this.GetRelatedTweetsAsync(tabRelated);
+            await this.RefreshTabAsync(tabRelated);
 
             tabPage = this.ListTab.TabPages.Cast<TabPage>()
                 .FirstOrDefault(x => x.Text == tabRelated.TabName);
@@ -11685,9 +11325,7 @@ namespace OpenTween
         }
 
         private void tw_UserIdChanged()
-        {
-            this.ModifySettingCommon = true;
-        }
+            => this.ModifySettingCommon = true;
 
 #region "Userstream"
         private async void tw_PostDeleted(object sender, PostDeletedEventArgs e)
@@ -11699,10 +11337,10 @@ namespace OpenTween
                     await this.InvokeAsync(async () =>
                     {
                         this._statuses.RemovePostFromAllTabs(e.StatusId, setIsDeleted: true);
-                        if (_curTab != null && _statuses.Tabs[_curTab.Text].Contains(e.StatusId))
+                        if (this.CurrentTab.Contains(e.StatusId))
                         {
                             this.PurgeListViewItemCache();
-                            ((DetailsListView)_curTab.Tag).Update();
+                            this._curList.Update();
                             if (_curPost != null && _curPost.StatusId == e.StatusId)
                                 await this.DispSelectedPost(true);
                         }
@@ -11720,9 +11358,7 @@ namespace OpenTween
             }
         }
 
-        private int userStreamsRefreshing = 0;
-
-        private async void tw_NewPostFromStream(object sender, EventArgs e)
+        private void tw_NewPostFromStream(object sender, EventArgs e)
         {
             if (SettingManager.Common.ReadOldPosts)
             {
@@ -11731,21 +11367,7 @@ namespace OpenTween
 
             this._statuses.DistributePosts();
 
-            if (SettingManager.Common.UserstreamPeriod > 0) return;
-
-            // userStreamsRefreshing が 0 (インクリメント後は1) であれば RefreshTimeline を実行
-            if (Interlocked.Increment(ref this.userStreamsRefreshing) == 1)
-            {
-                try
-                {
-                    await this.InvokeAsync(() => this.RefreshTimeline())
-                        .ConfigureAwait(false);
-                }
-                finally
-                {
-                    Interlocked.Exchange(ref this.userStreamsRefreshing, 0);
-                }
-            }
+            this.RefreshThrottlingTimer.Invoke();
         }
 
         private async void tw_UserStreamStarted(object sender, EventArgs e)
@@ -11839,12 +11461,12 @@ namespace OpenTween
             NotifyEvent(ev);
             if (ev.Event == "favorite" || ev.Event == "unfavorite")
             {
-                if (_curTab != null && _statuses.Tabs[_curTab.Text].Contains(ev.Id))
+                if (this.CurrentTab.Contains(ev.Id))
                 {
                     this.PurgeListViewItemCache();
-                    ((DetailsListView)_curTab.Tag).Update();
+                    this._curList.Update();
                 }
-                if (ev.Event == "unfavorite" && ev.Username.ToLowerInvariant().Equals(tw.Username.ToLowerInvariant()))
+                if (ev.Event == "unfavorite" && ev.Username.Equals(tw.Username, StringComparison.InvariantCultureIgnoreCase))
                 {
                     var favTab = this._statuses.GetTabByType(MyCommon.TabUsageType.Favorites);
                     favTab.EnqueueRemovePost(ev.Id, setIsDeleted: false);
@@ -11870,7 +11492,7 @@ namespace OpenTween
                 {
                     //title.Clear();
                 }
-                title.Append(Application.ProductName);
+                title.Append(ApplicationSettings.ApplicationName);
                 title.Append(" [");
                 title.Append(ev.Event.ToUpper(CultureInfo.CurrentCulture));
                 title.Append("] by ");
@@ -11996,14 +11618,17 @@ namespace OpenTween
         {
             if (evtDialog == null || evtDialog.IsDisposed)
             {
-                evtDialog = null;
-                evtDialog = new EventViewerDialog();
-                evtDialog.Owner = this;
+                this.evtDialog = new EventViewerDialog
+                {
+                    Owner = this,
+                };
+
                 //親の中央に表示
-                Point pos = evtDialog.Location;
-                pos.X = Convert.ToInt32(this.Location.X + this.Size.Width / 2 - evtDialog.Size.Width / 2);
-                pos.Y = Convert.ToInt32(this.Location.Y + this.Size.Height / 2 - evtDialog.Size.Height / 2);
-                evtDialog.Location = pos;
+                this.evtDialog.Location = new Point
+                {
+                    X = Convert.ToInt32(this.Location.X + this.Size.Width / 2 - evtDialog.Size.Width / 2),
+                    Y = Convert.ToInt32(this.Location.Y + this.Size.Height / 2 - evtDialog.Size.Height / 2),
+                };
             }
             evtDialog.EventSource = tw.StoredEvent;
             if (!evtDialog.Visible)
@@ -12028,20 +11653,12 @@ namespace OpenTween
             }
             catch (Exception)
             {
-                MessageBox.Show("Failed to restart. Please run " + Application.ProductName + " manually.");
+                MessageBox.Show("Failed to restart. Please run " + ApplicationSettings.ApplicationName + " manually.");
             }
         }
 
-        private async void OpenOwnFavedMenuItem_Click(object sender, EventArgs e)
-        {
-            if (!string.IsNullOrEmpty(tw.Username))
-                await this.OpenUriInBrowserAsync(Properties.Resources.FavstarUrl + "users/" + tw.Username + "/recent");
-        }
-
         private async void OpenOwnHomeMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl + tw.Username);
-        }
+            => await this.OpenUriInBrowserAsync(MyCommon.TwitterUrl + tw.Username);
 
         private bool ExistCurrentPost
         {
@@ -12053,10 +11670,8 @@ namespace OpenTween
             }
         }
 
-        private void ShowUserTimelineToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            ShowUserTimeline();
-        }
+        private async void ShowUserTimelineToolStripMenuItem_Click(object sender, EventArgs e)
+            => await this.ShowUserTimeline();
 
         private string GetUserIdFromCurPostOrInput(string caption)
         {
@@ -12080,21 +11695,12 @@ namespace OpenTween
             return id;
         }
 
-        private void UserTimelineToolStripMenuItem_Click(object sender, EventArgs e)
+        private async void UserTimelineToolStripMenuItem_Click(object sender, EventArgs e)
         {
             string id = GetUserIdFromCurPostOrInput("Show UserTimeline");
             if (!string.IsNullOrEmpty(id))
             {
-                AddNewTabForUserTimeline(id);
-            }
-        }
-
-        private async void UserFavorareToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            string id = GetUserIdFromCurPostOrInput("Show Favstar");
-            if (!string.IsNullOrEmpty(id))
-            {
-                await this.OpenUriInBrowserAsync(Properties.Resources.FavstarUrl + "users/" + id + "/recent");
+                await this.AddNewTabForUserTimeline(id);
             }
         }
 
@@ -12135,9 +11741,7 @@ namespace OpenTween
         }
 
         private void StopRefreshAllMenuItem_CheckedChanged(object sender, EventArgs e)
-        {
-            TimelineRefreshEnableChange(!StopRefreshAllMenuItem.Checked);
-        }
+            => this.TimelineRefreshEnableChange(!StopRefreshAllMenuItem.Checked);
 
         private async Task OpenUserAppointUrl()
         {
@@ -12164,9 +11768,7 @@ namespace OpenTween
         }
 
         private async void OpenUserSpecifiedUrlMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.OpenUserAppointUrl();
-        }
+            => await this.OpenUserAppointUrl();
 
         private async void GrowlHelper_Callback(object sender, GrowlHelper.NotifyCallbackEventArgs e)
         {
@@ -12197,19 +11799,13 @@ namespace OpenTween
         }
 
         private void tweetThumbnail1_ThumbnailLoading(object sender, EventArgs e)
-        {
-            this.SplitContainer3.Panel2Collapsed = false;
-        }
+            => this.SplitContainer3.Panel2Collapsed = false;
 
         private async void tweetThumbnail1_ThumbnailDoubleClick(object sender, ThumbnailDoubleClickEventArgs e)
-        {
-            await this.OpenThumbnailPicture(e.Thumbnail);
-        }
+            => await this.OpenThumbnailPicture(e.Thumbnail);
 
         private async void tweetThumbnail1_ThumbnailImageSearchClick(object sender, ThumbnailImageSearchEventArgs e)
-        {
-            await this.OpenUriInBrowserAsync(e.ImageUrl);
-        }
+            => await this.OpenUriInBrowserAsync(e.ImageUrl);
 
         private async Task OpenThumbnailPicture(ThumbnailInfo thumbnail)
         {
@@ -12219,9 +11815,7 @@ namespace OpenTween
         }
 
         private async void TwitterApiStatusToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            await this.OpenUriInBrowserAsync(Twitter.ServiceAvailabilityStatusUrl);
-        }
+            => await this.OpenUriInBrowserAsync(Twitter.ServiceAvailabilityStatusUrl);
 
         private void PostButton_KeyDown(object sender, KeyEventArgs e)
         {
@@ -12245,29 +11839,19 @@ namespace OpenTween
         }
 
         private void IconSizeNoneToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            ChangeListViewIconSize(MyCommon.IconSizes.IconNone);
-        }
+            => this.ChangeListViewIconSize(MyCommon.IconSizes.IconNone);
 
         private void IconSize16ToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            ChangeListViewIconSize(MyCommon.IconSizes.Icon16);
-        }
+            => this.ChangeListViewIconSize(MyCommon.IconSizes.Icon16);
 
         private void IconSize24ToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            ChangeListViewIconSize(MyCommon.IconSizes.Icon24);
-        }
+            => this.ChangeListViewIconSize(MyCommon.IconSizes.Icon24);
 
         private void IconSize48ToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            ChangeListViewIconSize(MyCommon.IconSizes.Icon48);
-        }
+            => this.ChangeListViewIconSize(MyCommon.IconSizes.Icon48);
 
         private void IconSize48_2ToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            ChangeListViewIconSize(MyCommon.IconSizes.Icon48_2);
-        }
+            => this.ChangeListViewIconSize(MyCommon.IconSizes.Icon48_2);
 
         private void ChangeListViewIconSize(MyCommon.IconSizes iconSize)
         {