OSDN Git Service

メイン以外のアカウントのホームタイムラインを表示する機能を追加
authorKimura Youichi <kim.upsilon@bucyou.net>
Wed, 7 Feb 2024 01:12:53 +0000 (10:12 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Mon, 20 May 2024 17:06:03 +0000 (02:06 +0900)
CHANGELOG.txt
OpenTween.Tests/SocialProtocol/AccountCollectionTest.cs
OpenTween/ApplicationEvents.cs
OpenTween/Models/HomeSpecifiedAccountTabModel.cs [new file with mode: 0644]
OpenTween/SocialProtocol/AccountCollection.cs
OpenTween/Tween.cs

index 3707ae3..0657dd6 100644 (file)
@@ -1,6 +1,10 @@
 更新履歴
 
 ==== Unreleased
+ * NEW: メインアカウント以外のホームタイムライン表示に対応
+   - タブ単位で切り替わるマルチアカウント機能です
+   - 投稿欄やふぁぼ・RT等の機能も表示中のタブに連動して使用するアカウントが変わります
+   - 現時点ではメインアカウント以外のタブ設定は次回起動時に保持されません
  * NEW: Twemoji 15.1.0 に対応しました
    - Unicode 15.1 で追加された絵文字が表示されるようになります
  * CHG: 設定画面でのアカウント一覧の表示形式を変更
index 7ba90e6..ae35efc 100644 (file)
@@ -142,6 +142,25 @@ namespace OpenTween.SocialProtocol
         }
 
         [Fact]
+        public void SecondaryAccounts_Test()
+        {
+            using var accounts = new AccountCollection();
+            accounts.LoadFromSettings(new()
+            {
+                UserAccounts = new()
+                {
+                    this.CreateAccountSetting("00000000-0000-4000-8000-000000000000"),
+                    this.CreateAccountSetting("00000000-0000-4000-8000-111111111111"),
+                },
+                SelectedAccountKey = new("00000000-0000-4000-8000-000000000000"),
+            });
+
+            var secondaryAccounts = accounts.SecondaryAccounts;
+            Assert.Single(secondaryAccounts);
+            Assert.Equal(new("00000000-0000-4000-8000-111111111111"), secondaryAccounts[0].UniqueKey);
+        }
+
+        [Fact]
         public void GetAccountForTab_DefaultTest()
         {
             using var accounts = new AccountCollection();
index 18f7986..dd802ac 100644 (file)
@@ -31,6 +31,7 @@ using System;
 using System.Linq;
 using System.Windows.Forms;
 using OpenTween.Connection;
+using OpenTween.Models;
 using OpenTween.Setting;
 using OpenTween.SocialProtocol;
 using OpenTween.SocialProtocol.Twitter;
@@ -100,6 +101,7 @@ namespace OpenTween
             }
 
             SetupAccounts(container.AccountCollection, settings);
+            AddSecondaryAccountTabs(container.AccountCollection, container.TabInfo);
 
             Application.Run(container.MainForm);
 
@@ -176,5 +178,19 @@ namespace OpenTween
                 throw new WebApiException(ex.InnerException.Message, ex);
             }
         }
+
+        private static void AddSecondaryAccountTabs(AccountCollection accounts, TabInformations tabInfo)
+        {
+            foreach (var account in accounts.Items)
+            {
+                var accountKey = account.UniqueKey;
+                if (accountKey == accounts.Primary.UniqueKey)
+                    continue;
+
+                var tabName = tabInfo.MakeTabName($"@{account.UserName}");
+                var homeTab = new HomeSpecifiedAccountTabModel(tabName, accountKey);
+                tabInfo.AddTab(homeTab);
+            }
+        }
     }
 }
diff --git a/OpenTween/Models/HomeSpecifiedAccountTabModel.cs b/OpenTween/Models/HomeSpecifiedAccountTabModel.cs
new file mode 100644 (file)
index 0000000..cbe10f8
--- /dev/null
@@ -0,0 +1,74 @@
+// OpenTween - Client of Twitter
+// Copyright (c) 2024 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+#nullable enable
+
+using System;
+using System.Threading.Tasks;
+using OpenTween.SocialProtocol;
+
+namespace OpenTween.Models
+{
+    public class HomeSpecifiedAccountTabModel : InternalStorageTabModel
+    {
+        public override MyCommon.TabUsageType TabType
+            => MyCommon.TabUsageType.Undefined;
+
+        public override bool IsPermanentTabType
+            => false;
+
+        public override Guid? SourceAccountId { get; }
+
+        public HomeSpecifiedAccountTabModel(string tabName, Guid accountId)
+            : base(tabName)
+        {
+            this.SourceAccountId = accountId;
+        }
+
+        public override async Task RefreshAsync(ISocialAccount account, bool backward, IProgress<string> progress)
+        {
+            progress.Report("Home refreshing...");
+
+            var firstLoad = !this.IsFirstLoadCompleted;
+            var count = Twitter.GetApiResultCount(MyCommon.WORKERTYPE.Timeline, backward, firstLoad);
+            var cursor = backward ? this.CursorBottom : this.CursorTop;
+
+            var response = await account.Client.GetHomeTimeline(count, cursor, firstLoad)
+                .ConfigureAwait(false);
+
+            foreach (var post in response.Posts)
+                this.AddPostQueue(post);
+
+            TabInformations.GetInstance().DistributePosts();
+
+            if (response.CursorTop != null && !backward)
+                this.CursorTop = response.CursorTop;
+
+            if (response.CursorBottom != null)
+                this.CursorBottom = response.CursorBottom;
+
+            if (firstLoad)
+                this.IsFirstLoadCompleted = true;
+
+            progress.Report("Home refreshed");
+        }
+    }
+}
index cf71380..afebef2 100644 (file)
@@ -43,6 +43,9 @@ namespace OpenTween.SocialProtocol
         public ISocialAccount[] Items
             => this.accounts.Values.ToArray();
 
+        public ISocialAccount[] SecondaryAccounts
+            => this.accounts.Values.Where(x => x.UniqueKey != this.primaryId).ToArray();
+
         public void LoadFromSettings(SettingCommon settingCommon)
         {
             var oldAccounts = this.accounts;
index 2603383..a94b094 100644 (file)
@@ -509,7 +509,11 @@ namespace OpenTween
 
             // タイマー設定
 
-            this.timelineScheduler.UpdateFunc[TimelineSchedulerTaskType.Home] = () => this.InvokeAsync(() => this.RefreshTabAsync<HomeTabModel>());
+            this.timelineScheduler.UpdateFunc[TimelineSchedulerTaskType.Home] = () => this.InvokeAsync(() => Task.WhenAll(new[]
+            {
+                this.RefreshTabAsync<HomeTabModel>(),
+                this.RefreshTabAsync<HomeSpecifiedAccountTabModel>(),
+            }));
             this.timelineScheduler.UpdateFunc[TimelineSchedulerTaskType.Mention] = () => this.InvokeAsync(() => this.RefreshTabAsync<MentionsTabModel>());
             this.timelineScheduler.UpdateFunc[TimelineSchedulerTaskType.Dm] = () => this.InvokeAsync(() => this.RefreshTabAsync<DirectMessagesTabModel>());
             this.timelineScheduler.UpdateFunc[TimelineSchedulerTaskType.PublicSearch] = () => this.InvokeAsync(() => this.RefreshTabAsync<PublicSearchTabModel>());
@@ -2492,6 +2496,7 @@ namespace OpenTween
         {
             // 設定画面表示前のユーザー情報
             var previousAccountId = this.settings.Common.SelectedAccountKey;
+            var previousSecondaryAccounts = this.accounts.SecondaryAccounts;
             var oldIconCol = this.Use2ColumnsMode;
 
             if (this.ShowSettingDialog() == DialogResult.OK)
@@ -2685,6 +2690,28 @@ namespace OpenTween
 
             if (this.PrimaryAccount.UniqueKey != previousAccountId)
                 await this.DoGetFollowersMenu();
+
+            var currentSecondaryAccounts = this.accounts.SecondaryAccounts;
+            var newSecondaryAccounts = currentSecondaryAccounts
+                .Where(x => !previousSecondaryAccounts.Any(y => y.UniqueKey == x.UniqueKey));
+            this.AddSecondaryAccountTabs(newSecondaryAccounts);
+        }
+
+        private void AddSecondaryAccountTabs(IEnumerable<ISocialAccount> accounts)
+        {
+            foreach (var account in accounts)
+            {
+                var isPrimary = account.UniqueKey == this.accounts.Primary.UniqueKey;
+                var tabExists = this.statuses.GetTabsByType<HomeSpecifiedAccountTabModel>()
+                    .Any(x => x.SourceAccountId == account.UniqueKey);
+                if (tabExists)
+                    continue;
+
+                var tabName = this.statuses.MakeTabName($"@{account.UserName}");
+                var homeTab = new HomeSpecifiedAccountTabModel(tabName, account.UniqueKey);
+                this.statuses.AddTab(homeTab);
+                this.AddNewTab(homeTab, startup: false);
+            }
         }
 
         /// <summary>
@@ -7802,6 +7829,7 @@ namespace OpenTween
                     this.RefreshNoRetweetIdsAsync,
                     this.RefreshTwitterConfigurationAsync,
                     this.RefreshTabAsync<HomeTabModel>,
+                    this.RefreshTabAsync<HomeSpecifiedAccountTabModel>,
                     this.RefreshTabAsync<MentionsTabModel>,
                     this.RefreshTabAsync<DirectMessagesTabModel>,
                     this.RefreshTabAsync<PublicSearchTabModel>,