toolStrip.GaugeHeight = 5;
MyCommon.TwitterApiInfo.AccessLimit["/statuses/user_timeline"] = new ApiLimit(
- limitCount: 1_000_000_000,
- limitRemain: 999_999_999,
- resetDate: now + TimeSpan.FromMinutes(15)
+ AccessLimitCount: 1_000_000_000,
+ AccessLimitRemain: 999_999_999,
+ AccessLimitResetDate: now + TimeSpan.FromMinutes(15)
);
toolStrip.ApiEndpoint = "/statuses/user_timeline";
namespace OpenTween.Api
{
- public class ApiLimit
- {
- public ApiLimit(int limitCount, int limitRemain, DateTimeUtc resetDate)
- : this(limitCount, limitRemain, resetDate, DateTimeUtc.Now)
- {
- }
-
- public ApiLimit(int limitCount, int limitRemain, DateTimeUtc resetDate, DateTimeUtc updatedAt)
- {
- this.AccessLimitCount = limitCount;
- this.AccessLimitRemain = limitRemain;
- this.AccessLimitResetDate = resetDate;
- this.UpdatedAt = updatedAt;
- }
-
- /// <summary>
- /// API 実行回数制限の値
- /// </summary>
- public int AccessLimitCount { get; }
-
- /// <summary>
- /// API 実行回数制限までの残回数
- /// </summary>
- public int AccessLimitRemain { get; }
-
- /// <summary>
- /// API 実行回数制限がリセットされる日時
- /// </summary>
- public DateTimeUtc AccessLimitResetDate { get; }
-
- /// <summary>
- /// API 実行回数制限値を取得した日時
- /// </summary>
- public DateTimeUtc UpdatedAt { get; }
-
- public override bool Equals(object? obj)
- => this.Equals(obj as ApiLimit);
-
- public bool Equals(ApiLimit? obj)
- => obj != null && this.AccessLimitCount == obj.AccessLimitCount &&
- this.AccessLimitRemain == obj.AccessLimitRemain && this.AccessLimitResetDate == obj.AccessLimitResetDate;
-
- public override int GetHashCode()
- => this.AccessLimitCount ^ this.AccessLimitRemain ^ this.AccessLimitResetDate.GetHashCode();
- }
+ /// <param name="AccessLimitCount">API 実行回数制限の値</param>
+ /// <param name="AccessLimitRemain">API 実行回数制限までの残回数</param>
+ /// <param name="AccessLimitResetDate">API 実行回数制限がリセットされる日時</param>
+ public record ApiLimit(
+ int AccessLimitCount,
+ int AccessLimitRemain,
+ DateTimeUtc AccessLimitResetDate
+ );
}
{
private readonly Form targetForm;
- private class KeyEventValue
- {
- public KeyEventArgs KeyEvent { get; }
-
- public int Value { get; }
-
- public KeyEventValue(KeyEventArgs keyEvent, int value)
- {
- this.KeyEvent = keyEvent;
- this.Value = value;
- }
- }
+ private readonly record struct KeyEventValue(
+ KeyEventArgs KeyEvent,
+ int Value
+ );
private readonly Dictionary<int, KeyEventValue> hotkeyID;
--- /dev/null
+// OpenTween - Client of Twitter
+// Copyright (c) 2022 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 System.Runtime.CompilerServices
+{
+ internal sealed class IsExternalInit
+ {
+ }
+}
{
public class PostClass : ICloneable
{
- public readonly struct StatusGeo : IEquatable<StatusGeo>
- {
- public double Longitude { get; }
-
- public double Latitude { get; }
-
- public StatusGeo(double longitude, double latitude)
- {
- this.Longitude = longitude;
- this.Latitude = latitude;
- }
-
- public override int GetHashCode()
- => this.Longitude.GetHashCode() ^ this.Latitude.GetHashCode();
-
- public override bool Equals(object obj)
- => obj is StatusGeo geo && this.Equals(geo);
-
- public bool Equals(StatusGeo other)
- => this.Longitude == other.Longitude && this.Latitude == other.Longitude;
-
- public static bool operator ==(StatusGeo left, StatusGeo right)
- => left.Equals(right);
-
- public static bool operator !=(StatusGeo left, StatusGeo right)
- => !left.Equals(right);
- }
+ public readonly record struct StatusGeo(
+ double Longitude,
+ double Latitude
+ );
public string Nickname { get; set; } = "";
public abstract Task RefreshAsync(Twitter tw, bool backward, bool startup, IProgress<string> progress);
- private readonly struct TemporaryId
- {
- public long StatusId { get; }
-
- public bool Read { get; }
-
- public TemporaryId(long statusId, bool read)
- {
- this.StatusId = statusId;
- this.Read = read;
- }
- }
+ private readonly record struct TemporaryId(
+ long StatusId,
+ bool Read
+ );
public virtual void AddPostQueue(PostClass post)
{
return false;
}
- internal class MouseEvent
- {
- public Point ScreenLocation { get; }
-
- public int WheelDelta { get; }
-
- public MouseEvent(Point location, int delta)
- {
- this.ScreenLocation = location;
- this.WheelDelta = delta;
- }
- }
+ internal readonly record struct MouseEvent(
+ Point ScreenLocation,
+ int WheelDelta
+ );
internal static MouseEvent ParseMessage(Message m)
{
<Compile Include="Bing.cs" />
<Compile Include="Connection\IApiConnection.cs" />
<Compile Include="DebounceTimer.cs" />
+ <Compile Include="IsExternalInit.cs" />
<Compile Include="MediaUploadServices\IMediaUploadService.cs" />
<Compile Include="MediaUploadServices\Imgur.cs" />
<Compile Include="Connection\LazyJson.cs" />
}
}
- public class OpenUrlItem
+ public readonly record struct OpenUrlItem(
+ string LinkText,
+ string Url,
+ string Href
+ )
{
- private readonly string linkText;
-
- public OpenUrlItem(string linkText, string url, string href)
- {
- this.linkText = linkText;
- this.Url = url;
- this.Href = href;
- }
-
public string Text
{
get
{
- if (this.linkText[0] is '@' or '@' or '#' or '#')
- return this.linkText;
+ if (this.LinkText[0] is '@' or '@' or '#' or '#')
+ return this.LinkText;
- if (this.linkText.TrimEnd('/') == this.Url.TrimEnd('/'))
+ if (this.LinkText.TrimEnd('/') == this.Url.TrimEnd('/'))
return this.Url;
- return this.linkText + " >>> " + this.Url;
+ return this.LinkText + " >>> " + this.Url;
}
}
public override string ToString()
=> this.Href;
-
- public string Url { get; }
-
- public string Href { get; }
}
}
Public,
}
- public class SearchOptions
- {
- public SearchType Type { get; }
-
- public string Query { get; }
-
- // タイムライン内検索のみで使用する
- public bool NewTab { get; }
-
- public bool CaseSensitive { get; }
-
- public bool UseRegex { get; }
-
- public SearchOptions(SearchType type, string query, bool newTab, bool caseSensitive, bool useRegex)
- {
- this.Type = type;
- this.Query = query;
- this.NewTab = newTab;
- this.CaseSensitive = caseSensitive;
- this.UseRegex = useRegex;
- }
- }
+ public record SearchOptions(
+ SearchType Type,
+ string Query,
+ bool NewTab, // タイムライン内検索のみで使用する
+ bool CaseSensitive,
+ bool UseRegex
+ );
private SearchOptions? resultOptions = null;
}
}
- protected internal class TabListItem
+ protected internal record TabListItem(
+ string Label,
+ FilterTabModel? Tab
+ )
{
- public FilterTabModel? Tab { get; set; }
-
- public string Label { get; set; } = "";
-
public override string ToString()
=> this.Label;
}
{
this.TabList.SelectionMode = SelectionMode.One;
- this.TabList.Items.Add(new TabListItem
- {
- Label = Properties.Resources.AddNewTabText1,
- Tab = null,
- });
+ this.TabList.Items.Add(new TabListItem(
+ Label: Properties.Resources.AddNewTabText1,
+ Tab: null
+ ));
}
var tabs = this.tabInfo.Tabs.Append(this.tabInfo.MuteTab);
foreach (var tab in tabs.OfType<FilterTabModel>())
{
- this.TabList.Items.Add(new TabListItem
- {
- Label = tab.TabName,
- Tab = tab,
- });
+ this.TabList.Items.Add(new TabListItem(
+ Label: tab.TabName,
+ Tab: tab
+ ));
}
}
}
}
- public class GlobalLocation
- {
- public double Latitude { get; set; }
-
- public double Longitude { get; set; }
- }
+ public record GlobalLocation(
+ double Latitude,
+ double Longitude
+ );
public enum MapProvider
{
if (planetElm != null && planetElm.Value != "earth")
return null;
- return new GlobalLocation
- {
- Latitude = double.Parse(locationElm.Element("lat").Value, CultureInfo.InvariantCulture),
- Longitude = double.Parse(locationElm.Element("lng").Value, CultureInfo.InvariantCulture),
- };
+ return new GlobalLocation(
+ Latitude: double.Parse(locationElm.Element("lat").Value, CultureInfo.InvariantCulture),
+ Longitude: double.Parse(locationElm.Element("lng").Value, CultureInfo.InvariantCulture)
+ );
}
}
}
Highest = 256,
}
- public class LogEntry
+ public readonly record struct LogEntry(
+ LogLevel LogLevel,
+ DateTimeUtc Timestamp,
+ string Summary,
+ string Detail
+ )
{
- public LogLevel LogLevel { get; }
-
- public DateTimeUtc Timestamp { get; }
-
- public string Summary { get; }
-
- public string Detail { get; }
-
- public LogEntry(LogLevel logLevel, DateTimeUtc timestamp, string summary, string detail)
- {
- this.LogLevel = logLevel;
- this.Timestamp = timestamp;
- this.Summary = summary;
- this.Detail = detail;
- }
-
public LogEntry(DateTimeUtc timestamp, string summary)
: this(LogLevel.Debug, timestamp, summary, summary)
{
/// </remarks>
private ListViewItemCache? listItemCache = null;
- internal class ListViewItemCache
+ /// <param name="TargetList">アイテムをキャッシュする対象の <see cref="ListView"/></param>
+ /// <param name="StartIndex">キャッシュする範囲の開始インデックス</param>
+ /// <param name="EndIndex">キャッシュする範囲の終了インデックス</param>
+ /// <param name="Cache">ャッシュされた範囲に対応する <see cref="ListViewItem"/> と <see cref="PostClass"/> の組</param>
+ internal record class ListViewItemCache(
+ ListView TargetList,
+ int StartIndex,
+ int EndIndex,
+ (ListViewItem, PostClass)[] Cache
+ )
{
- /// <summary>アイテムをキャッシュする対象の <see cref="ListView"/></summary>
- public ListView TargetList { get; set; } = null!;
-
- /// <summary>キャッシュする範囲の開始インデックス</summary>
- public int StartIndex { get; set; }
-
- /// <summary>キャッシュする範囲の終了インデックス</summary>
- public int EndIndex { get; set; }
-
- /// <summary>キャッシュされた範囲に対応する <see cref="ListViewItem"/> と <see cref="PostClass"/> の組</summary>
- public (ListViewItem, PostClass)[] Cache { get; set; } = null!;
-
/// <summary>キャッシュされたアイテムの件数</summary>
public int Count
=> this.EndIndex - this.StartIndex + 1;
private bool preventSmsCommand = true;
// URL短縮のUndo用
- private struct UrlUndo
- {
- public string Before;
- public string After;
- }
+ private readonly record struct UrlUndo(
+ string Before,
+ string After
+ );
private List<UrlUndo>? urlUndoBuffer = null;
- private readonly struct ReplyChain
- {
- public readonly long OriginalId;
- public readonly long InReplyToId;
- public readonly TabModel OriginalTab;
-
- public ReplyChain(long originalId, long inReplyToId, TabModel originalTab)
- {
- this.OriginalId = originalId;
- this.InReplyToId = inReplyToId;
- this.OriginalTab = originalTab;
- }
- }
+ private readonly record struct ReplyChain(
+ long OriginalId,
+ long InReplyToId,
+ TabModel OriginalTab
+ );
/// <summary>[, ]でのリプライ移動の履歴</summary>
private Stack<ReplyChain>? replyChains;
PrevSearch,
}
- private class StatusTextHistory
- {
- public string Status { get; } = "";
-
- public (long StatusId, string ScreenName)? InReplyTo { get; } = null;
-
- /// <summary>画像投稿サービス名</summary>
- public string ImageService { get; set; } = "";
-
- public IMediaItem[]? MediaItems { get; set; } = null;
-
- public StatusTextHistory()
- {
- }
-
- public StatusTextHistory(string status, (long StatusId, string ScreenName)? inReplyTo)
- {
- this.Status = status;
- this.InReplyTo = inReplyTo;
- }
- }
+ private readonly record struct StatusTextHistory(
+ string Status,
+ (long StatusId, string ScreenName)? InReplyTo = null
+ );
private void TweenMain_Activated(object sender, EventArgs e)
{
this.recommendedStatusFooter = " [TWNv" + Regex.Replace(MyCommon.FileVersion.Replace(".", ""), "^0*", "") + "]";
- this.history.Add(new StatusTextHistory());
+ this.history.Add(new StatusTextHistory(""));
this.hisIdx = 0;
this.inReplyTo = null;
this.HashSupl.AddRangeItem(this.tw.GetHashList());
}
- internal struct ListViewScroll
- {
- public ScrollLockMode ScrollLockMode { get; set; }
-
- public long? TopItemStatusId { get; set; }
- }
+ internal readonly record struct ListViewScroll(
+ ScrollLockMode ScrollLockMode,
+ long? TopItemStatusId
+ );
internal enum ScrollLockMode
{
/// </summary>
private ListViewScroll SaveListViewScroll(DetailsListView listView, TabModel tab)
{
- var listScroll = new ListViewScroll
- {
- ScrollLockMode = this.GetScrollLockMode(listView),
- };
+ var lockMode = this.GetScrollLockMode(listView);
+ long? topItemStatusId = null;
- if (listScroll.ScrollLockMode == ScrollLockMode.FixedToItem)
+ if (lockMode == ScrollLockMode.FixedToItem)
{
var topItemIndex = listView.TopItem?.Index ?? -1;
if (topItemIndex != -1 && topItemIndex < tab.AllCount)
- listScroll.TopItemStatusId = tab.GetStatusIdAt(topItemIndex);
+ topItemStatusId = tab.GetStatusIdAt(topItemIndex);
}
- return listScroll;
+ return new ListViewScroll
+ {
+ ScrollLockMode = lockMode,
+ TopItemStatusId = topItemStatusId,
+ };
}
private ScrollLockMode GetScrollLockMode(DetailsListView listView)
}
}
- internal struct ListViewSelection
- {
- public long[]? SelectedStatusIds { get; set; }
-
- public long? SelectionMarkStatusId { get; set; }
-
- public long? FocusedStatusId { get; set; }
- }
+ internal readonly record struct ListViewSelection(
+ long[]? SelectedStatusIds,
+ long? SelectionMarkStatusId,
+ long? FocusedStatusId
+ );
/// <summary>
/// <see cref="ListView"/> の選択状態を <see cref="ListViewSelection"/> として返します
this.inReplyTo = null;
this.StatusText.Text = "";
- this.history.Add(new StatusTextHistory());
+ this.history.Add(new StatusTextHistory(""));
this.hisIdx = this.history.Count - 1;
if (!SettingManager.Common.FocusLockToStatusText)
this.CurrentListView.Focus();
.Select(x => this.CreateItem(tab, posts[x]))
.ToArray();
- var listCache = new ListViewItemCache
- {
- TargetList = this.CurrentListView,
- StartIndex = startIndex,
- EndIndex = endIndex,
- Cache = Enumerable.Zip(listItems, posts, (x, y) => (x, y)).ToArray(),
- };
+ var listCache = new ListViewItemCache(
+ TargetList: this.CurrentListView,
+ StartIndex: startIndex,
+ EndIndex: endIndex,
+ Cache: Enumerable.Zip(listItems, posts, (x, y) => (x, y)).ToArray()
+ );
Interlocked.Exchange(ref this.listItemCache, listCache);
}
}
}
- public class VersionInfo
- {
- public Version Version { get; }
-
- public Uri DownloadUri { get; }
-
- public string ReleaseNote { get; }
-
- public VersionInfo(Version version, Uri downloadUri, string releaseNote)
- => (this.Version, this.DownloadUri, this.ReleaseNote) = (version, downloadUri, releaseNote);
- }
+ public readonly record struct VersionInfo(
+ Version Version,
+ Uri DownloadUri,
+ string ReleaseNote
+ );
/// <summary>
/// OpenTween の最新バージョンの情報を取得します
msgBody = Regex.Replace(msgBody, "(?<!\r)\n", "\r\n"); // LF -> CRLF
- return new VersionInfo(
- version: Version.Parse(msgHeader[0]),
- downloadUri: new Uri(msgHeader[1]),
- releaseNote: msgBody
- );
+ return new VersionInfo
+ {
+ Version = Version.Parse(msgHeader[0]),
+ DownloadUri = new Uri(msgHeader[1]),
+ ReleaseNote = msgBody,
+ };
}
private async Task CheckNewVersion(bool startup = false)
if (!MyCommon.IsNullOrEmpty(result))
{
- var undotmp = new UrlUndo();
-
// 短縮 URL が生成されるまでの間に投稿欄から元の URL が削除されていたら中断する
var origUrlIndex = this.StatusText.Text.IndexOf(tmp, StringComparison.Ordinal);
if (origUrlIndex == -1)
this.StatusText.SelectedText = result;
// undoバッファにセット
- undotmp.Before = tmp;
- undotmp.After = result;
+ var undo = new UrlUndo
+ {
+ Before = tmp,
+ After = result,
+ };
if (this.urlUndoBuffer == null)
{
this.UrlUndoToolStripMenuItem.Enabled = true;
}
- this.urlUndoBuffer.Add(undotmp);
+ this.urlUndoBuffer.Add(undo);
}
}
}
var tmp = mt.Result("${url}");
if (tmp.StartsWith("w", StringComparison.OrdinalIgnoreCase))
tmp = "http://" + tmp;
- var undotmp = new UrlUndo();
// 選んだURLを選択(?)
this.StatusText.Select(this.StatusText.Text.IndexOf(mt.Result("${url}"), StringComparison.Ordinal), mt.Result("${url}").Length);
this.StatusText.Select(origUrlIndex, mt.Result("${url}").Length);
this.StatusText.SelectedText = result;
// undoバッファにセット
- undotmp.Before = mt.Result("${url}");
- undotmp.After = result;
+ var undo = new UrlUndo
+ {
+ Before = mt.Result("${url}"),
+ After = result,
+ };
if (this.urlUndoBuffer == null)
{
this.UrlUndoToolStripMenuItem.Enabled = true;
}
- this.urlUndoBuffer.Add(undotmp);
+ this.urlUndoBuffer.Add(undo);
}
}
}
var searchOptions = new SearchWordDialog.SearchOptions(
SearchWordDialog.SearchType.Timeline,
selText,
- newTab: false,
- caseSensitive: false,
- useRegex: false);
+ NewTab: false,
+ CaseSensitive: false,
+ UseRegex: false
+ );
this.Owner.SearchDialog.ResultOptions = searchOptions;