OSDN Git Service

TwitterUserIdクラスを追加
authorKimura Youichi <kim.upsilon@bucyou.net>
Fri, 17 May 2024 18:39:42 +0000 (03:39 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Fri, 17 May 2024 20:02:13 +0000 (05:02 +0900)
36 files changed:
OpenTween.Tests/Api/GraphQL/CreateTweetRequestTest.cs
OpenTween.Tests/Api/GraphQL/LikesRequestTest.cs
OpenTween.Tests/Api/GraphQL/TimelineTweetTest.cs
OpenTween.Tests/Api/GraphQL/UserTweetsAndRepliesRequestTest.cs
OpenTween.Tests/Api/TwitterApiTest.cs
OpenTween.Tests/Models/PersonIdTest.cs [new file with mode: 0644]
OpenTween.Tests/Models/PostClassTest.cs
OpenTween.Tests/Models/TabInformationTest.cs
OpenTween.Tests/Models/TwitterPostFactoryTest.cs
OpenTween.Tests/SocialProtocol/AccountCollectionTest.cs
OpenTween.Tests/SocialProtocol/Twitter/TwitterAccountStateTest.cs
OpenTween.Tests/SocialProtocol/Twitter/TwitterAccountTest.cs
OpenTween.Tests/TimelineListViewCacheTest.cs
OpenTween.Tests/TweenMainTest.cs
OpenTween/Api/DataModel/TwitterPageable.cs
OpenTween/Api/GraphQL/CreateTweetRequest.cs
OpenTween/Api/GraphQL/LikesRequest.cs
OpenTween/Api/GraphQL/UserTweetsAndRepliesRequest.cs
OpenTween/Api/TwitterApi.cs
OpenTween/AppendSettingDialog.cs
OpenTween/ListElement.cs
OpenTween/Models/PersonId.cs [new file with mode: 0644]
OpenTween/Models/PostClass.cs
OpenTween/Models/TabInformations.cs
OpenTween/Models/TwitterPostFactory.cs
OpenTween/Models/TwitterUserId.cs [new file with mode: 0644]
OpenTween/Models/UserTimelineTabModel.cs
OpenTween/PostStatusParams.cs
OpenTween/Setting/Panel/BasedPanel.cs
OpenTween/Setting/SettingCommon.cs
OpenTween/SocialProtocol/ISocialAccount.cs
OpenTween/SocialProtocol/Twitter/TwitterAccount.cs
OpenTween/SocialProtocol/Twitter/TwitterAccountState.cs
OpenTween/Tween.cs
OpenTween/Twitter.cs
OpenTween/UserInfoDialog.cs

index b01e95a..e6c843f 100644 (file)
@@ -22,6 +22,7 @@
 using System.Threading.Tasks;
 using Moq;
 using OpenTween.Connection;
+using OpenTween.Models;
 using Xunit;
 
 namespace OpenTween.Api.GraphQL
@@ -78,7 +79,7 @@ namespace OpenTween.Api.GraphQL
             {
                 TweetText = "tetete",
                 InReplyToTweetId = new("12345"),
-                ExcludeReplyUserIds = new[] { "11111", "22222" },
+                ExcludeReplyUserIds = new TwitterUserId[] { new("11111"), new("22222") },
             };
             await request.Send(mock.Object);
             mock.VerifyAll();
index b9f5738..72eb618 100644 (file)
@@ -51,7 +51,7 @@ namespace OpenTween.Api.GraphQL
 
             var request = new LikesRequest
             {
-                UserId = "12345",
+                UserId = new("12345"),
                 Count = 20,
             };
 
@@ -83,7 +83,7 @@ namespace OpenTween.Api.GraphQL
 
             var request = new LikesRequest
             {
-                UserId = "12345",
+                UserId = new("12345"),
                 Count = 20,
                 Cursor = new("aaa"),
             };
index 38e6ace..3c3ed3b 100644 (file)
@@ -73,10 +73,10 @@ namespace OpenTween.Api.GraphQL
             var timelineTweet = new TimelineTweet(rootElm);
             var status = timelineTweet.ToTwitterStatus();
             var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
-            var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>(), firstLoad: false);
+            var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);
 
             Assert.Equal("1613784711020826626", post.StatusId.Id);
-            Assert.Equal(40480664L, post.UserId);
+            Assert.Equal(new TwitterUserId("40480664"), post.UserId);
             Assert.False(post.IsPromoted);
         }
 
@@ -87,10 +87,10 @@ namespace OpenTween.Api.GraphQL
             var timelineTweet = new TimelineTweet(rootElm);
             var status = timelineTweet.ToTwitterStatus();
             var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
-            var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>(), firstLoad: false);
+            var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);
 
             Assert.Equal("1614587968567783424", post.StatusId.Id);
-            Assert.Equal(40480664L, post.UserId);
+            Assert.Equal(new TwitterUserId("40480664"), post.UserId);
             Assert.Equal(2, post.Media.Count);
             Assert.Equal("https://pbs.twimg.com/media/FmgrJiEaAAEU42G.png", post.Media[0].Url);
             Assert.Equal("OpenTweenで @opentween のツイート一覧を表示しているスクショ", post.Media[0].AltText);
@@ -105,12 +105,12 @@ namespace OpenTween.Api.GraphQL
             var timelineTweet = new TimelineTweet(rootElm);
             var status = timelineTweet.ToTwitterStatus();
             var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
-            var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>(), firstLoad: false);
+            var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);
 
             Assert.Equal("1617128268548964354", post.StatusId.Id);
-            Assert.Equal(40480664L, post.RetweetedByUserId);
+            Assert.Equal(new TwitterUserId("40480664"), post.RetweetedByUserId);
             Assert.Equal("1617126084138659840", post.RetweetedId!.Id);
-            Assert.Equal(514241801L, post.UserId);
+            Assert.Equal(new TwitterUserId("514241801"), post.UserId);
         }
 
         [Fact]
@@ -120,10 +120,10 @@ namespace OpenTween.Api.GraphQL
             var timelineTweet = new TimelineTweet(rootElm);
             var status = timelineTweet.ToTwitterStatus();
             var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
-            var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>(), firstLoad: false);
+            var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);
 
             Assert.Equal("1602775353088524288", post.StatusId.Id);
-            Assert.Equal(357750891L, post.UserId);
+            Assert.Equal(new TwitterUserId("357750891"), post.UserId);
         }
 
         [Fact]
@@ -133,10 +133,10 @@ namespace OpenTween.Api.GraphQL
             var timelineTweet = new TimelineTweet(rootElm);
             var status = timelineTweet.ToTwitterStatus();
             var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
-            var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>(), firstLoad: false);
+            var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);
 
             Assert.Equal("1511751702684499968", post.StatusId.Id);
-            Assert.Equal(40480664L, post.UserId);
+            Assert.Equal(new TwitterUserId("40480664"), post.UserId);
         }
 
         [Fact]
@@ -146,7 +146,7 @@ namespace OpenTween.Api.GraphQL
             var timelineTweet = new TimelineTweet(rootElm);
             var status = timelineTweet.ToTwitterStatus();
             var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
-            var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>(), firstLoad: false);
+            var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);
 
             Assert.Equal("1588614645866147840", post.StatusId.Id);
             var quotedPostId = Assert.Single(post.QuoteStatusIds);
@@ -160,7 +160,7 @@ namespace OpenTween.Api.GraphQL
             var timelineTweet = new TimelineTweet(rootElm);
             var status = timelineTweet.ToTwitterStatus();
             var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
-            var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>(), firstLoad: false);
+            var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);
 
             Assert.Equal("1614653321310253057", post.StatusId.Id);
             var quotedPostId = Assert.Single(post.QuoteStatusIds);
@@ -174,10 +174,10 @@ namespace OpenTween.Api.GraphQL
             var timelineTweet = new TimelineTweet(rootElm);
             var status = timelineTweet.ToTwitterStatus();
             var postFactory = new TwitterPostFactory(this.CreateTabInfo(), new());
-            var post = postFactory.CreateFromStatus(status, selfUserId: 1L, new HashSet<long>(), firstLoad: false);
+            var post = postFactory.CreateFromStatus(status, selfUserId: new("1"), new HashSet<PersonId>(), firstLoad: false);
 
             Assert.Equal("1674737917363888129", post.StatusId.Id);
-            Assert.Equal(2941313791L, post.UserId);
+            Assert.Equal(new TwitterUserId("2941313791"), post.UserId);
             Assert.True(post.IsPromoted);
             Assert.Matches(new Regex(@"^\[Promoted\]\n"), post.TextFromApi);
         }
index 575df9d..4c31973 100644 (file)
@@ -22,6 +22,7 @@
 using System.Threading.Tasks;
 using Moq;
 using OpenTween.Connection;
+using OpenTween.Models;
 using Xunit;
 
 namespace OpenTween.Api.GraphQL
@@ -49,7 +50,7 @@ namespace OpenTween.Api.GraphQL
                 })
                 .ReturnsAsync(apiResponse);
 
-            var request = new UserTweetsAndRepliesRequest(userId: "40480664")
+            var request = new UserTweetsAndRepliesRequest(userId: new("40480664"))
             {
                 Count = 20,
             };
@@ -83,7 +84,7 @@ namespace OpenTween.Api.GraphQL
                 })
                 .ReturnsAsync(apiResponse);
 
-            var request = new UserTweetsAndRepliesRequest(userId: "40480664")
+            var request = new UserTweetsAndRepliesRequest(userId: new("40480664"))
             {
                 Count = 20,
                 Cursor = new("aaa"),
index 96fb472..c1ac6d7 100644 (file)
@@ -32,6 +32,7 @@ using System.Threading.Tasks;
 using Moq;
 using OpenTween.Api.DataModel;
 using OpenTween.Connection;
+using OpenTween.Models;
 using Xunit;
 
 namespace OpenTween.Api
@@ -276,7 +277,7 @@ namespace OpenTween.Api
                     replyToId: new("100"),
                     mediaIds: new[] { 10L, 20L },
                     autoPopulateReplyMetadata: true,
-                    excludeReplyUserIds: new[] { 100L, 200L },
+                    excludeReplyUserIds: new TwitterUserId[] { new("100"), new("200") },
                     attachmentUrl: "https://twitter.com/twitterapi/status/22634515958"
                 )
                 .IgnoreResponse();
@@ -304,7 +305,7 @@ namespace OpenTween.Api
             using var twitterApi = new TwitterApi();
             twitterApi.ApiConnection = mock.Object;
 
-            await twitterApi.StatusesUpdate("hogehoge", replyToId: null, mediaIds: null, excludeReplyUserIds: Array.Empty<long>())
+            await twitterApi.StatusesUpdate("hogehoge", replyToId: null, mediaIds: null, excludeReplyUserIds: Array.Empty<TwitterUserId>())
                 .IgnoreResponse();
 
             mock.VerifyAll();
@@ -770,7 +771,7 @@ namespace OpenTween.Api
             using var twitterApi = new TwitterApi();
             twitterApi.ApiConnection = mock.Object;
 
-            await twitterApi.DirectMessagesEventsNew(recipientId: 12345L, text: "hogehoge", mediaId: 67890L);
+            await twitterApi.DirectMessagesEventsNew(recipientId: new("12345"), text: "hogehoge", mediaId: 67890L);
 
             mock.VerifyAll();
         }
@@ -847,7 +848,7 @@ namespace OpenTween.Api
             using var twitterApi = new TwitterApi();
             twitterApi.ApiConnection = mock.Object;
 
-            await twitterApi.UsersLookup(userIds: new[] { "11111", "22222" });
+            await twitterApi.UsersLookup(userIds: new TwitterUserId[] { new("11111"), new("22222") });
 
             mock.VerifyAll();
         }
diff --git a/OpenTween.Tests/Models/PersonIdTest.cs b/OpenTween.Tests/Models/PersonIdTest.cs
new file mode 100644 (file)
index 0000000..575e232
--- /dev/null
@@ -0,0 +1,157 @@
+// 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.
+
+using Moq;
+using Xunit;
+
+namespace OpenTween.Models
+{
+    public class PersonIdTest
+    {
+        private PersonId CreatePersonId(string type, string id)
+        {
+            var mock = new Mock<PersonId>() { CallBase = true };
+            mock.Setup(x => x.IdType).Returns(type);
+            mock.Setup(x => x.Id).Returns(id);
+            return mock.Object;
+        }
+
+        [Fact]
+        public void CompareTo_Test()
+        {
+            var a = this.CreatePersonId("mastodon", "200");
+            var b = this.CreatePersonId("twitter", "100");
+            Assert.True(a.CompareTo(b) < 0);
+            Assert.True(b.CompareTo(a) > 0);
+            Assert.Equal(0, a.CompareTo(a));
+        }
+
+        [Fact]
+        public void CompareTo_SameIdTypeTest()
+        {
+            var a = this.CreatePersonId("twitter", "100");
+            var b = this.CreatePersonId("twitter", "200");
+            Assert.True(a.CompareTo(b) < 0);
+            Assert.True(b.CompareTo(a) > 0);
+            Assert.Equal(0, a.CompareTo(a));
+        }
+
+        [Fact]
+        public void CompareTo_IdLengthTest()
+        {
+            var a = this.CreatePersonId("twitter", "200");
+            var b = this.CreatePersonId("twitter", "1000");
+            Assert.True(a.CompareTo(b) < 0);
+            Assert.True(b.CompareTo(a) > 0);
+        }
+
+        [Fact]
+        public void OperatorGreaterThan_Test()
+        {
+            var a = this.CreatePersonId("twitter", "100");
+            var b = this.CreatePersonId("twitter", "200");
+#pragma warning disable CS1718
+            Assert.False(a < a);
+            Assert.True(a < b);
+            Assert.False(b < a);
+            Assert.False(b < b);
+            Assert.True(a <= a);
+            Assert.True(a <= b);
+            Assert.False(b <= a);
+            Assert.True(b <= b);
+#pragma warning restore CS1718
+        }
+
+        [Fact]
+        public void OperatorLessThan_Test()
+        {
+            var a = this.CreatePersonId("twitter", "100");
+            var b = this.CreatePersonId("twitter", "200");
+#pragma warning disable CS1718
+            Assert.False(a > a);
+            Assert.False(a > b);
+            Assert.True(b > a);
+            Assert.False(b > b);
+            Assert.True(a >= a);
+            Assert.False(a >= b);
+            Assert.True(b >= a);
+            Assert.True(b >= b);
+#pragma warning restore CS1718
+        }
+
+        [Fact]
+        public void Equals_Test()
+        {
+            var a = this.CreatePersonId("twitter", "100");
+            var b = this.CreatePersonId("twitter", "100");
+            Assert.True(a.Equals(b));
+            Assert.True(b.Equals(a));
+            Assert.True(a == b);
+            Assert.True(b == a);
+        }
+
+        [Fact]
+        public void Equals_NotSameIdTypeTest()
+        {
+            var a = this.CreatePersonId("mastodon", "100");
+            var b = this.CreatePersonId("twitter", "100");
+            Assert.False(a.Equals(b));
+            Assert.False(b.Equals(a));
+            Assert.True(a != b);
+            Assert.True(b != a);
+        }
+
+        [Fact]
+        public void Equals_NotSameIdTest()
+        {
+            var a = this.CreatePersonId("twitter", "100");
+            var b = this.CreatePersonId("twitter", "200");
+            Assert.False(a.Equals(b));
+            Assert.False(b.Equals(a));
+            Assert.True(a != b);
+            Assert.True(b != a);
+        }
+
+        [Fact]
+        public void GetHashCode_SameIdTest()
+        {
+            var a = this.CreatePersonId("twitter", "100");
+            var b = this.CreatePersonId("twitter", "100");
+            Assert.Equal(a.GetHashCode(), b.GetHashCode());
+        }
+
+        [Fact]
+        public void GetHashCode_NotSameIdTypeTest()
+        {
+            var a = this.CreatePersonId("mastodon", "100");
+            var b = this.CreatePersonId("twitter", "100");
+            Assert.NotEqual(a.GetHashCode(), b.GetHashCode());
+        }
+
+        [Fact]
+        public void GetHashCode_NotSameIdTest()
+        {
+            var a = this.CreatePersonId("twitter", "100");
+            var b = this.CreatePersonId("twitter", "200");
+            Assert.NotEqual(a.GetHashCode(), b.GetHashCode());
+        }
+    }
+}
index c7bbfb1..291b061 100644 (file)
@@ -129,10 +129,10 @@ namespace OpenTween.Models
             {
                 IsDm = true,
                 IsMe = true, // 自分が送信した DM
-                UserId = 222L, // 送信先ユーザーID
+                UserId = new TwitterUserId("222"), // 送信先ユーザーID
             };
 
-            Assert.True(post.CanDeleteBy(selfUserId: 111L));
+            Assert.True(post.CanDeleteBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -142,10 +142,10 @@ namespace OpenTween.Models
             {
                 IsDm = true,
                 IsMe = false, // 自分が受け取った DM
-                UserId = 222L, // 送信元ユーザーID
+                UserId = new TwitterUserId("222"), // 送信元ユーザーID
             };
 
-            Assert.True(post.CanDeleteBy(selfUserId: 111L));
+            Assert.True(post.CanDeleteBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -153,10 +153,10 @@ namespace OpenTween.Models
         {
             var post = new PostClass
             {
-                UserId = 111L, // 自分のツイート
+                UserId = new TwitterUserId("111"), // 自分のツイート
             };
 
-            Assert.True(post.CanDeleteBy(selfUserId: 111L));
+            Assert.True(post.CanDeleteBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -164,10 +164,10 @@ namespace OpenTween.Models
         {
             var post = new PostClass
             {
-                UserId = 222L, // 他人のツイート
+                UserId = new TwitterUserId("222"), // 他人のツイート
             };
 
-            Assert.False(post.CanDeleteBy(selfUserId: 111L));
+            Assert.False(post.CanDeleteBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -175,11 +175,11 @@ namespace OpenTween.Models
         {
             var post = new PostClass
             {
-                RetweetedByUserId = 111L, // 自分がリツイートした
-                UserId = 222L, // 他人のツイート
+                RetweetedByUserId = new TwitterUserId("111"), // 自分がリツイートした
+                UserId = new TwitterUserId("222"), // 他人のツイート
             };
 
-            Assert.True(post.CanDeleteBy(selfUserId: 111L));
+            Assert.True(post.CanDeleteBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -187,11 +187,11 @@ namespace OpenTween.Models
         {
             var post = new PostClass
             {
-                RetweetedByUserId = 333L, // 他人がリツイートした
-                UserId = 222L, // 他人のツイート
+                RetweetedByUserId = new TwitterUserId("333"), // 他人がリツイートした
+                UserId = new TwitterUserId("222"), // 他人のツイート
             };
 
-            Assert.False(post.CanDeleteBy(selfUserId: 111L));
+            Assert.False(post.CanDeleteBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -199,11 +199,11 @@ namespace OpenTween.Models
         {
             var post = new PostClass
             {
-                RetweetedByUserId = 222L, // 他人がリツイートした
-                UserId = 111L, // 自分のツイート
+                RetweetedByUserId = new TwitterUserId("222"), // 他人がリツイートした
+                UserId = new TwitterUserId("111"), // 自分のツイート
             };
 
-            Assert.True(post.CanDeleteBy(selfUserId: 111L));
+            Assert.True(post.CanDeleteBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -213,10 +213,10 @@ namespace OpenTween.Models
             {
                 IsDm = true,
                 IsMe = false, // 自分が受け取った DM
-                UserId = 222L, // 送信元ユーザーID
+                UserId = new TwitterUserId("222"), // 送信元ユーザーID
             };
 
-            Assert.False(post.CanRetweetBy(selfUserId: 111L));
+            Assert.False(post.CanRetweetBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -224,10 +224,10 @@ namespace OpenTween.Models
         {
             var post = new PostClass
             {
-                UserId = 111L, // 自分のツイート
+                UserId = new TwitterUserId("111"), // 自分のツイート
             };
 
-            Assert.True(post.CanRetweetBy(selfUserId: 111L));
+            Assert.True(post.CanRetweetBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -235,11 +235,11 @@ namespace OpenTween.Models
         {
             var post = new PostClass
             {
-                UserId = 111L, // 自分のツイート
+                UserId = new TwitterUserId("111"), // 自分のツイート
                 IsProtect = true,
             };
 
-            Assert.True(post.CanRetweetBy(selfUserId: 111L));
+            Assert.True(post.CanRetweetBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -247,11 +247,11 @@ namespace OpenTween.Models
         {
             var post = new PostClass
             {
-                UserId = 222L, // 他人のツイート
+                UserId = new TwitterUserId("222"), // 他人のツイート
                 IsProtect = false,
             };
 
-            Assert.True(post.CanRetweetBy(selfUserId: 111L));
+            Assert.True(post.CanRetweetBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -259,11 +259,11 @@ namespace OpenTween.Models
         {
             var post = new PostClass
             {
-                UserId = 222L, // 他人のツイート
+                UserId = new TwitterUserId("222"), // 他人のツイート
                 IsProtect = true,
             };
 
-            Assert.False(post.CanRetweetBy(selfUserId: 111L));
+            Assert.False(post.CanRetweetBy(selfUserId: new TwitterUserId("111")));
         }
 
         [Fact]
@@ -275,11 +275,11 @@ namespace OpenTween.Models
                 CreatedAtForSorting = new(2023, 1, 2, 0, 0, 0),
                 CreatedAt = new(2023, 1, 1, 0, 0, 0),
                 ScreenName = "@aaa",
-                UserId = 1L,
+                UserId = new TwitterUserId("1"),
 
                 RetweetedId = new TwitterStatusId("50"),
                 RetweetedBy = "@bbb",
-                RetweetedByUserId = 2L,
+                RetweetedByUserId = new TwitterUserId("2"),
                 RetweetedCount = 0,
             };
 
@@ -289,7 +289,7 @@ namespace OpenTween.Models
             Assert.Equal(new(2023, 1, 1, 0, 0, 0), originalPost.CreatedAt);
             Assert.Equal(new(2023, 1, 1, 0, 0, 0), originalPost.CreatedAtForSorting);
             Assert.Equal("@aaa", originalPost.ScreenName);
-            Assert.Equal(1L, originalPost.UserId);
+            Assert.Equal(new TwitterUserId("1"), originalPost.UserId);
 
             Assert.Null(originalPost.RetweetedId);
             Assert.Equal("", originalPost.RetweetedBy);
index 1e6377b..ca59d86 100644 (file)
@@ -542,11 +542,11 @@ namespace OpenTween.Models
         [Fact]
         public void IsMuted_Test()
         {
-            this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
+            this.tabinfo.MuteUserIds = new HashSet<PersonId> { new TwitterUserId("12345") };
 
             var post = new PostClass
             {
-                UserId = 12345L,
+                UserId = new TwitterUserId("12345"),
                 Text = "hogehoge",
             };
             Assert.True(this.tabinfo.IsMuted(post, isHomeTimeline: true));
@@ -555,11 +555,11 @@ namespace OpenTween.Models
         [Fact]
         public void IsMuted_NotMutingTest()
         {
-            this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
+            this.tabinfo.MuteUserIds = new HashSet<PersonId> { new TwitterUserId("12345") };
 
             var post = new PostClass
             {
-                UserId = 11111L,
+                UserId = new TwitterUserId("11111"),
                 Text = "hogehoge",
             };
             Assert.False(this.tabinfo.IsMuted(post, isHomeTimeline: true));
@@ -568,12 +568,12 @@ namespace OpenTween.Models
         [Fact]
         public void IsMuted_RetweetTest()
         {
-            this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
+            this.tabinfo.MuteUserIds = new HashSet<PersonId> { new TwitterUserId("12345") };
 
             var post = new PostClass
             {
-                UserId = 11111L,
-                RetweetedByUserId = 12345L,
+                UserId = new TwitterUserId("11111"),
+                RetweetedByUserId = new TwitterUserId("12345"),
                 Text = "hogehoge",
             };
             Assert.True(this.tabinfo.IsMuted(post, isHomeTimeline: true));
@@ -582,12 +582,12 @@ namespace OpenTween.Models
         [Fact]
         public void IsMuted_RetweetNotMutingTest()
         {
-            this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
+            this.tabinfo.MuteUserIds = new HashSet<PersonId> { new TwitterUserId("12345") };
 
             var post = new PostClass
             {
-                UserId = 11111L,
-                RetweetedByUserId = 22222L,
+                UserId = new TwitterUserId("11111"),
+                RetweetedByUserId = new TwitterUserId("22222"),
                 Text = "hogehoge",
             };
             Assert.False(this.tabinfo.IsMuted(post, isHomeTimeline: true));
@@ -596,12 +596,12 @@ namespace OpenTween.Models
         [Fact]
         public void IsMuted_ReplyTest()
         {
-            this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
+            this.tabinfo.MuteUserIds = new HashSet<PersonId> { new TwitterUserId("12345") };
 
             // ミュート対象のユーザーであってもリプライの場合は対象外とする
             var post = new PostClass
             {
-                UserId = 12345L,
+                UserId = new TwitterUserId("12345"),
                 Text = "@foo hogehoge",
                 IsReply = true,
             };
@@ -611,12 +611,12 @@ namespace OpenTween.Models
         [Fact]
         public void IsMuted_NotInHomeTimelineTest()
         {
-            this.tabinfo.MuteUserIds = new HashSet<long> { 12345L };
+            this.tabinfo.MuteUserIds = new HashSet<PersonId> { new TwitterUserId("12345") };
 
             // Recent以外のタブ(検索など)の場合は対象外とする
             var post = new PostClass
             {
-                UserId = 12345L,
+                UserId = new TwitterUserId("12345"),
                 Text = "hogehoge",
             };
             Assert.False(this.tabinfo.IsMuted(post, isHomeTimeline: false));
@@ -625,7 +625,7 @@ namespace OpenTween.Models
         [Fact]
         public void IsMuted_MuteTabRulesTest()
         {
-            this.tabinfo.MuteUserIds = new HashSet<long> { };
+            this.tabinfo.MuteUserIds = new HashSet<PersonId> { };
 
             var muteTab = new MuteTabModel();
             muteTab.AddFilter(new PostFilterRule
@@ -637,7 +637,7 @@ namespace OpenTween.Models
 
             var post = new PostClass
             {
-                UserId = 12345L,
+                UserId = new TwitterUserId("12345"),
                 ScreenName = "foo",
                 Text = "hogehoge",
             };
@@ -647,7 +647,7 @@ namespace OpenTween.Models
         [Fact]
         public void IsMuted_MuteTabRules_NotInHomeTimelineTest()
         {
-            this.tabinfo.MuteUserIds = new HashSet<long> { };
+            this.tabinfo.MuteUserIds = new HashSet<PersonId> { };
 
             var muteTab = new MuteTabModel();
             muteTab.AddFilter(new PostFilterRule
@@ -660,7 +660,7 @@ namespace OpenTween.Models
             // ミュートタブによるミュートはリプライも対象とする
             var post = new PostClass
             {
-                UserId = 12345L,
+                UserId = new TwitterUserId("12345"),
                 ScreenName = "foo",
                 Text = "@hoge hogehoge",
                 IsReply = true,
@@ -1291,14 +1291,14 @@ namespace OpenTween.Models
             {
                 StatusId = new TwitterStatusId("100"),
                 ScreenName = "aaa",
-                UserId = 123L,
+                UserId = new TwitterUserId("123"),
                 IsOwl = true,
             };
             this.tabinfo.AddPost(post);
             this.tabinfo.DistributePosts();
             this.tabinfo.SubmitUpdate();
 
-            var followerIds = new HashSet<long> { 123L };
+            var followerIds = new HashSet<PersonId> { new TwitterUserId("123") };
             this.tabinfo.RefreshOwl(followerIds);
 
             Assert.False(post.IsOwl);
@@ -1314,14 +1314,14 @@ namespace OpenTween.Models
             {
                 StatusId = new TwitterStatusId("100"),
                 ScreenName = "aaa",
-                UserId = 123L,
+                UserId = new TwitterUserId("123"),
                 IsOwl = true,
             };
             tab.AddPostQueue(post);
             this.tabinfo.DistributePosts();
             this.tabinfo.SubmitUpdate();
 
-            var followerIds = new HashSet<long> { 123L };
+            var followerIds = new HashSet<PersonId> { new TwitterUserId("123") };
             this.tabinfo.RefreshOwl(followerIds);
 
             Assert.False(post.IsOwl);
@@ -1334,14 +1334,14 @@ namespace OpenTween.Models
             {
                 StatusId = new TwitterStatusId("100"),
                 ScreenName = "aaa",
-                UserId = 123L,
+                UserId = new TwitterUserId("123"),
                 IsOwl = false,
             };
             this.tabinfo.AddPost(post);
             this.tabinfo.DistributePosts();
             this.tabinfo.SubmitUpdate();
 
-            var followerIds = new HashSet<long> { 456L };
+            var followerIds = new HashSet<PersonId> { new TwitterUserId("456") };
             this.tabinfo.RefreshOwl(followerIds);
 
             Assert.True(post.IsOwl);
index 9c74484..8ab1b74 100644 (file)
@@ -28,7 +28,7 @@ namespace OpenTween.Models
 {
     public class TwitterPostFactoryTest
     {
-        private static readonly ISet<long> EmptyIdSet = new HashSet<long>();
+        private static readonly ISet<PersonId> EmptyIdSet = new HashSet<PersonId>();
 
         private readonly Random random = new();
 
@@ -74,7 +74,7 @@ namespace OpenTween.Models
         {
             var factory = new TwitterPostFactory(this.CreateTabinfo(), new());
             var status = this.CreateStatus();
-            var post = factory.CreateFromStatus(status, selfUserId: 20000L, followerIds: EmptyIdSet, firstLoad: false);
+            var post = factory.CreateFromStatus(status, selfUserId: new("20000"), followerIds: EmptyIdSet, firstLoad: false);
 
             Assert.Equal(new TwitterStatusId(status.IdStr), post.StatusId);
             Assert.Equal(new DateTimeUtc(2022, 1, 1, 0, 0, 0), post.CreatedAt);
@@ -107,7 +107,7 @@ namespace OpenTween.Models
             Assert.Null(post.RetweetedBy);
             Assert.Null(post.RetweetedByUserId);
 
-            Assert.Equal(status.User.Id, post.UserId);
+            Assert.Equal(new TwitterUserId(status.User.IdStr), post.UserId);
             Assert.Equal("tetete", post.ScreenName);
             Assert.Equal("ててて", post.Nickname);
             Assert.Equal("https://example.com/profile.png", post.ImageUrl);
@@ -123,7 +123,7 @@ namespace OpenTween.Models
         {
             var factory = new TwitterPostFactory(this.CreateTabinfo(), new());
             var status = this.CreateStatus();
-            var selfUserId = status.User.Id;
+            var selfUserId = new TwitterUserId(status.User.IdStr);
             var post = factory.CreateFromStatus(status, selfUserId, followerIds: EmptyIdSet, firstLoad: false);
 
             Assert.True(post.IsMe);
@@ -134,8 +134,8 @@ namespace OpenTween.Models
         {
             var factory = new TwitterPostFactory(this.CreateTabinfo(), new());
             var status = this.CreateStatus();
-            var followerIds = new HashSet<long> { status.User.Id };
-            var post = factory.CreateFromStatus(status, selfUserId: 20000L, followerIds, firstLoad: false);
+            var followerIds = new HashSet<PersonId> { new TwitterUserId(status.User.IdStr) };
+            var post = factory.CreateFromStatus(status, selfUserId: new("20000"), followerIds, firstLoad: false);
 
             Assert.False(post.IsOwl);
         }
@@ -145,8 +145,8 @@ namespace OpenTween.Models
         {
             var factory = new TwitterPostFactory(this.CreateTabinfo(), new());
             var status = this.CreateStatus();
-            var followerIds = new HashSet<long> { 30000L };
-            var post = factory.CreateFromStatus(status, selfUserId: 20000L, followerIds, firstLoad: false);
+            var followerIds = new HashSet<PersonId> { new TwitterUserId("30000") };
+            var post = factory.CreateFromStatus(status, selfUserId: new("20000"), followerIds, firstLoad: false);
 
             Assert.True(post.IsOwl);
         }
@@ -161,12 +161,12 @@ namespace OpenTween.Models
             retweetStatus.RetweetedStatus = originalStatus;
             retweetStatus.Source = """<a href="https://mobile.twitter.com" rel="nofollow">Twitter Web App</a>""";
 
-            var post = factory.CreateFromStatus(retweetStatus, selfUserId: 20000L, followerIds: EmptyIdSet, firstLoad: false);
+            var post = factory.CreateFromStatus(retweetStatus, selfUserId: new("20000"), followerIds: EmptyIdSet, firstLoad: false);
 
             Assert.Equal(new TwitterStatusId(retweetStatus.IdStr), post.StatusId);
-            Assert.Equal(retweetStatus.User.Id, post.RetweetedByUserId);
+            Assert.Equal(new TwitterUserId(retweetStatus.User.IdStr), post.RetweetedByUserId);
             Assert.Equal(new TwitterStatusId(originalStatus.IdStr), post.RetweetedId);
-            Assert.Equal(originalStatus.User.Id, post.UserId);
+            Assert.Equal(new TwitterUserId(originalStatus.User.IdStr), post.UserId);
 
             Assert.Equal("OpenTween", post.Source);
             Assert.Equal("https://www.opentween.org/", post.SourceUri?.OriginalString);
@@ -182,7 +182,7 @@ namespace OpenTween.Models
 
             var factory = new TwitterPostFactory(this.CreateTabinfo(), settingCommon);
             var status = this.CreateStatus();
-            var post = factory.CreateFromStatus(status, selfUserId: 20000L, followerIds: EmptyIdSet, firstLoad: true);
+            var post = factory.CreateFromStatus(status, selfUserId: new("20000"), followerIds: EmptyIdSet, firstLoad: true);
 
             Assert.True(post.IsRead); // 既読
         }
@@ -197,7 +197,7 @@ namespace OpenTween.Models
 
             var factory = new TwitterPostFactory(this.CreateTabinfo(), settingCommon);
             var status = this.CreateStatus();
-            var post = factory.CreateFromStatus(status, selfUserId: 20000L, followerIds: EmptyIdSet, firstLoad: true);
+            var post = factory.CreateFromStatus(status, selfUserId: new("20000"), followerIds: EmptyIdSet, firstLoad: true);
 
             Assert.False(post.IsRead); // 未読
         }
@@ -213,7 +213,7 @@ namespace OpenTween.Models
             var factory = new TwitterPostFactory(this.CreateTabinfo(), settingCommon);
             var status = this.CreateStatus();
             status.User.Id = 20000L;
-            var post = factory.CreateFromStatus(status, selfUserId: 20000L, followerIds: EmptyIdSet, firstLoad: false);
+            var post = factory.CreateFromStatus(status, selfUserId: new("20000"), followerIds: EmptyIdSet, firstLoad: false);
 
             Assert.False(post.IsRead); // 未読
         }
@@ -228,8 +228,8 @@ namespace OpenTween.Models
 
             var factory = new TwitterPostFactory(this.CreateTabinfo(), settingCommon);
             var status = this.CreateStatus();
-            status.User.Id = 20000L;
-            var post = factory.CreateFromStatus(status, selfUserId: 20000L, followerIds: EmptyIdSet, firstLoad: false);
+            status.User.IdStr = "20000";
+            var post = factory.CreateFromStatus(status, selfUserId: new("20000"), followerIds: EmptyIdSet, firstLoad: false);
 
             Assert.True(post.IsRead); // 既読
         }
@@ -281,13 +281,13 @@ namespace OpenTween.Models
             var selfUser = this.CreateUser();
             var otherUser = this.CreateUser();
             var eventItem = this.CreateDirectMessage(senderId: otherUser.IdStr, recipientId: selfUser.IdStr);
-            var users = new Dictionary<string, TwitterUser>()
+            var users = new Dictionary<TwitterUserId, TwitterUser>()
             {
-                [selfUser.IdStr] = selfUser,
-                [otherUser.IdStr] = otherUser,
+                [new(selfUser.IdStr)] = selfUser,
+                [new(otherUser.IdStr)] = otherUser,
             };
             var apps = this.CreateApps();
-            var post = factory.CreateFromDirectMessageEvent(eventItem, users, apps, selfUserId: selfUser.Id, firstLoad: false);
+            var post = factory.CreateFromDirectMessageEvent(eventItem, users, apps, selfUserId: new(selfUser.IdStr), firstLoad: false);
 
             Assert.Equal(new TwitterDirectMessageId(eventItem.Id), post.StatusId);
             Assert.Equal(new DateTimeUtc(2022, 1, 1, 0, 0, 0), post.CreatedAt);
@@ -320,7 +320,7 @@ namespace OpenTween.Models
             Assert.Null(post.RetweetedBy);
             Assert.Null(post.RetweetedByUserId);
 
-            Assert.Equal(otherUser.Id, post.UserId);
+            Assert.Equal(new TwitterUserId(otherUser.IdStr), post.UserId);
             Assert.Equal("tetete", post.ScreenName);
             Assert.Equal("ててて", post.Nickname);
             Assert.Equal("https://example.com/profile.png", post.ImageUrl);
@@ -339,15 +339,15 @@ namespace OpenTween.Models
             var selfUser = this.CreateUser();
             var otherUser = this.CreateUser();
             var eventItem = this.CreateDirectMessage(senderId: selfUser.IdStr, recipientId: otherUser.IdStr);
-            var users = new Dictionary<string, TwitterUser>()
+            var users = new Dictionary<TwitterUserId, TwitterUser>()
             {
-                [selfUser.IdStr] = selfUser,
-                [otherUser.IdStr] = otherUser,
+                [new(selfUser.IdStr)] = selfUser,
+                [new(otherUser.IdStr)] = otherUser,
             };
             var apps = this.CreateApps();
-            var post = factory.CreateFromDirectMessageEvent(eventItem, users, apps, selfUserId: selfUser.Id, firstLoad: false);
+            var post = factory.CreateFromDirectMessageEvent(eventItem, users, apps, selfUserId: new(selfUser.IdStr), firstLoad: false);
 
-            Assert.Equal(otherUser.Id, post.UserId);
+            Assert.Equal(new TwitterUserId(otherUser.IdStr), post.UserId);
             Assert.False(post.IsOwl);
             Assert.True(post.IsMe);
         }
@@ -367,7 +367,7 @@ namespace OpenTween.Models
                 },
             };
 
-            _ = factory.CreateFromStatus(status, selfUserId: 20000L, followerIds: EmptyIdSet, firstLoad: false);
+            _ = factory.CreateFromStatus(status, selfUserId: new("20000"), followerIds: EmptyIdSet, firstLoad: false);
 
             Assert.Equal(new[] { "#OpenTween" }, factory.GetReceivedHashtags());
             Assert.Empty(factory.GetReceivedHashtags());
@@ -395,7 +395,7 @@ namespace OpenTween.Models
                 },
             };
 
-            var post = factory.CreateFromStatus(status, selfUserId: 100L, followerIds: EmptyIdSet, firstLoad: false);
+            var post = factory.CreateFromStatus(status, selfUserId: new("100"), followerIds: EmptyIdSet, firstLoad: false);
 
             var accessibleText = string.Format(Properties.Resources.ImageAltText, "代替テキスト");
             Assert.Equal(accessibleText, post.AccessibleText);
@@ -426,7 +426,7 @@ namespace OpenTween.Models
                 },
             };
 
-            var post = factory.CreateFromStatus(status, selfUserId: 100L, followerIds: EmptyIdSet, firstLoad: false);
+            var post = factory.CreateFromStatus(status, selfUserId: new("100"), followerIds: EmptyIdSet, firstLoad: false);
 
             Assert.Equal("pic.twitter.com/hoge", post.AccessibleText);
             Assert.Equal("""<a href="https://t.co/hoge" title="https://twitter.com/hoge/status/1234567890/photo/1">pic.twitter.com/hoge</a>""", post.Text);
@@ -467,7 +467,7 @@ namespace OpenTween.Models
                 FullText = "test",
             };
 
-            var post = factory.CreateFromStatus(status, selfUserId: 100L, followerIds: EmptyIdSet, firstLoad: false);
+            var post = factory.CreateFromStatus(status, selfUserId: new("100"), followerIds: EmptyIdSet, firstLoad: false);
 
             var accessibleText = string.Format(Properties.Resources.QuoteStatus_AccessibleText, "foo", "test");
             Assert.Equal(accessibleText, post.AccessibleText);
@@ -502,7 +502,7 @@ namespace OpenTween.Models
                 Expanded = "https://twitter.com/hoge/status/1234567890",
             };
 
-            var post = factory.CreateFromStatus(status, selfUserId: 100L, followerIds: EmptyIdSet, firstLoad: false);
+            var post = factory.CreateFromStatus(status, selfUserId: new("100"), followerIds: EmptyIdSet, firstLoad: false);
 
             var accessibleText = "hoge " + string.Format(Properties.Resources.QuoteStatus_AccessibleText, "foo", "test");
             Assert.Equal(accessibleText, post.AccessibleText);
@@ -533,7 +533,7 @@ namespace OpenTween.Models
             };
             status.QuotedStatus = null;
 
-            var post = factory.CreateFromStatus(status, selfUserId: 100L, followerIds: EmptyIdSet, firstLoad: false);
+            var post = factory.CreateFromStatus(status, selfUserId: new("100"), followerIds: EmptyIdSet, firstLoad: false);
 
             var accessibleText = "twitter.com/hoge/status/1…";
             Assert.Equal(accessibleText, post.AccessibleText);
index c75d895..7ba90e6 100644 (file)
@@ -38,7 +38,7 @@ namespace OpenTween.SocialProtocol
                 TwitterAuthType = APIAuthType.OAuth1,
                 Token = "aaaaa",
                 TokenSecret = "bbbbb",
-                UserId = this.random.Next(),
+                UserId = this.random.Next().ToString(),
                 Username = "tetete",
             };
         }
@@ -59,7 +59,7 @@ namespace OpenTween.SocialProtocol
             accounts.LoadFromSettings(settingCommon);
 
             Assert.Single(accounts.Items);
-            Assert.Equal(settingCommon.UserAccounts[0].UserId, accounts.Primary.UserId);
+            Assert.Equal(new TwitterUserId(settingCommon.UserAccounts[0].UserId), accounts.Primary.UserId);
         }
 
         [Fact]
@@ -78,7 +78,7 @@ namespace OpenTween.SocialProtocol
             accounts.LoadFromSettings(settingCommon1);
 
             var accountItem1 = Assert.Single(accounts.Items);
-            Assert.Equal(settingCommon1.UserAccounts[0].UserId, accounts.Primary.UserId);
+            Assert.Equal(new TwitterUserId(settingCommon1.UserAccounts[0].UserId), accounts.Primary.UserId);
 
             var settingCommon2 = new SettingCommon
             {
@@ -112,7 +112,7 @@ namespace OpenTween.SocialProtocol
             accounts.LoadFromSettings(settingCommon1);
 
             var accountItem1 = Assert.Single(accounts.Items);
-            Assert.Equal(settingCommon1.UserAccounts[0].UserId, accounts.Primary.UserId);
+            Assert.Equal(new TwitterUserId(settingCommon1.UserAccounts[0].UserId), accounts.Primary.UserId);
 
             var settingCommon2 = new SettingCommon
             {
@@ -126,16 +126,16 @@ namespace OpenTween.SocialProtocol
             accounts.LoadFromSettings(settingCommon2);
 
             var accountItem2 = Assert.Single(accounts.Items);
-            Assert.Equal(settingCommon2.UserAccounts[0].UserId, accounts.Primary.UserId);
+            Assert.Equal(new TwitterUserId(settingCommon2.UserAccounts[0].UserId), accounts.Primary.UserId);
 
             // 同一の ID は同じインスタンスを使用
             Assert.Same(accountItem1, accountItem2);
             Assert.NotEqual(
-                settingCommon1.UserAccounts[0].UserId,
+                new TwitterUserId(settingCommon1.UserAccounts[0].UserId),
                 accountItem2.UserId
             );
             Assert.Equal(
-                settingCommon2.UserAccounts[0].UserId,
+                new TwitterUserId(settingCommon2.UserAccounts[0].UserId),
                 accountItem2.UserId
             );
             Assert.False(accountItem2.IsDisposed);
index 0035cdf..3ab0d6d 100644 (file)
@@ -20,6 +20,7 @@
 // Boston, MA 02110-1301, USA.
 
 using OpenTween.Api.DataModel;
+using OpenTween.Models;
 using Xunit;
 
 namespace OpenTween.SocialProtocol.Twitter
@@ -42,7 +43,7 @@ namespace OpenTween.SocialProtocol.Twitter
             };
             accountState.UpdateFromUser(twitterUser);
 
-            Assert.Equal(514241801L, accountState.UserId);
+            Assert.Equal(new TwitterUserId("514241801"), accountState.UserId);
             Assert.Equal("OpenTween", accountState.UserName);
             Assert.Equal(31, accountState.StatusesCount);
             Assert.Equal(1, accountState.FriendsCount);
index 043543d..0564b3d 100644 (file)
@@ -20,6 +20,7 @@
 // Boston, MA 02110-1301, USA.
 
 using System;
+using OpenTween.Models;
 using Xunit;
 
 namespace OpenTween.SocialProtocol.Twitter
@@ -38,12 +39,12 @@ namespace OpenTween.SocialProtocol.Twitter
                 TwitterAuthType = APIAuthType.OAuth1,
                 Token = "aaaaa",
                 TokenSecret = "aaaaa",
-                UserId = 11111L,
+                UserId = "11111",
                 Username = "tetete",
             };
             var settingCommon = new SettingCommon();
             account.Initialize(accountSettings, settingCommon);
-            Assert.Equal(11111L, account.UserId);
+            Assert.Equal(new TwitterUserId("11111"), account.UserId);
             Assert.Equal("tetete", account.UserName);
             Assert.Equal(APIAuthType.OAuth1, account.AuthType);
             Assert.Same(account.Legacy.Api.Connection, account.Connection);
@@ -61,12 +62,12 @@ namespace OpenTween.SocialProtocol.Twitter
                 TwitterAuthType = APIAuthType.OAuth1,
                 Token = "aaaaa",
                 TokenSecret = "aaaaa",
-                UserId = 11111L,
+                UserId = "11111",
                 Username = "tetete",
             };
             var settingCommon1 = new SettingCommon();
             account.Initialize(accountSettings1, settingCommon1);
-            Assert.Equal(11111L, account.UserId);
+            Assert.Equal(new TwitterUserId("11111"), account.UserId);
 
             var accountSettings2 = new UserAccount
             {
@@ -74,12 +75,12 @@ namespace OpenTween.SocialProtocol.Twitter
                 TwitterAuthType = APIAuthType.OAuth1,
                 Token = "bbbbb",
                 TokenSecret = "bbbbb",
-                UserId = 22222L,
+                UserId = "22222",
                 Username = "hoge",
             };
             var settingCommon2 = new SettingCommon();
             account.Initialize(accountSettings2, settingCommon2);
-            Assert.Equal(22222L, account.UserId);
+            Assert.Equal(new TwitterUserId("22222"), account.UserId);
         }
 
         [Fact]
@@ -101,7 +102,7 @@ namespace OpenTween.SocialProtocol.Twitter
                 TwitterAuthType = APIAuthType.OAuth1,
                 Token = "aaaaa",
                 TokenSecret = "aaaaa",
-                UserId = 11111L,
+                UserId = "11111",
                 Username = "tetete",
             };
             var settingCommon = new SettingCommon();
@@ -121,7 +122,7 @@ namespace OpenTween.SocialProtocol.Twitter
                 UniqueKey = accountKey,
                 TwitterAuthType = APIAuthType.TwitterComCookie,
                 TwitterComCookie = "auth_token=foo; ct0=bar",
-                UserId = 11111L,
+                UserId = "11111",
                 Username = "tetete",
             };
             var settingCommon = new SettingCommon();
index 6b88e5d..667e05f 100644 (file)
@@ -35,7 +35,7 @@ namespace OpenTween
             return new()
             {
                 StatusId = new TwitterStatusId(this.random.Next(10000)),
-                UserId = this.random.Next(10000),
+                UserId = new TwitterUserId(this.random.Next(10000).ToString()),
                 ScreenName = "test",
                 Nickname = "てすと",
                 AccessibleText = "foo",
index 7feab84..180d426 100644 (file)
@@ -219,7 +219,7 @@ namespace OpenTween
                 {
                     StatusId = new TwitterStatusId("100"),
                     Text = "hoge",
-                    UserId = 111L,
+                    UserId = new TwitterUserId("111"),
                     ScreenName = "opentween",
                     CreatedAt = new(2024, 1, 1, 0, 0, 0),
                 };
index e7b9e57..5a5b01e 100644 (file)
@@ -27,6 +27,7 @@ using System.Linq;
 using System.Runtime.Serialization;
 using System.Text;
 using System.Threading.Tasks;
+using OpenTween.Models;
 
 namespace OpenTween.Api.DataModel
 {
@@ -69,14 +70,14 @@ namespace OpenTween.Api.DataModel
     }
 
     [DataContract]
-    public class TwitterIds : TwitterPageable<long>
+    public class TwitterIds : TwitterPageable<TwitterUserId>
     {
         [DataMember(Name = "ids")]
-        public long[] Ids { get; set; }
+        public string[] Ids { get; set; }
 
         [IgnoreDataMember]
-        public override long[] Items
-            => this.Ids;
+        public override TwitterUserId[] Items
+            => this.Ids.Select(x => new TwitterUserId(x)).ToArray();
 
         /// <exception cref="SerializationException"/>
         public static TwitterIds ParseJson(string json)
index 5caf3ac..b268cb8 100644 (file)
@@ -41,7 +41,7 @@ namespace OpenTween.Api.GraphQL
 
         public TwitterStatusId? InReplyToTweetId { get; set; }
 
-        public string[] ExcludeReplyUserIds { get; set; } = Array.Empty<string>();
+        public TwitterUserId[] ExcludeReplyUserIds { get; set; } = Array.Empty<TwitterUserId>();
 
         public string[] MediaIds { get; set; } = Array.Empty<string>();
 
@@ -105,7 +105,7 @@ namespace OpenTween.Api.GraphQL
                     Reply: this.InReplyToTweetId != null
                         ? new(
                             InReplyToTweetId: this.InReplyToTweetId.Id,
-                            ExcludeReplyUserIds: this.ExcludeReplyUserIds
+                            ExcludeReplyUserIds: this.ExcludeReplyUserIds.Select(x => x.Id).ToArray()
                         )
                         : null,
                     Media: this.MediaIds.Length > 0
index b03dbf4..31dd294 100644 (file)
@@ -25,6 +25,7 @@ using System;
 using System.Collections.Generic;
 using System.Threading.Tasks;
 using OpenTween.Connection;
+using OpenTween.Models;
 
 namespace OpenTween.Api.GraphQL
 {
@@ -34,7 +35,7 @@ namespace OpenTween.Api.GraphQL
 
         private static readonly Uri EndpointUri = new("https://twitter.com/i/api/graphql/G_zHbTiwSqLm0TAK_3sNWQ/Likes");
 
-        public required string UserId { get; set; }
+        public required TwitterUserId UserId { get; set; }
 
         public int Count { get; set; } = 20;
 
@@ -47,7 +48,7 @@ namespace OpenTween.Api.GraphQL
             return new()
             {
                 ["variables"] = "{" +
-                    $@"""userId"":""{JsonUtils.EscapeJsonString(this.UserId)}""," +
+                    $@"""userId"":""{JsonUtils.EscapeJsonString(this.UserId.Id)}""," +
                     $@"""count"":{this.Count}," +
                     $@"""includePromotedContent"":false," +
                     $@"""withClientEventToken"":false," +
index 8bbf154..f5d629f 100644 (file)
@@ -25,6 +25,7 @@ using System;
 using System.Collections.Generic;
 using System.Threading.Tasks;
 using OpenTween.Connection;
+using OpenTween.Models;
 
 namespace OpenTween.Api.GraphQL
 {
@@ -34,13 +35,13 @@ namespace OpenTween.Api.GraphQL
 
         private static readonly Uri EndpointUri = new("https://twitter.com/i/api/graphql/YlkSUg0mRBx7-EkxCvc-bw/UserTweetsAndReplies");
 
-        public string UserId { get; set; }
+        public TwitterUserId UserId { get; set; }
 
         public int Count { get; set; } = 20;
 
         public TwitterGraphqlCursor? Cursor { get; set; }
 
-        public UserTweetsAndRepliesRequest(string userId)
+        public UserTweetsAndRepliesRequest(TwitterUserId userId)
             => this.UserId = userId;
 
         public Dictionary<string, string> CreateParameters()
@@ -50,7 +51,7 @@ namespace OpenTween.Api.GraphQL
             return new()
             {
                 ["variables"] = "{" +
-                    $@"""userId"":""{JsonUtils.EscapeJsonString(this.UserId)}""," +
+                    $@"""userId"":""{JsonUtils.EscapeJsonString(this.UserId.Id)}""," +
                     $@"""count"":{this.Count}," +
                     $@"""includePromotedContent"":true," +
                     $@"""withCommunity"":true," +
index 07f6714..3277b8d 100644 (file)
@@ -193,7 +193,7 @@ namespace OpenTween.Api
             TwitterStatusId? replyToId,
             IReadOnlyList<long>? mediaIds,
             bool? autoPopulateReplyMetadata = null,
-            IReadOnlyList<long>? excludeReplyUserIds = null,
+            IReadOnlyList<TwitterUserId>? excludeReplyUserIds = null,
             string? attachmentUrl = null)
         {
             var param = new Dictionary<string, string>
@@ -613,7 +613,7 @@ namespace OpenTween.Api
                 .ConfigureAwait(false);
         }
 
-        public async Task<LazyJson<TwitterMessageEventSingle>> DirectMessagesEventsNew(long recipientId, string text, long? mediaId = null)
+        public async Task<LazyJson<TwitterMessageEventSingle>> DirectMessagesEventsNew(TwitterUserId recipientId, string text, long? mediaId = null)
         {
             var attachment = "";
             if (mediaId != null)
@@ -634,7 +634,7 @@ namespace OpenTween.Api
                     "type": "message_create",
                     "message_create": {
                       "target": {
-                        "recipient_id": "{{JsonUtils.EscapeJsonString(recipientId.ToString())}}"
+                        "recipient_id": "{{JsonUtils.EscapeJsonString(recipientId.Id)}}"
                       },
                       "message_data": {
                         "text": "{{JsonUtils.EscapeJsonString(text)}}"{{attachment}}
@@ -694,14 +694,14 @@ namespace OpenTween.Api
                 .ConfigureAwait(false);
         }
 
-        public async Task<TwitterUser[]> UsersLookup(IReadOnlyList<string> userIds)
+        public async Task<TwitterUser[]> UsersLookup(IReadOnlyList<TwitterUserId> userIds)
         {
             var request = new GetRequest
             {
                 RequestUri = new("users/lookup.json", UriKind.Relative),
                 Query = new Dictionary<string, string>
                 {
-                    ["user_id"] = string.Join(",", userIds),
+                    ["user_id"] = string.Join(",", userIds.Select(x => x.Id)),
                     ["include_entities"] = "true",
                     ["include_ext_alt_text"] = "true",
                     ["tweet_mode"] = "extended",
@@ -854,7 +854,7 @@ namespace OpenTween.Api
             return response.ReadAsLazyJson<TwitterFriendship>();
         }
 
-        public async Task<long[]> NoRetweetIds()
+        public async Task<TwitterUserId[]> NoRetweetIds()
         {
             var request = new GetRequest
             {
@@ -865,8 +865,10 @@ namespace OpenTween.Api
             using var response = await this.Connection.SendAsync(request)
                 .ConfigureAwait(false);
 
-            return await response.ReadAsJson<long[]>()
+            var idsStr = await response.ReadAsJson<string[]>()
                 .ConfigureAwait(false);
+
+            return idsStr.Select(x => new TwitterUserId(x)).ToArray();
         }
 
         public async Task<TwitterIds> FollowersIds(long? cursor = null)
index aecd38f..9f0939a 100644 (file)
@@ -191,7 +191,7 @@ namespace OpenTween
                         using var apiConnection = new TwitterApiConnection(new TwitterCredentialCookie(appToken), new());
                         twitterApi.Initialize(apiConnection);
                         var twitterUser = await twitterApi.AccountVerifyCredentials();
-                        newAccount.UserId = twitterUser.Id;
+                        newAccount.UserId = twitterUser.IdStr;
                         newAccount.Username = twitterUser.ScreenName;
                     }
                     else
@@ -280,7 +280,7 @@ namespace OpenTween
                 TwitterOAuth1ConsumerKey = appToken.OAuth1CustomConsumerKey?.Value ?? "",
                 TwitterOAuth1ConsumerSecret = appToken.OAuth1CustomConsumerSecret?.Value ?? "",
                 Username = accessTokenResponse["screen_name"],
-                UserId = long.Parse(accessTokenResponse["user_id"]),
+                UserId = accessTokenResponse["user_id"],
                 Token = accessTokenResponse["oauth_token"],
                 TokenSecret = accessTokenResponse["oauth_token_secret"],
             };
index 71bfe42..5344e27 100644 (file)
@@ -30,6 +30,7 @@ using System.Collections.Generic;
 using System.Threading.Tasks;
 using System.Xml.Serialization;
 using OpenTween.Api.DataModel;
+using OpenTween.Models;
 
 namespace OpenTween
 {
@@ -42,7 +43,7 @@ namespace OpenTween
         public bool IsPublic = true;
         public int SubscriberCount = 0;   // 購読者数
         public int MemberCount = 0;   // リストメンバ数
-        public long UserId = 0;
+        public PersonId UserId = null!;
         public string Username = "";
         public string Nickname = "";
 
@@ -68,7 +69,7 @@ namespace OpenTween
             this.Slug = listElementData.Slug;
             this.Nickname = listElementData.User.Name.Trim();
             this.Username = listElementData.User.ScreenName;
-            this.UserId = listElementData.User.Id;
+            this.UserId = new TwitterUserId(listElementData.User.IdStr);
 
             this.tw = tw;
         }
diff --git a/OpenTween/Models/PersonId.cs b/OpenTween/Models/PersonId.cs
new file mode 100644 (file)
index 0000000..efc511e
--- /dev/null
@@ -0,0 +1,82 @@
+// 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.Collections.Generic;
+using System.Diagnostics;
+
+namespace OpenTween.Models
+{
+    [DebuggerDisplay("{IdType}:{Id}")]
+    public abstract class PersonId
+        : IEquatable<PersonId>, IComparable<PersonId>
+    {
+        public abstract string IdType { get; }
+
+        public abstract string Id { get; }
+
+        public virtual int CompareTo(PersonId other)
+        {
+            var compareByIdType = this.IdType.CompareTo(other.IdType);
+            if (compareByIdType != 0)
+                return compareByIdType;
+
+            // 辞書順による比較のみだと "20" > "100" となってしまうため文字数による比較も加える
+            var compareByIdLength = this.Id.Length.CompareTo(other.Id.Length);
+            if (compareByIdLength != 0)
+                return compareByIdLength;
+
+            return this.Id.CompareTo(other.Id);
+        }
+
+        public virtual bool Equals(PersonId other)
+            => this.IdType == other.IdType && this.Id == other.Id;
+
+        public override bool Equals(object obj)
+            => obj is PersonId otherId && this.Equals(otherId);
+
+        public override int GetHashCode()
+            => this.IdType.GetHashCode() ^ this.Id.GetHashCode();
+
+        public override string ToString()
+            => this.Id;
+
+        public static bool operator ==(PersonId? left, PersonId? right)
+            => EqualityComparer<PersonId?>.Default.Equals(left, right);
+
+        public static bool operator !=(PersonId? left, PersonId? right)
+            => !EqualityComparer<PersonId?>.Default.Equals(left, right);
+
+        public static bool operator <(PersonId left, PersonId right)
+            => Comparer<PersonId>.Default.Compare(left, right) < 0;
+
+        public static bool operator <=(PersonId left, PersonId right)
+            => Comparer<PersonId>.Default.Compare(left, right) <= 0;
+
+        public static bool operator >=(PersonId left, PersonId right)
+            => Comparer<PersonId>.Default.Compare(left, right) >= 0;
+
+        public static bool operator >(PersonId left, PersonId right)
+            => Comparer<PersonId>.Default.Compare(left, right) > 0;
+    }
+}
index b1791c8..df607fd 100644 (file)
@@ -93,21 +93,21 @@ namespace OpenTween.Models
 
         public Uri? SourceUri { get; init; }
 
-        public List<(long UserId, string ScreenName)> ReplyToList { get; init; } = new();
+        public List<(PersonId UserId, string ScreenName)> ReplyToList { get; init; } = new();
 
         public bool IsMe { get; init; }
 
         public bool IsDm { get; init; }
 
-        public long UserId { get; init; }
+        public PersonId UserId { get; init; } = null!;
 
         public string? RetweetedBy { get; init; }
 
         public PostId? RetweetedId { get; init; }
 
-        public long? RetweetedByUserId { get; init; }
+        public PersonId? RetweetedByUserId { get; init; }
 
-        public long? InReplyToUserId { get; init; }
+        public PersonId? InReplyToUserId { get; init; }
 
         public List<MediaInfo> Media { get; init; } = new();
 
@@ -203,7 +203,7 @@ namespace OpenTween.Models
         /// </summary>
         /// <param name="selfUserId">ツイートを削除しようとするユーザーのID</param>
         /// <returns>削除可能であれば true、そうでなければ false</returns>
-        public bool CanDeleteBy(long selfUserId)
+        public bool CanDeleteBy(PersonId selfUserId)
         {
             // 自分が送った DM と自分に届いた DM のどちらも削除可能
             if (this.IsDm)
@@ -225,7 +225,7 @@ namespace OpenTween.Models
         /// </summary>
         /// <param name="selfUserId">リツイートしようとするユーザーのID</param>
         /// <returns>リツイート可能であれば true、そうでなければ false</returns>
-        public bool CanRetweetBy(long selfUserId)
+        public bool CanRetweetBy(PersonId selfUserId)
         {
             // DM は常にリツイート不可
             if (this.IsDm)
index 2e8da9d..28619c3 100644 (file)
@@ -54,9 +54,9 @@ namespace OpenTween.Models
 
         public Stack<TabModel> RemovedTab { get; } = new();
 
-        public ISet<long> BlockIds { get; set; } = new HashSet<long>();
+        public ISet<PersonId> BlockIds { get; set; } = new HashSet<PersonId>();
 
-        public ISet<long> MuteUserIds { get; set; } = new HashSet<long>();
+        public ISet<PersonId> MuteUserIds { get; set; } = new HashSet<PersonId>();
 
         // 発言の追加
         // AddPost(複数回) -> DistributePosts          -> SubmitUpdate
@@ -260,7 +260,7 @@ namespace OpenTween.Models
                 MyCommon.TabUsageType.UserTimeline
                     => new UserTimelineTabModel(tabName, tabSetting.User!)
                     {
-                        UserId = tabSetting.UserId,
+                        UserId = tabSetting.UserId is { } userId ? new TwitterUserId(userId) : null,
                     },
                 MyCommon.TabUsageType.PublicSearch
                     => new PublicSearchTabModel(tabName)
@@ -643,7 +643,7 @@ namespace OpenTween.Models
             if (this.MuteUserIds.Contains(post.UserId))
                 return true;
 
-            if (post.RetweetedByUserId != null && this.MuteUserIds.Contains(post.RetweetedByUserId.Value))
+            if (post.RetweetedByUserId != null && this.MuteUserIds.Contains(post.RetweetedByUserId))
                 return true;
 
             return false;
@@ -890,7 +890,7 @@ namespace OpenTween.Models
             }
         }
 
-        public void RefreshOwl(ISet<long> follower)
+        public void RefreshOwl(ISet<PersonId> follower)
         {
             lock (this.lockObj)
             {
index 5a4efce..a15d3eb 100644 (file)
@@ -58,13 +58,14 @@ namespace OpenTween.Models
 
         public PostClass CreateFromStatus(
             TwitterStatus status,
-            long selfUserId,
-            ISet<long> followerIds,
+            TwitterUserId selfUserId,
+            ISet<PersonId> followerIds,
             bool firstLoad,
             bool favTweet = false
         )
         {
             var statusUser = status.User ?? TwitterUser.CreateUnknownUser();
+            var statusUserId = new TwitterUserId(statusUser.IdStr);
 
             // リツイートでない場合は null
             var retweetedStatus = (TwitterStatus?)null;
@@ -80,8 +81,9 @@ namespace OpenTween.Models
             // リツイートであるか否かに関わらず常にオリジナルのツイート及びユーザーを指す
             var originalStatus = retweetedStatus ?? status;
             var originalStatusUser = originalStatus.User ?? TwitterUser.CreateUnknownUser();
+            var originalStatusUserId = new TwitterUserId(originalStatusUser.IdStr);
 
-            var isMe = statusUser.Id == selfUserId;
+            var isMe = statusUserId == selfUserId;
 
             bool isFav = favTweet;
             if (isFav == false)
@@ -140,7 +142,7 @@ namespace OpenTween.Models
 
             var isOwl = false;
             if (!isMe && followerIds.Count > 0)
-                isOwl = !followerIds.Contains(originalStatusUser.Id);
+                isOwl = !followerIds.Contains(originalStatusUserId);
 
             var createdAtForSorting = ParseDateTimeFromSnowflakeId(status.Id, status.CreatedAt);
             var createdAt = retweetedStatus != null
@@ -179,10 +181,10 @@ namespace OpenTween.Models
                 IsReply = retweetedStatus == null && replyToList.Any(x => x.UserId == selfUserId),
                 InReplyToStatusId = originalStatus.InReplyToStatusIdStr != null ? new TwitterStatusId(originalStatus.InReplyToStatusIdStr) : null,
                 InReplyToUser = originalStatus.InReplyToScreenName,
-                InReplyToUserId = originalStatus.InReplyToUserId,
+                InReplyToUserId = originalStatus.InReplyToUserIdStr is { } inReplyToUserId ? new TwitterUserId(inReplyToUserId) : null,
 
                 // originalStatusUser から生成
-                UserId = originalStatusUser.Id,
+                UserId = originalStatusUserId,
                 ScreenName = screenName,
                 Nickname = nickname,
                 ImageUrl = imageUrl,
@@ -194,7 +196,7 @@ namespace OpenTween.Models
 
                 // retweeterUser から生成
                 RetweetedBy = retweeterUser != null ? string.Intern(retweeterUser.ScreenName) : null,
-                RetweetedByUserId = retweeterUser?.Id,
+                RetweetedByUserId = retweeterUser?.IdStr is { } retweetedByUserId ? new TwitterUserId(retweetedByUserId) : null,
 
                 IsRead = this.DetermineUnreadState(isMe, firstLoad),
             };
@@ -202,9 +204,9 @@ namespace OpenTween.Models
 
         public PostClass CreateFromDirectMessageEvent(
             TwitterMessageEvent eventItem,
-            IReadOnlyDictionary<string, TwitterUser> users,
+            IReadOnlyDictionary<TwitterUserId, TwitterUser> users,
             IReadOnlyDictionary<string, TwitterMessageEventList.App> apps,
-            long selfUserId,
+            TwitterUserId selfUserId,
             bool firstLoad
         )
         {
@@ -242,10 +244,11 @@ namespace OpenTween.Models
                 .ToArray();
 
             // 以下、ユーザー情報
-            var senderIsMe = eventItem.MessageCreate.SenderId == selfUserId.ToString(CultureInfo.InvariantCulture);
+            var senderId = new TwitterUserId(eventItem.MessageCreate.SenderId);
+            var senderIsMe = senderId == selfUserId;
             var displayUserId = senderIsMe
-                ? eventItem.MessageCreate.Target.RecipientId
-                : eventItem.MessageCreate.SenderId;
+                ? new TwitterUserId(eventItem.MessageCreate.Target.RecipientId)
+                : senderId;
 
             if (!users.TryGetValue(displayUserId, out var displayUser))
                 displayUser = TwitterUser.CreateUnknownUser();
@@ -293,7 +296,7 @@ namespace OpenTween.Models
                 SourceUri = sourceUri,
 
                 // displayUser から生成
-                UserId = displayUser.Id,
+                UserId = new TwitterUserId(displayUser.IdStr),
                 ScreenName = screenName,
                 Nickname = nickname,
                 ImageUrl = imageUrl,
@@ -342,9 +345,9 @@ namespace OpenTween.Models
             return text;
         }
 
-        private (List<(long UserId, string ScreenName)> ReplyToList, List<MediaInfo> Media) ExtractEntities(TwitterEntities? entities)
+        private (List<(PersonId UserId, string ScreenName)> ReplyToList, List<MediaInfo> Media) ExtractEntities(TwitterEntities? entities)
         {
-            var atList = new List<(long UserId, string ScreenName)>();
+            var atList = new List<(PersonId UserId, string ScreenName)>();
             var media = new List<MediaInfo>();
 
             if (entities == null)
@@ -361,7 +364,7 @@ namespace OpenTween.Models
             if (entities.UserMentions != null)
             {
                 foreach (var ent in entities.UserMentions)
-                    atList.Add((ent.Id, ent.ScreenName));
+                    atList.Add((new TwitterUserId(ent.IdStr), ent.ScreenName));
             }
 
             if (entities.Media != null)
diff --git a/OpenTween/Models/TwitterUserId.cs b/OpenTween/Models/TwitterUserId.cs
new file mode 100644 (file)
index 0000000..e57fc93
--- /dev/null
@@ -0,0 +1,38 @@
+// 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
+
+namespace OpenTween.Models
+{
+    public class TwitterUserId : PersonId
+    {
+        public override string IdType => "twitter_user";
+
+        public override string Id { get; }
+
+        public TwitterUserId(string id)
+            => this.Id = id;
+
+        public TwitterUserId(long id)
+            => this.Id = id.ToString();
+    }
+}
index 0c13c61..e935b91 100644 (file)
@@ -45,7 +45,7 @@ namespace OpenTween.Models
 
         public string ScreenName { get; }
 
-        public string? UserId { get; set; }
+        public PersonId? UserId { get; set; }
 
         public UserTimelineTabModel(string tabName, string screenName)
             : base(tabName)
index d7af5bc..75c7d0f 100644 (file)
@@ -41,7 +41,7 @@ namespace OpenTween
 
         public bool AutoPopulateReplyMetadata { get; set; }
 
-        public IReadOnlyList<long> ExcludeReplyUserIds { get; set; } = Array.Empty<long>();
+        public IReadOnlyList<PersonId> ExcludeReplyUserIds { get; set; } = Array.Empty<PersonId>();
 
         public string? AttachmentUrl { get; set; }
     }
index b4b76c1..7b9370a 100644 (file)
@@ -102,7 +102,7 @@ namespace OpenTween.Setting.Panel
             }
             else
             {
-                settingCommon.UserId = 0;
+                settingCommon.UserId = "";
                 settingCommon.UserName = "";
                 settingCommon.Token = "";
                 settingCommon.TokenSecret = "";
index dbc4a94..ecd534b 100644 (file)
@@ -112,7 +112,7 @@ namespace OpenTween
             return password;
         }
 
-        public long UserId = 0;
+        public string UserId = "";
         public List<string> TabList = new();
         public int TimelinePeriod = 180;
         public int ReplyPeriod = 180;
@@ -339,7 +339,7 @@ namespace OpenTween
 
             this.SelectedAccountKey = selectedAccount?.UniqueKey;
 
-            if (selectedAccount?.UserId == 0)
+            if (selectedAccount != null && MyCommon.IsNullOrEmpty(selectedAccount.UserId))
                 selectedAccount.UserId = this.UserId;
 
             if (MyCommon.IsNullOrEmpty(this.Token))
@@ -352,7 +352,7 @@ namespace OpenTween
         public Guid UniqueKey { get; set; } = Guid.NewGuid();
 
         public string Username = "";
-        public long UserId = 0;
+        public string UserId = "";
 
         public APIAuthType TwitterAuthType { get; set; } = APIAuthType.OAuth1;
 
index 7c92acd..68dd539 100644 (file)
@@ -23,6 +23,7 @@
 
 using System;
 using OpenTween.Connection;
+using OpenTween.Models;
 
 namespace OpenTween.SocialProtocol
 {
@@ -32,7 +33,7 @@ namespace OpenTween.SocialProtocol
 
         public Guid UniqueKey { get; }
 
-        public long UserId { get; }
+        public PersonId UserId { get; }
 
         public string UserName { get; }
 
index 12731d8..bd0c535 100644 (file)
@@ -24,6 +24,7 @@
 using System;
 using System.Diagnostics;
 using OpenTween.Connection;
+using OpenTween.Models;
 
 namespace OpenTween.SocialProtocol.Twitter
 {
@@ -46,7 +47,7 @@ namespace OpenTween.SocialProtocol.Twitter
         public OpenTween.Twitter Legacy
             => this.twLegacy;
 
-        public long UserId
+        public PersonId UserId
             => this.AccountState.UserId;
 
         public string UserName
@@ -69,8 +70,9 @@ namespace OpenTween.SocialProtocol.Twitter
             Debug.Assert(accountSettings.UniqueKey == this.UniqueKey, "UniqueKey must be same as current value.");
 
             var credential = accountSettings.GetTwitterCredential();
+            var userId = new TwitterUserId(accountSettings.UserId);
 
-            this.AccountState = new TwitterAccountState(accountSettings.UserId, accountSettings.Username)
+            this.AccountState = new TwitterAccountState(userId, accountSettings.Username)
             {
                 HasUnrecoverableError = credential is TwitterCredentialNone,
             };
index 95dd391..3e61027 100644 (file)
 
 using System.Collections.Generic;
 using OpenTween.Api.DataModel;
+using OpenTween.Models;
 
 namespace OpenTween.SocialProtocol.Twitter
 {
     public class TwitterAccountState
     {
-        public long UserId { get; private set; }
+        public TwitterUserId UserId { get; private set; }
 
         public string UserName { get; private set; }
 
@@ -38,18 +39,18 @@ namespace OpenTween.SocialProtocol.Twitter
 
         public int? StatusesCount { get; private set; }
 
-        public ISet<long> FollowerIds { get; set; } = new HashSet<long>();
+        public ISet<PersonId> FollowerIds { get; set; } = new HashSet<PersonId>();
 
-        public ISet<long> NoRetweetUserIds { get; set; } = new HashSet<long>();
+        public ISet<TwitterUserId> NoRetweetUserIds { get; set; } = new HashSet<TwitterUserId>();
 
         public bool HasUnrecoverableError { get; set; } = true;
 
         public TwitterAccountState()
-            : this(0L, "")
+            : this(new("0"), "")
         {
         }
 
-        public TwitterAccountState(long userId, string userName)
+        public TwitterAccountState(TwitterUserId userId, string userName)
         {
             this.UserId = userId;
             this.UserName = userName;
@@ -58,7 +59,7 @@ namespace OpenTween.SocialProtocol.Twitter
         /// <summary>ユーザー情報を更新します</summary>
         public void UpdateFromUser(TwitterUser self)
         {
-            this.UserId = self.Id;
+            this.UserId = new(self.IdStr);
             this.UserName = self.ScreenName;
             this.FollowersCount = self.FollowersCount;
             this.FriendsCount = self.FriendsCount;
index 6e0b4bf..2603383 100644 (file)
@@ -2491,7 +2491,7 @@ namespace OpenTween
         private async void SettingStripMenuItem_Click(object sender, EventArgs e)
         {
             // 設定画面表示前のユーザー情報
-            var previousUserId = this.settings.Common.UserId;
+            var previousAccountId = this.settings.Common.SelectedAccountKey;
             var oldIconCol = this.Use2ColumnsMode;
 
             if (this.ShowSettingDialog() == DialogResult.OK)
@@ -2683,7 +2683,7 @@ namespace OpenTween
             this.TopMost = this.settings.Common.AlwaysTop;
             this.SaveConfigsAll(false);
 
-            if (this.PrimaryAccount.UserId != previousUserId)
+            if (this.PrimaryAccount.UniqueKey != previousAccountId)
                 await this.DoGetFollowersMenu();
         }
 
@@ -3299,9 +3299,9 @@ namespace OpenTween
         /// <summary>
         /// 投稿時に auto_populate_reply_metadata オプションによって自動で追加されるメンションを除去します
         /// </summary>
-        private string RemoveAutoPopuratedMentions(string statusText, out long[] autoPopulatedUserIds)
+        private string RemoveAutoPopuratedMentions(string statusText, out PersonId[] autoPopulatedUserIds)
         {
-            var autoPopulatedUserIdList = new List<long>();
+            var autoPopulatedUserIdList = new List<PersonId>();
 
             var replyToPost = this.inReplyTo != null ? this.statuses[this.inReplyTo.Value.StatusId] : null;
             if (replyToPost != null)
@@ -3357,7 +3357,7 @@ namespace OpenTween
         /// <summary>
         /// <see cref="FormatStatusText"/> に加えて、拡張モードで140字にカウントされない文字列の除去を行います
         /// </summary>
-        private string FormatStatusTextExtended(string statusText, out long[] autoPopulatedUserIds, out string? attachmentUrl)
+        private string FormatStatusTextExtended(string statusText, out PersonId[] autoPopulatedUserIds, out string? attachmentUrl)
         {
             statusText = this.RemoveAutoPopuratedMentions(statusText, out autoPopulatedUserIds);
 
@@ -5612,7 +5612,7 @@ namespace OpenTween
                         break;
                     case UserTimelineTabModel userTab:
                         tabSetting.User = userTab.ScreenName;
-                        tabSetting.UserId = userTab.UserId;
+                        tabSetting.UserId = userTab.UserId?.Id;
                         break;
                     case PublicSearchTabModel searchTab:
                         tabSetting.SearchWords = searchTab.SearchWords;
index 363f7e5..6ea9628 100644 (file)
@@ -230,7 +230,7 @@ namespace OpenTween
                 {
                     TweetText = param.Text,
                     InReplyToTweetId = param.InReplyToStatusId?.ToTwitterStatusId(),
-                    ExcludeReplyUserIds = param.ExcludeReplyUserIds.Select(x => x.ToString()).ToArray(),
+                    ExcludeReplyUserIds = param.ExcludeReplyUserIds.OfType<TwitterUserId>().ToArray(),
                     MediaIds = param.MediaIds.Select(x => x.ToString()).ToArray(),
                     AttachmentUrl = param.AttachmentUrl,
                 };
@@ -245,7 +245,7 @@ namespace OpenTween
                         param.InReplyToStatusId?.ToTwitterStatusId(),
                         param.MediaIds,
                         param.AutoPopulateReplyMetadata,
-                        param.ExcludeReplyUserIds,
+                        param.ExcludeReplyUserIds.OfType<TwitterUserId>().ToArray(),
                         param.AttachmentUrl
                     )
                     .ConfigureAwait(false);
@@ -337,7 +337,8 @@ namespace OpenTween
             var recipient = await this.GetUserInfo(recipientName)
                 .ConfigureAwait(false);
 
-            using var response = await this.Api.DirectMessagesEventsNew(recipient.Id, body, mediaId)
+            var recipientUserId = new TwitterUserId(recipient.IdStr);
+            using var response = await this.Api.DirectMessagesEventsNew(recipientUserId, body, mediaId)
                 .ConfigureAwait(false);
 
             var messageEventSingle = await response.LoadJsonAsync()
@@ -375,7 +376,7 @@ namespace OpenTween
         public string Username
             => this.AccountState.UserName;
 
-        public long UserId
+        public TwitterUserId UserId
             => this.AccountState.UserId;
 
         public bool RestrictFavCheck { get; set; }
@@ -526,14 +527,14 @@ namespace OpenTween
             TwitterStatus[] statuses;
             if (this.Api.AuthType == APIAuthType.TwitterComCookie)
             {
-                var userId = tab.UserId;
-                if (MyCommon.IsNullOrEmpty(userId))
+                var userId = tab.UserId as TwitterUserId;
+                if (userId == null)
                 {
                     var user = await this.GetUserInfo(tab.ScreenName)
                         .ConfigureAwait(false);
 
-                    userId = user.IdStr;
-                    tab.UserId = user.IdStr;
+                    userId = new TwitterUserId(user.IdStr);
+                    tab.UserId = userId;
                 }
 
                 var cursor = more ? tab.CursorBottom : tab.CursorTop;
@@ -546,7 +547,7 @@ namespace OpenTween
                     .ConfigureAwait(false);
 
                 statuses = response.ToTwitterStatuses()
-                    .Where(x => x.User.IdStr == userId) // リプライツリーに含まれる他ユーザーのツイートを除外
+                    .Where(x => x.User.IdStr == userId.Id) // リプライツリーに含まれる他ユーザーのツイートを除外
                     .ToArray();
 
                 tab.CursorBottom = response.CursorBottom;
@@ -595,7 +596,7 @@ namespace OpenTween
         }
 
         internal PostClass[] FilterNoRetweetUserPosts(PostClass[] posts)
-            => posts.Where(x => x.RetweetedByUserId == null || !this.AccountState.NoRetweetUserIds.Contains(x.RetweetedByUserId.Value)).ToArray();
+            => posts.Where(x => x.RetweetedByUserId == null || !this.AccountState.NoRetweetUserIds.Contains(x.RetweetedByUserId)).ToArray();
 
         public async Task GetListStatus(ListTimelineTabModel tab, bool more, bool firstLoad)
         {
@@ -697,12 +698,12 @@ namespace OpenTween
                 return Array.Empty<PostClass>();
 
             var userIds = Enumerable.Concat(
-                events.Select(x => x.MessageCreate.SenderId),
-                events.Select(x => x.MessageCreate.Target.RecipientId)
+                events.Select(x => new TwitterUserId(x.MessageCreate.SenderId)),
+                events.Select(x => new TwitterUserId(x.MessageCreate.Target.RecipientId))
             ).Distinct().ToArray();
 
             var users = (await this.Api.UsersLookup(userIds).ConfigureAwait(false))
-                .ToDictionary(x => x.IdStr);
+                .ToDictionary(x => new TwitterUserId(x.IdStr));
 
             var apps = eventList.Apps ?? new Dictionary<string, TwitterMessageEventList.App>();
 
@@ -711,7 +712,7 @@ namespace OpenTween
 
         private PostClass[] CreateDirectMessagesEventFromJson(
             IReadOnlyCollection<TwitterMessageEvent> events,
-            IReadOnlyDictionary<string, TwitterUser> users,
+            IReadOnlyDictionary<TwitterUserId, TwitterUser> users,
             IReadOnlyDictionary<string, TwitterMessageEventList.App> apps,
             bool firstLoad)
         {
@@ -741,7 +742,7 @@ namespace OpenTween
                 var cursor = backward ? tab.CursorBottom : tab.CursorTop;
                 var request = new LikesRequest
                 {
-                    UserId = this.UserId.ToString(CultureInfo.InvariantCulture),
+                    UserId = this.UserId,
                     Count = count,
                     Cursor = cursor?.As<TwitterGraphqlCursor>(),
                 };
@@ -785,7 +786,7 @@ namespace OpenTween
             if (MyCommon.EndingFlag) return;
 
             var cursor = -1L;
-            var newFollowerIds = Enumerable.Empty<long>();
+            var newFollowerIds = Enumerable.Empty<PersonId>();
             do
             {
                 var ret = await this.Api.FollowersIds(cursor)
@@ -794,7 +795,7 @@ namespace OpenTween
                 if (ret.Ids == null)
                     throw new WebApiException("ret.ids == null");
 
-                newFollowerIds = newFollowerIds.Concat(ret.Ids);
+                newFollowerIds = newFollowerIds.Concat(ret.Ids.Select(x => new TwitterUserId(x)));
                 cursor = ret.NextCursor;
             }
             while (cursor != 0);
@@ -816,7 +817,7 @@ namespace OpenTween
             var noRetweetUserIds = await this.Api.NoRetweetIds()
                 .ConfigureAwait(false);
 
-            this.AccountState.NoRetweetUserIds = new HashSet<long>(noRetweetUserIds);
+            this.AccountState.NoRetweetUserIds = new HashSet<TwitterUserId>(noRetweetUserIds);
             this.GetNoRetweetSuccess = true;
         }
 
@@ -941,13 +942,13 @@ namespace OpenTween
             if (MyCommon.EndingFlag) return;
 
             var cursor = -1L;
-            var newBlockIds = Enumerable.Empty<long>();
+            var newBlockIds = Enumerable.Empty<PersonId>();
             do
             {
                 var ret = await this.Api.BlocksIds(cursor)
                     .ConfigureAwait(false);
 
-                newBlockIds = newBlockIds.Concat(ret.Ids);
+                newBlockIds = newBlockIds.Concat(ret.Ids.Select(x => new TwitterUserId(x)));
                 cursor = ret.NextCursor;
             }
             while (cursor != 0);
@@ -969,7 +970,7 @@ namespace OpenTween
             var ids = await TwitterIds.GetAllItemsAsync(x => this.Api.MutesUsersIds(x))
                 .ConfigureAwait(false);
 
-            TabInformations.GetInstance().MuteUserIds = ids.ToHashSet();
+            TabInformations.GetInstance().MuteUserIds = ids.ToHashSet<PersonId>();
         }
 
         public string[] GetHashList()
index ff27d2a..d07eff9 100644 (file)
@@ -138,7 +138,8 @@ namespace OpenTween
             this.LinkLabelTweet.Tag = profileUrl;
             this.ToolTip1.SetToolTip(this.LinkLabelTweet, profileUrl);
 
-            if (this.twitter.UserId == user.Id)
+            var userId = new TwitterUserId(user.IdStr);
+            if (this.twitter.UserId == userId)
             {
                 this.ButtonEdit.Enabled = true;
                 this.ChangeIconToolStripMenuItem.Enabled = true;
@@ -483,8 +484,9 @@ namespace OpenTween
 
         private async void ButtonEdit_Click(object sender, EventArgs e)
         {
+            var displayUserId = new TwitterUserId(this.displayUser.IdStr);
             // 自分以外のプロフィールは変更できない
-            if (this.twitter.UserId != this.displayUser.Id)
+            if (this.twitter.UserId != displayUserId)
                 return;
 
             using (ControlTransaction.Disabled(this.ButtonEdit))