更新履歴
==== Unreleased
+ * NEW: メインアカウント以外のホームタイムライン表示に対応
+ - タブ単位で切り替わるマルチアカウント機能です
+ - 投稿欄やふぁぼ・RT等の機能も表示中のタブに連動して使用するアカウントが変わります
+ - 現時点ではメインアカウント以外のタブ設定は次回起動時に保持されません
* NEW: Twemoji 15.1.0 に対応しました
- Unicode 15.1 で追加された絵文字が表示されるようになります
* CHG: 設定画面でのアカウント一覧の表示形式を変更
}
[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();
using System.Linq;
using System.Windows.Forms;
using OpenTween.Connection;
+using OpenTween.Models;
using OpenTween.Setting;
using OpenTween.SocialProtocol;
using OpenTween.SocialProtocol.Twitter;
}
SetupAccounts(container.AccountCollection, settings);
+ AddSecondaryAccountTabs(container.AccountCollection, container.TabInfo);
Application.Run(container.MainForm);
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);
+ }
+ }
}
}
--- /dev/null
+// 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");
+ }
+ }
+}
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;
// タイマー設定
- 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>());
{
// 設定画面表示前のユーザー情報
var previousAccountId = this.settings.Common.SelectedAccountKey;
+ var previousSecondaryAccounts = this.accounts.SecondaryAccounts;
var oldIconCol = this.Use2ColumnsMode;
if (this.ShowSettingDialog() == DialogResult.OK)
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>
this.RefreshNoRetweetIdsAsync,
this.RefreshTwitterConfigurationAsync,
this.RefreshTabAsync<HomeTabModel>,
+ this.RefreshTabAsync<HomeSpecifiedAccountTabModel>,
this.RefreshTabAsync<MentionsTabModel>,
this.RefreshTabAsync<DirectMessagesTabModel>,
this.RefreshTabAsync<PublicSearchTabModel>,