diff --git a/src/Disqord.Extensions.Interactivity/Menus/MenuBase.cs b/src/Disqord.Extensions.Interactivity/Menus/MenuBase.cs index e99aae75f..27d7ab4a4 100644 --- a/src/Disqord.Extensions.Interactivity/Menus/MenuBase.cs +++ b/src/Disqord.Extensions.Interactivity/Menus/MenuBase.cs @@ -129,6 +129,58 @@ public ViewBase? View } private ViewBase? _view; + /// + /// Gets or sets the timeout of this menu. + /// + public TimeSpan Timeout + { + get => _timeout; + set + { + if (_timeout == value) + { + if (value == System.Threading.Timeout.InfiniteTimeSpan) + { + return; + } + + RefreshTimeout(); + } + else + { + lock (_disposeLock) + { + _timeout = value; + if (value == System.Threading.Timeout.InfiniteTimeSpan) + { + _timeoutTimer?.Dispose(); + return; + } + + _timeoutTimer = new Timer(TimerCallback, this, value, System.Threading.Timeout.InfiniteTimeSpan); + return; + + static void TimerCallback(object? state) + { + var menu = Unsafe.As(state)!; + lock (menu._disposeLock) + { + if (!menu.IsRunning) + return; + + var cts = menu._cts; + if (cts == null) + return; + + cts.Cancel(); + menu._tcs!.Cancel(cts.Token); + } + } + } + } + } + } + private Tcs? _tcs; private Cts? _cts; private TimeSpan _timeout; @@ -168,14 +220,14 @@ protected virtual void ValidateView() /// Refreshes the timeout of this menu. /// By default, is called by . /// - protected void RefreshTimeout() + public void RefreshTimeout() { if (!IsRunning) return; lock (_disposeLock) { - _timeoutTimer?.Change(_timeout, Timeout.InfiniteTimeSpan); + _timeoutTimer?.Change(_timeout, System.Threading.Timeout.InfiniteTimeSpan); } } @@ -367,38 +419,16 @@ internal void Start(TimeSpan timeout, CancellationToken cancellationToken) _tcs = new Tcs(); _cts = Cts.Linked(Client.StoppingToken, cancellationToken); - static void CancellationCallback(object? state, CancellationToken cancellationToken) - { - var tcs = Unsafe.As(state)!; - tcs.Cancel(cancellationToken); - } - _cts.Token.UnsafeRegister(CancellationCallback, _tcs); - if (timeout == Timeout.InfiniteTimeSpan) - return; + Timeout = timeout; + return; - // We store the timeout so it can be refreshed when a button is triggered in HandleInteractionAsync. - _timeout = timeout; - - static void TimerCallback(object? state) + static void CancellationCallback(object? state, CancellationToken cancellationToken) { - var menu = Unsafe.As(state)!; - lock (menu._disposeLock) - { - if (!menu.IsRunning) - return; - - var cts = menu._cts; - if (cts == null) - return; - - cts.Cancel(); - menu._tcs!.Cancel(cts.Token); - } + var tcs = Unsafe.As(state)!; + tcs.Cancel(cancellationToken); } - - _timeoutTimer = new Timer(TimerCallback, this, timeout, Timeout.InfiniteTimeSpan); } ///