Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for application blacklist #344

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 29 additions & 15 deletions LightBulb/Services/SettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,19 @@ namespace LightBulb.Services;
[INotifyPropertyChanged]
public partial class SettingsService() : SettingsBase(GetFilePath(), SerializerContext.Default)
{
private readonly RegistrySwitch<int> _extendedGammaRangeSwitch =
new(
RegistryHive.LocalMachine,
@"Software\Microsoft\Windows NT\CurrentVersion\ICM",
"GdiICMGammaRange",
256
);

private readonly RegistrySwitch<string> _autoStartSwitch =
new(
RegistryHive.CurrentUser,
@"Software\Microsoft\Windows\CurrentVersion\Run",
Program.Name,
$"\"{Program.ExecutableFilePath}\" {StartOptions.IsInitiallyHiddenArgument}"
);
private readonly RegistrySwitch<int> _extendedGammaRangeSwitch = new(
RegistryHive.LocalMachine,
@"Software\Microsoft\Windows NT\CurrentVersion\ICM",
"GdiICMGammaRange",
256
);

private readonly RegistrySwitch<string> _autoStartSwitch = new(
RegistryHive.CurrentUser,
@"Software\Microsoft\Windows\CurrentVersion\Run",
Program.Name,
$"\"{Program.ExecutableFilePath}\" {StartOptions.IsInitiallyHiddenArgument}"
);

private bool _isFirstTimeExperienceEnabled = true;
public bool IsFirstTimeExperienceEnabled
Expand Down Expand Up @@ -206,6 +204,22 @@ public IReadOnlyList<ExternalApplication>? WhitelistedApplications
set => SetProperty(ref _whitelistedApplications, value);
}

// Application blacklist

private bool _isApplicationBlacklistEnabled;
public bool IsApplicationBlacklistEnabled
{
get => _isApplicationBlacklistEnabled;
set => SetProperty(ref _isApplicationBlacklistEnabled, value);
}

private IReadOnlyList<ExternalApplication>? _blacklistedApplications;
public IReadOnlyList<ExternalApplication>? BlacklistedApplications
{
get => _blacklistedApplications;
set => SetProperty(ref _blacklistedApplications, value);
}

// HotKeys

private HotKey _focusWindowHotKey;
Expand Down
11 changes: 10 additions & 1 deletion LightBulb/ViewModels/Components/DashboardViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,16 @@ bool IsPausedByWhitelistedApplication() =>
_externalApplicationService.TryGetForegroundApplication()
);

IsPaused = IsPausedByFullScreen() || IsPausedByWhitelistedApplication();
bool IsUpdateForcedByBlacklist() =>
_settingsService.IsApplicationBlacklistEnabled
&& _settingsService.BlacklistedApplications is not null
&& _settingsService.BlacklistedApplications.Contains(
_externalApplicationService.TryGetForegroundApplication()
);

IsPaused =
!IsUpdateForcedByBlacklist()
&& (IsPausedByFullScreen() || IsPausedByWhitelistedApplication());
}

[RelayCommand]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LightBulb.Framework;
using LightBulb.Models;
using LightBulb.Services;
using LightBulb.Utils;
using LightBulb.Utils.Extensions;

namespace LightBulb.ViewModels.Components.Settings;

public partial class ApplicationWhitelistSettingsTabViewModel : SettingsTabViewModelBase
{
private readonly ExternalApplicationService _externalApplicationService;
private readonly DisposableCollector _eventRoot = new();

[ObservableProperty]
private IReadOnlyList<ExternalApplication>? _applications;
private ObservableCollection<ExternalApplicationViewModel> _applications = [];

public ApplicationWhitelistSettingsTabViewModel(
SettingsService settingsService,
Expand All @@ -24,13 +24,7 @@ ExternalApplicationService externalApplicationService
: base(settingsService, 3, "Application whitelist")
{
_externalApplicationService = externalApplicationService;

_eventRoot.Add(
this.WatchProperty(
o => o.IsApplicationWhitelistEnabled,
() => RefreshApplicationsCommand.NotifyCanExecuteChanged()
)
);
RefreshApplications();
}

public bool IsApplicationWhitelistEnabled
Expand All @@ -39,36 +33,145 @@ public bool IsApplicationWhitelistEnabled
set => SettingsService.IsApplicationWhitelistEnabled = value;
}

public IReadOnlyList<ExternalApplication>? WhitelistedApplications
public bool IsApplicationBlacklistEnabled
{
get => SettingsService.WhitelistedApplications;
set => SettingsService.WhitelistedApplications = value;
get => SettingsService.IsApplicationBlacklistEnabled;
set => SettingsService.IsApplicationBlacklistEnabled = value;
}

private bool CanRefreshApplications() => IsApplicationWhitelistEnabled;

[RelayCommand(CanExecute = nameof(CanRefreshApplications))]
[RelayCommand]
private void RefreshApplications()
{
var applications = new HashSet<ExternalApplication>();
Applications.Clear();

// Add previously whitelisted applications
// (this has to be done first to preserve references in selected applications)
foreach (var application in WhitelistedApplications ?? [])
applications.Add(application);
foreach (var application in SettingsService.WhitelistedApplications ?? [])
{
var externalAppVm = new ExternalApplicationViewModel(SettingsService)
{
Application = application,
AppExclusionType = AppExclusionType.Whitelist,
};
Applications.Add(externalAppVm);
}

foreach (var application in SettingsService.BlacklistedApplications ?? [])
{
// There should not be duplicates at this point, but in case there were, ignore
if (Applications.Any(x => x.Application == application))
{
continue;
}

var externalAppVm = new ExternalApplicationViewModel(SettingsService)
{
Application = application,
AppExclusionType = AppExclusionType.Blacklist,
};
Applications.Add(externalAppVm);
}

// Add all running applications
foreach (var application in _externalApplicationService.GetAllRunningApplications())
applications.Add(application);
{
if (Applications.Any(x => x.Application == application))
{
continue;
}

var externalAppVm = new ExternalApplicationViewModel(SettingsService)
{
Application = application,
AppExclusionType = AppExclusionType.None,
};
Applications.Add(externalAppVm);
}
}
}

Applications = applications.ToArray();
public sealed class ExternalApplicationViewModel : ViewModelBase
{
private readonly SettingsService _settingsService;

public ExternalApplicationViewModel(SettingsService settingsService)
{
_settingsService = settingsService;
}

protected override void Dispose(bool disposing)
public required ExternalApplication Application { get; init; }

public AppExclusionType AppExclusionType
{
if (disposing)
_eventRoot.Dispose();
get;
set
{
var previousValue = field;
if (previousValue == value)
{
return;
}

base.Dispose(disposing);
field = value;
switch (value)
{
case AppExclusionType.None when previousValue is AppExclusionType.Whitelist:
RemoveFromWhitelist();
break;
case AppExclusionType.None when previousValue is AppExclusionType.Blacklist:
RemoveFromBlacklist();
break;
case AppExclusionType.Whitelist:
RemoveFromBlacklist();
AddToWhitelist();
break;
case AppExclusionType.Blacklist:
RemoveFromWhitelist();
AddToBlacklist();
break;
default:
throw new ArgumentOutOfRangeException(nameof(value), value, null);
}
}
}

public static IReadOnlyList<AppExclusionType> AvailableExclusionTypes { get; } =
Enum.GetValues<AppExclusionType>();

private void RemoveFromWhitelist()
{
_settingsService.WhitelistedApplications = _settingsService
.WhitelistedApplications?.Except([Application])
.ToList();
}

private void RemoveFromBlacklist()
{
_settingsService.BlacklistedApplications = _settingsService
.BlacklistedApplications?.Except([Application])
.ToList();
}

private void AddToWhitelist()
{
_settingsService.WhitelistedApplications = _settingsService
.WhitelistedApplications?.Concat([Application])
.Distinct()
.ToList();
}

private void AddToBlacklist()
{
_settingsService.BlacklistedApplications = _settingsService
.BlacklistedApplications?.Concat([Application])
.Distinct()
.ToList();
}
}

public enum AppExclusionType
{
None,
Whitelist,
Blacklist,
}
Loading