diff --git a/src/Client/Logic/Connection/ProtonVPN.Client.Logic.Connection.Contracts/IChangeServerModerator.cs b/src/Client/Logic/Connection/ProtonVPN.Client.Logic.Connection.Contracts/IChangeServerModerator.cs index 04977643d..8642a6712 100644 --- a/src/Client/Logic/Connection/ProtonVPN.Client.Logic.Connection.Contracts/IChangeServerModerator.cs +++ b/src/Client/Logic/Connection/ProtonVPN.Client.Logic.Connection.Contracts/IChangeServerModerator.cs @@ -28,4 +28,6 @@ public interface IChangeServerModerator TimeSpan GetDelayUntilNextAttempt(); TimeSpan GetRemainingDelayUntilNextAttempt(); + + bool HasTroubleConnecting(); } \ No newline at end of file diff --git a/src/Client/Logic/Connection/ProtonVPN.Client.Logic.Connection/ChangeServerModerator.cs b/src/Client/Logic/Connection/ProtonVPN.Client.Logic.Connection/ChangeServerModerator.cs index ddc88a17a..dd4db03ef 100644 --- a/src/Client/Logic/Connection/ProtonVPN.Client.Logic.Connection/ChangeServerModerator.cs +++ b/src/Client/Logic/Connection/ProtonVPN.Client.Logic.Connection/ChangeServerModerator.cs @@ -39,12 +39,16 @@ public class ChangeServerModerator : IEventMessageReceiver, IEventMessageReceiver { + private const int TroubleConnectingDelaySeconds = 6; + private readonly ISettings _settings; private readonly IConnectionManager _connectionManager; private readonly IEventMessageSender _eventMessageSender; private ChangeServerSettings _changeServerSettings; private ChangeServerAttempts _changeServerAttempts; + private DateTimeOffset? _connectionStartTime; + private bool _isConnecting; protected override TimeSpan PollingInterval { get; } = TimeSpan.FromSeconds(1); @@ -92,6 +96,17 @@ public TimeSpan GetRemainingDelayUntilNextAttempt() : TimeSpan.FromSeconds(Math.Ceiling(remainingTime.TotalSeconds)); } + public bool HasTroubleConnecting() + { + if (!_isConnecting || !_connectionStartTime.HasValue) + { + return false; + } + + TimeSpan elapsedTime = DateTimeOffset.UtcNow - _connectionStartTime.Value; + return elapsedTime.TotalSeconds >= TroubleConnectingDelaySeconds; + } + public void Receive(LoggedInMessage message) { InvalidateChangeServerAttempts(); @@ -116,6 +131,20 @@ public void Receive(SettingChangedMessage message) public void Receive(ConnectionStatusChangedMessage message) { + // Track connection state for HasTroubleConnecting logic + switch (message.ConnectionStatus) + { + case ConnectionStatus.Connecting: + _isConnecting = true; + _connectionStartTime = DateTimeOffset.UtcNow; + break; + case ConnectionStatus.Connected: + case ConnectionStatus.Disconnected: + _isConnecting = false; + _connectionStartTime = null; + break; + } + if (_connectionManager.IsConnected && _connectionManager.CurrentConnectionIntent?.Location is FreeServerLocationIntent intent && intent.Kind == ConnectionIntentKind.Random) diff --git a/src/Client/ProtonVPN.Client/UI/Main/Home/Upsell/ChangeServerComponentViewModel.cs b/src/Client/ProtonVPN.Client/UI/Main/Home/Upsell/ChangeServerComponentViewModel.cs index 924db1764..9e613ef90 100644 --- a/src/Client/ProtonVPN.Client/UI/Main/Home/Upsell/ChangeServerComponentViewModel.cs +++ b/src/Client/ProtonVPN.Client/UI/Main/Home/Upsell/ChangeServerComponentViewModel.cs @@ -47,6 +47,7 @@ public partial class ChangeServerComponentViewModel : ActivatableViewModelBase, public double DelayInSeconds => _changeServerModerator.GetDelayUntilNextAttempt().TotalSeconds; public double RemainingDelayInSeconds => _changeServerModerator.GetRemainingDelayUntilNextAttempt().TotalSeconds; public string? FormattedRemainingTime => Localizer.GetFormattedShortTime(_changeServerModerator.GetRemainingDelayUntilNextAttempt()); + public bool HasTroubleConnecting => _changeServerModerator.HasTroubleConnecting(); public ChangeServerComponentViewModel( IConnectionManager connectionManager, @@ -99,7 +100,10 @@ private Task ChangeServerAsync() private bool CanChangeServer() { - return _connectionManager.IsConnected && _changeServerModerator.CanChangeServer(); + bool isConnectedOrHasTroubleConnecting = _connectionManager.IsConnected || + (_connectionManager.IsConnecting && _changeServerModerator.HasTroubleConnecting()); + + return isConnectedOrHasTroubleConnecting && _changeServerModerator.CanChangeServer(); } [RelayCommand] @@ -115,6 +119,7 @@ private void InvalidateChangeServer() OnPropertyChanged(nameof(DelayInSeconds)); OnPropertyChanged(nameof(RemainingDelayInSeconds)); OnPropertyChanged(nameof(FormattedRemainingTime)); + OnPropertyChanged(nameof(HasTroubleConnecting)); ChangeServerCommand.NotifyCanExecuteChanged(); }