/* * Copyright (c) 2024 Proton AG * * This file is part of ProtonVPN. * * ProtonVPN 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. * * ProtonVPN 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 ProtonVPN. If not, see . */ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using ProtonVPN.Client.Contracts.Profiles; using ProtonVPN.Client.Core.Bases; using ProtonVPN.Client.Core.Bases.ViewModels; using ProtonVPN.Client.Core.Enums; using ProtonVPN.Client.Core.Services.Activation; using ProtonVPN.Client.Core.Services.Navigation; using ProtonVPN.Client.EventMessaging.Contracts; using ProtonVPN.Client.Localization.Extensions; using ProtonVPN.Client.Logic.Connection.Contracts; using ProtonVPN.Client.Logic.Connection.Contracts.Messages; using ProtonVPN.Client.Settings.Contracts; using ProtonVPN.Client.Settings.Contracts.Enums; using ProtonVPN.Client.Settings.Contracts.RequiredReconnections; using ProtonVPN.Client.UI.Main.Features.Bases; using ProtonVPN.Client.UI.Main.Settings.Bases; using ProtonVPN.Client.UI.Main.Settings.Connection; using ProtonVPN.StatisticalEvents.Contracts; namespace ProtonVPN.Client.UI.Main.Features.NetShield; public partial class NetShieldWidgetViewModel : FeatureWidgetViewModelBase, IEventMessageReceiver { private const int BADGE_MAXIMUM_NUMBER = 99; private readonly Lazy> _disableNetShieldSettings; private readonly Lazy> _enableNetShieldLevelOneSettings; private readonly Lazy> _enableNetShieldLevelTwoSettings; private readonly Lazy> _enableNetShieldLevelThreeSettings; [ObservableProperty] [NotifyPropertyChangedFor(nameof(TotalAdsAndTrackersBlocked))] [NotifyPropertyChangedFor(nameof(FormattedTotalAdsAndTrackersBlocked))] private long _numberOfTrackersStopped; [ObservableProperty] [NotifyPropertyChangedFor(nameof(TotalAdsAndTrackersBlocked))] [NotifyPropertyChangedFor(nameof(FormattedTotalAdsAndTrackersBlocked))] private long _numberOfAdsBlocked; public int TotalAdsAndTrackersBlocked => Convert.ToInt32(NumberOfTrackersStopped + NumberOfAdsBlocked); public string FormattedTotalAdsAndTrackersBlocked => TotalAdsAndTrackersBlocked > BADGE_MAXIMUM_NUMBER ? $"{BADGE_MAXIMUM_NUMBER}+" : $"{TotalAdsAndTrackersBlocked}"; public override string Header => Localizer.Get("Settings_Connection_NetShield"); public string InfoMessage => Localizer.Get("Flyouts_NetShield_Info"); public string BlockMalwareOnlyMessage => Localizer.Get("Flyouts_NetShield_MalwareOnly_Success"); public string BlockAdsMalwareTrackersMessage => Localizer.Get("Flyouts_NetShield_AdsMalwareTrackers_Success"); public string BlockAdsMalwareTrackersAdultContentMessage => Localizer.Get("Flyouts_NetShield_AdsMalwareTrackersAdultContent_Success"); public bool IsNetShieldEnabled => IsFeatureOverridden ? CurrentProfile!.Settings.IsNetShieldEnabled : Settings.IsNetShieldEnabled; public NetShieldMode NetShieldMode => IsFeatureOverridden ? CurrentProfile!.Settings.NetShieldMode : Settings.NetShieldMode; public bool IsInfoMessageVisible => !ConnectionManager.IsConnected || !IsNetShieldEnabled; public bool IsBlockMalwareOnlyMessageVisible => ConnectionManager.IsConnected && IsNetShieldLevelOneEnabled; public bool IsBlockAdsMalwareTrackersMessageVisible => ConnectionManager.IsConnected && IsNetShieldLevelTwoEnabled; public bool IsBlockAdsMalwareTrackersAdultContentMessageVisible => ConnectionManager.IsConnected && IsNetShieldLevelThreeEnabled; public bool IsNetShieldStatsPanelVisible => ConnectionManager.IsConnected && IsNetShieldEnabled && NetShieldMode >= NetShieldMode.BlockAdsMalwareTrackers; public bool IsNetShieldLevelOneEnabled => IsNetShieldEnabled && NetShieldMode == NetShieldMode.BlockMalwareOnly; public bool IsNetShieldLevelTwoEnabled => IsNetShieldEnabled && (NetShieldMode == NetShieldMode.BlockAdsMalwareTrackers || (NetShieldMode == NetShieldMode.BlockAdsMalwareTrackersAdultContent && !IsNetShieldLevelThreeAvailable)); public bool IsNetShieldLevelThreeEnabled => IsNetShieldLevelThreeAvailable && IsNetShieldEnabled && NetShieldMode == NetShieldMode.BlockAdsMalwareTrackersAdultContent; public bool IsNetShieldLevelThreeAvailable => !Settings.VpnPlan.IsB2B; protected override UpsellModalContext ModalContext { get; } = new(ModalSource.NetShield, ModalTrigger.Settings); public override bool IsFeatureOverridden => ConnectionManager.IsConnected && CurrentProfile != null; public NetShieldWidgetViewModel( IViewModelHelper viewModelHelper, ISettings settings, IMainViewNavigator mainViewNavigator, ISettingsViewNavigator settingsViewNavigator, IMainWindowOverlayActivator mainWindowOverlayActivator, IConnectionManager connectionManager, IUpsellCarouselWindowActivator upsellCarouselWindowActivator, IRequiredReconnectionSettings requiredReconnectionSettings, ISettingsConflictResolver settingsConflictResolver, IProfileEditor profileEditor) : base(viewModelHelper, mainViewNavigator, settingsViewNavigator, mainWindowOverlayActivator, settings, connectionManager, upsellCarouselWindowActivator, requiredReconnectionSettings, settingsConflictResolver, profileEditor, ConnectionFeature.NetShield) { _disableNetShieldSettings = new(() => [ ChangedSettingArgs.Create(() => Settings.IsNetShieldEnabled, () => false) ]); _enableNetShieldLevelOneSettings = new(() => [ ChangedSettingArgs.Create(() => Settings.NetShieldMode, () => NetShieldMode.BlockMalwareOnly), ChangedSettingArgs.Create(() => Settings.IsNetShieldEnabled, () => true) ]); _enableNetShieldLevelTwoSettings = new(() => [ ChangedSettingArgs.Create(() => Settings.NetShieldMode, () => NetShieldMode.BlockAdsMalwareTrackers), ChangedSettingArgs.Create(() => Settings.IsNetShieldEnabled, () => true) ]); _enableNetShieldLevelThreeSettings = new(() => [ ChangedSettingArgs.Create(() => Settings.NetShieldMode, () => NetShieldMode.BlockAdsMalwareTrackersAdultContent), ChangedSettingArgs.Create(() => Settings.IsNetShieldEnabled, () => true) ]); } public void Receive(NetShieldStatsChangedMessage message) { ExecuteOnUIThread(() => { if (ConnectionManager.IsConnected) { SetNetShieldStats(message); } else { ClearNetShieldStats(); } }); } protected override IEnumerable GetSettingsChangedForUpdate() { yield return nameof(ISettings.NetShieldMode); yield return nameof(ISettings.IsNetShieldEnabled); } protected override string GetFeatureStatus() { return Localizer.GetToggleValue(IsNetShieldEnabled); } protected override void OnLanguageChanged() { base.OnLanguageChanged(); OnPropertyChanged(nameof(InfoMessage)); OnPropertyChanged(nameof(BlockMalwareOnlyMessage)); OnPropertyChanged(nameof(BlockAdsMalwareTrackersMessage)); OnPropertyChanged(nameof(BlockAdsMalwareTrackersAdultContentMessage)); } protected override void OnSettingsChanged() { OnPropertyChanged(nameof(Status)); OnPropertyChanged(nameof(IsInfoMessageVisible)); OnPropertyChanged(nameof(IsBlockMalwareOnlyMessageVisible)); OnPropertyChanged(nameof(IsBlockAdsMalwareTrackersMessageVisible)); OnPropertyChanged(nameof(IsBlockAdsMalwareTrackersAdultContentMessageVisible)); OnPropertyChanged(nameof(IsNetShieldStatsPanelVisible)); OnPropertyChanged(nameof(IsNetShieldEnabled)); OnPropertyChanged(nameof(NetShieldMode)); OnPropertyChanged(nameof(IsNetShieldLevelOneEnabled)); OnPropertyChanged(nameof(IsNetShieldLevelTwoEnabled)); OnPropertyChanged(nameof(IsNetShieldLevelThreeEnabled)); } protected override void OnConnectionStatusChanged() { OnPropertyChanged(nameof(Status)); OnPropertyChanged(nameof(IsInfoMessageVisible)); OnPropertyChanged(nameof(IsBlockMalwareOnlyMessageVisible)); OnPropertyChanged(nameof(IsBlockAdsMalwareTrackersMessageVisible)); OnPropertyChanged(nameof(IsBlockAdsMalwareTrackersAdultContentMessageVisible)); OnPropertyChanged(nameof(IsNetShieldStatsPanelVisible)); OnPropertyChanged(nameof(IsFeatureOverridden)); OnPropertyChanged(nameof(IsNetShieldEnabled)); OnPropertyChanged(nameof(NetShieldMode)); OnPropertyChanged(nameof(CurrentProfile)); if (!ConnectionManager.IsConnected) { ClearNetShieldStats(); } } protected override bool IsOnFeaturePage(PageViewModelBase? currentPageContext) { return currentPageContext is NetShieldPageViewModel; } private void SetNetShieldStats(NetShieldStatsChangedMessage stats) { NumberOfAdsBlocked = stats.NumOfAdvertisementUrlsBlocked; NumberOfTrackersStopped = stats.NumOfTrackingUrlsBlocked; } private void ClearNetShieldStats() { NumberOfAdsBlocked = 0; NumberOfTrackersStopped = 0; } [RelayCommand] private Task DisableNetShieldAsync() { return TryChangeFeatureSettingsAsync(_disableNetShieldSettings.Value); } [RelayCommand] private Task EnableNetShieldLevelOneAsync() { return TryChangeFeatureSettingsAsync(_enableNetShieldLevelOneSettings.Value); } [RelayCommand] private Task EnableNetShieldLevelTwoAsync() { return TryChangeFeatureSettingsAsync(_enableNetShieldLevelTwoSettings.Value); } [RelayCommand] private Task EnableNetShieldLevelThreeAsync() { return TryChangeFeatureSettingsAsync(_enableNetShieldLevelThreeSettings.Value); } }